Compare commits
2 Commits
master
...
spike/comp
Author | SHA1 | Date | |
---|---|---|---|
|
90bd588ed6 | ||
|
f1a83885f8 |
@ -1,9 +0,0 @@
|
|||||||
artifacts
|
|
||||||
reports
|
|
||||||
.nyc_output
|
|
||||||
coverage
|
|
||||||
dist
|
|
||||||
styleguide
|
|
||||||
build
|
|
||||||
consoles/*/lib/app
|
|
||||||
node_modules
|
|
10
.eslintrc
10
.eslintrc
@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "joyent-portal",
|
|
||||||
"rules": {
|
|
||||||
"no-console": 1,
|
|
||||||
"new-cap": 0,
|
|
||||||
"jsx-a11y/href-no-hash": 0,
|
|
||||||
"no-negated-condition": 1,
|
|
||||||
"camelcase": 1
|
|
||||||
}
|
|
||||||
}
|
|
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*.sketch filter=lfs diff=lfs merge=lfs -text
|
25
.github/COMMIT_GUIDELINES.md
vendored
25
.github/COMMIT_GUIDELINES.md
vendored
@ -1,25 +0,0 @@
|
|||||||
# Commit Guidelines
|
|
||||||
|
|
||||||
```
|
|
||||||
<type><(scope)?>: <msg>
|
|
||||||
```
|
|
||||||
|
|
||||||
Where type is one of:
|
|
||||||
|
|
||||||
```
|
|
||||||
build
|
|
||||||
chore
|
|
||||||
ci
|
|
||||||
docs
|
|
||||||
feat
|
|
||||||
fix
|
|
||||||
perf
|
|
||||||
refactor
|
|
||||||
revert
|
|
||||||
style
|
|
||||||
test
|
|
||||||
```
|
|
||||||
|
|
||||||
And where scope is one of ui-toolkit, my-joy-beta, cloudapi-gql, boilerplate, and create-instance.
|
|
||||||
|
|
||||||
_The recommended method to commit should be by running npm run commit._
|
|
17
.github/ISSUE_TEMPLATE.md
vendored
17
.github/ISSUE_TEMPLATE.md
vendored
@ -1,17 +0,0 @@
|
|||||||
## I'm submitting a...
|
|
||||||
|
|
||||||
* [ ] bug report
|
|
||||||
* [ ] feature request
|
|
||||||
* [ ] design request
|
|
||||||
|
|
||||||
## What is the current behavior?
|
|
||||||
|
|
||||||
## If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem
|
|
||||||
|
|
||||||
## What is the expected behavior?
|
|
||||||
|
|
||||||
## What is the motivation / use case for changing the behavior?
|
|
||||||
|
|
||||||
## If the current behavior is a bug, please provide your browser
|
|
||||||
|
|
||||||
## Other information
|
|
14
.github/PULL_REQUEST_TEMPLATE.md
vendored
14
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,14 +0,0 @@
|
|||||||
**Please check if the PR fulfills these requirements**
|
|
||||||
|
|
||||||
* [ ] The commit message follows our [guidelines](https://github.com/yldio/joyent-portal/blob/master/.github/COMMIT_GUIDELINES.md)
|
|
||||||
* [ ] Tests for the changes have been added (for bug fixes / features)
|
|
||||||
|
|
||||||
**What kind of change does this PR introduce?** (Bug fix, feature, docs update, ...)
|
|
||||||
|
|
||||||
**Does this PR close an issue?** (If not please create one)
|
|
||||||
|
|
||||||
**What is the new behavior (if this is a feature change)?**
|
|
||||||
|
|
||||||
**Does this PR introduce a breaking change?** (What changes might users need to make in their application due to this PR?)
|
|
||||||
|
|
||||||
**Other information**
|
|
19
.gitignore
vendored
19
.gitignore
vendored
@ -118,6 +118,9 @@ Session.vim
|
|||||||
# temporary
|
# temporary
|
||||||
.netrwhist
|
.netrwhist
|
||||||
*~
|
*~
|
||||||
|
# auto-generated tag files
|
||||||
|
tags
|
||||||
|
|
||||||
|
|
||||||
### Windows ###
|
### Windows ###
|
||||||
# Windows image file caches
|
# Windows image file caches
|
||||||
@ -151,19 +154,3 @@ $RECYCLE.BIN/
|
|||||||
tap-xunit
|
tap-xunit
|
||||||
/ui/dist
|
/ui/dist
|
||||||
|
|
||||||
_todo
|
|
||||||
packages/*/dist
|
|
||||||
prototypes/*/dist
|
|
||||||
packages/*/buid
|
|
||||||
prototypes/*/buid
|
|
||||||
packages/*/.next
|
|
||||||
prototypes/*/.next
|
|
||||||
packages/ui-toolkit/styleguide/
|
|
||||||
packages/ui-toolkit/.snapguidist/
|
|
||||||
packages/*/package-lock.json
|
|
||||||
prototypes/*/package-lock.json
|
|
||||||
|
|
||||||
_env*
|
|
||||||
keys*
|
|
||||||
/packages/*/public/index.html
|
|
||||||
/consoles/*/public/index.html
|
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"ignoreDevDependencies": true,
|
|
||||||
"allowedPackages": [
|
|
||||||
{
|
|
||||||
"name": "colors",
|
|
||||||
"extraFieldsForDocumentation":
|
|
||||||
"Licence is MIT, but was not found by tool: https://github.com/Marak/colors.js/blob/v0.5.1/MIT-LICENSE.txt",
|
|
||||||
"date": "17 January 2017",
|
|
||||||
"reason": "MIT Licenced"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"allowedLicenses": [
|
|
||||||
"CC-BY-4.0",
|
|
||||||
"CC0-1.0",
|
|
||||||
"MIT",
|
|
||||||
"ISC",
|
|
||||||
"Apache",
|
|
||||||
"BSD",
|
|
||||||
"WTF",
|
|
||||||
"Public Domain",
|
|
||||||
"MPL",
|
|
||||||
"Unlicense"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
.git/*
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
license
|
|
||||||
yarn.lock
|
|
||||||
.travis.yml
|
|
||||||
|
|
||||||
.yarnclean
|
|
||||||
.eslintignore
|
|
||||||
.prettierignore
|
|
||||||
.npmignore
|
|
||||||
.gitignore
|
|
||||||
.dockerignore
|
|
||||||
|
|
||||||
dist
|
|
||||||
build
|
|
||||||
packages/*/lib/app
|
|
||||||
consoles/*/lib/app
|
|
||||||
|
|
||||||
*.ico
|
|
||||||
*.html
|
|
||||||
*.log
|
|
||||||
*.svg
|
|
||||||
*.map
|
|
||||||
*.png
|
|
||||||
*.snap
|
|
||||||
*.ttf
|
|
||||||
*.sh
|
|
||||||
*.txt
|
|
31
.prettierrc
31
.prettierrc
@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"bracketSpacing": true,
|
|
||||||
"jsxBracketSameLine": false,
|
|
||||||
"printWidth": 80,
|
|
||||||
"semi": true,
|
|
||||||
"singleQuote": true,
|
|
||||||
"tabWidth": 2,
|
|
||||||
"trailingComma": "none",
|
|
||||||
"useTabs": false,
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"files": [
|
|
||||||
".prettierrc",
|
|
||||||
".eslintrc",
|
|
||||||
".babelrc",
|
|
||||||
".tern-project",
|
|
||||||
".stylelintrc",
|
|
||||||
".lighthouserc"
|
|
||||||
],
|
|
||||||
"options": {
|
|
||||||
"parser": "json"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"files": ["package.json"],
|
|
||||||
"options": {
|
|
||||||
"printWidth": 180
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"libs": ["ecmascript", "browser"],
|
|
||||||
"plugins": {
|
|
||||||
"doc_comment": true,
|
|
||||||
"local-scope": true,
|
|
||||||
"jsx": true,
|
|
||||||
"node": true,
|
|
||||||
"webpack": {
|
|
||||||
"configPath": "./webpack/index.js"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
language: node_js
|
|
||||||
node_js:
|
|
||||||
- '9'
|
|
||||||
script:
|
|
||||||
- yarn run test:ci
|
|
15
.vscode/launch.json
vendored
15
.vscode/launch.json
vendored
@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
// Use IntelliSense to learn about possible attributes.
|
|
||||||
// Hover to view descriptions of existing attributes.
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"type": "chrome",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "Launch Chrome against localhost",
|
|
||||||
"url": "http://localhost:3069/",
|
|
||||||
"webRoot": "${workspaceRoot}"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -1 +0,0 @@
|
|||||||
{}
|
|
36
.yarnclean
36
.yarnclean
@ -1,36 +0,0 @@
|
|||||||
# test directories
|
|
||||||
__tests__
|
|
||||||
test
|
|
||||||
tests
|
|
||||||
powered-test
|
|
||||||
|
|
||||||
# asset directories
|
|
||||||
docs
|
|
||||||
doc
|
|
||||||
website
|
|
||||||
images
|
|
||||||
assets
|
|
||||||
|
|
||||||
# code coverage directories
|
|
||||||
coverage
|
|
||||||
.nyc_output
|
|
||||||
|
|
||||||
# build scripts
|
|
||||||
Makefile
|
|
||||||
Gulpfile.js
|
|
||||||
Gruntfile.js
|
|
||||||
|
|
||||||
# configs
|
|
||||||
.tern-project
|
|
||||||
.gitattributes
|
|
||||||
.editorconfig
|
|
||||||
.*ignore
|
|
||||||
.eslintrc
|
|
||||||
.jshintrc
|
|
||||||
.flowconfig
|
|
||||||
.documentup.json
|
|
||||||
.yarn-metadata.json
|
|
||||||
|
|
||||||
# misc
|
|
||||||
*.gz
|
|
||||||
*.md
|
|
33
CONTRIBUTING.md
Normal file
33
CONTRIBUTING.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
## Development Workflow
|
||||||
|
|
||||||
|
### Small Feature Development
|
||||||
|
|
||||||
|
Contributors who have write access to the repository will practise continuous
|
||||||
|
delivery (CD as known from now on in this document).
|
||||||
|
|
||||||
|
We will define CD in this document as a method of developing a feature per commit
|
||||||
|
with an encapsulating test that proves that the functionality is working, the
|
||||||
|
contributor will test their code locally and if all is passing will push to *master*.
|
||||||
|
|
||||||
|
For contributors that do not have write access, follow the same conventions but
|
||||||
|
open a Pull Request instead.
|
||||||
|
|
||||||
|
### Large changesets
|
||||||
|
|
||||||
|
When larger changes need to be made, or the work that is carried out spans multiple
|
||||||
|
components / services of the application at the same time a single commit will
|
||||||
|
not suffice.
|
||||||
|
|
||||||
|
In this scenario, the contributor should open a pull request instead.
|
||||||
|
|
||||||
|
## Commit messages
|
||||||
|
|
||||||
|
Follow [Git blessed](http://chris.beams.io/posts/git-commit/)
|
||||||
|
|
||||||
|
1. Separate subject from body with a blank line
|
||||||
|
2. Limit the subject line to 50 characters
|
||||||
|
3. Capitalize the subject line
|
||||||
|
4. Do not end the subject line with a period
|
||||||
|
5. Use the imperative mood in the subject line
|
||||||
|
6. Wrap the body at 72 characters
|
||||||
|
7. Use the body to explain what and why vs. how
|
57
Makefile
Normal file
57
Makefile
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
.PHONY: check
|
||||||
|
check:
|
||||||
|
@yarn install --prefer-offline
|
||||||
|
-@./bin/setup
|
||||||
|
|
||||||
|
.PHONE: licence
|
||||||
|
licence:
|
||||||
|
./node_modules/.bin/license-to-fail ./licence.js
|
||||||
|
make licence-check
|
||||||
|
|
||||||
|
SUBDIRS := $(dir $(wildcard */Makefile))
|
||||||
|
TARGETS := install clean test test-ci lint lint-ci licence-check# whatever else, but must not contain '/'
|
||||||
|
|
||||||
|
# foo/.all bar/.all foo/.clean bar/.clean
|
||||||
|
SUBDIRS_TARGETS := \
|
||||||
|
$(foreach t,$(TARGETS),$(addsuffix $t,$(SUBDIRS)))
|
||||||
|
|
||||||
|
.PHONY: $(TARGETS) $(SUBDIRS_TARGETS)
|
||||||
|
|
||||||
|
# static pattern rule, expands into:
|
||||||
|
# all clean: %: foo/.% bar/.%
|
||||||
|
$(TARGETS): %: $(addsuffix %,$(SUBDIRS))
|
||||||
|
@echo 'Done "$*" target'
|
||||||
|
|
||||||
|
# here, for foo/.all:
|
||||||
|
# $(@D) is foo
|
||||||
|
# $(@F) is .all, with leading period
|
||||||
|
# $(@F:.%=%) is just all
|
||||||
|
$(SUBDIRS_TARGETS):
|
||||||
|
$(MAKE) --no-print-directory -C $(@D) $(@F:.%=%)
|
||||||
|
|
||||||
|
DIFF := $(lastword $(subst /, ,${CIRCLE_COMPARE_URL}))
|
||||||
|
CHANGED_FILES := $(subst /, , $(dir $(shell git diff --name-only $(DIFF))))
|
||||||
|
CHANGES := $(patsubst %, %/, $(sort $(filter $(subst /, ,$(SUBDIRS)), $(CHANGED_FILES))))
|
||||||
|
.PHONY: diff
|
||||||
|
diff:
|
||||||
|
echo $(CHANGES)
|
||||||
|
|
||||||
|
BUILDS := build push
|
||||||
|
|
||||||
|
# foo/.all bar/.all foo/.clean bar/.clean
|
||||||
|
BUILDS_TARGETS := \
|
||||||
|
$(foreach t,$(BUILDS),$(addsuffix $t,$(CHANGES)))
|
||||||
|
|
||||||
|
.PHONY: $(BUILDS) $(BUILDS_TARGETS)
|
||||||
|
|
||||||
|
# static pattern rule, expands into:
|
||||||
|
# all clean: %: foo/.% bar/.%
|
||||||
|
$(BUILDS): %: $(addsuffix %,$(CHANGES))
|
||||||
|
@echo 'Done "$*" target'
|
||||||
|
|
||||||
|
# here, for foo/.all:
|
||||||
|
# $(@D) is foo
|
||||||
|
# $(@F) is .all, with leading period
|
||||||
|
# $(@F:.%=%) is just all
|
||||||
|
$(BUILDS_TARGETS):
|
||||||
|
$(MAKE) --no-print-directory -C $(@D) $(@F:.%=%)
|
120
README.md
Normal file
120
README.md
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
[![CircleCI](https://circleci.com/gh/yldio/joyent-portal.svg?style=shield&circle-token=0bbeaaafc4868c707ca0ed0568f5193a04daddb4)](https://circleci.com/gh/yldio/joyent-portal)
|
||||||
|
[![License: MPL 2.0](https://img.shields.io/badge/License-MPL%202.0-brightgreen.svg)](https://opensource.org/licenses/MPL-2.0)
|
||||||
|
|
||||||
|
# Prototype Triton Portal
|
||||||
|
|
||||||
|
This is a prototype project intended to explore some ideas that might contribute to new capabilities and a new user experience for managing applications on [Joyent's Triton](https://www.joyent.com/triton).
|
||||||
|
|
||||||
|
**This is not intended for general use and is completely unsupported.**
|
||||||
|
|
||||||
|
## Our Principles
|
||||||
|
We have designed this product with these principles in mind (to be completed).
|
||||||
|
|
||||||
|
## Our Design Library
|
||||||
|
We use inVision craft for our design components, you can downoad this library [here](https://drive.google.com/open?id=0Bw56g3tFwIuWOXNHUDZmRmQ3ZlE) and submit proposed changes to our Sketch wireframes [here](https://drive.google.com/open?id=0B1oWObk56wa5cE5iY2JWNmI2djg).
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
Our workshop meeting notes are kept in this [Google Drive folder](https://drive.google.com/open?id=0B1oWObk56wa5eklBNGFlWFRFOHM). Our meeting notes are kept in this [Google Drive folder](https://drive.google.com/open?id=0B1oWObk56wa5N1VzZjhZWWpDTTQ).
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
If you would like to contribute to the project, the recommended way to setup is to
|
||||||
|
insure that you have docker installed, and optionally have a triton account and profile
|
||||||
|
setup using the triton tool.
|
||||||
|
|
||||||
|
Currently requires [yarn](https://yarnpkg.com/en/docs/install) for installing dependencies,
|
||||||
|
as well as `docker` and `docker-compose` are installed correctly, this can be done by
|
||||||
|
running `make`, make continues without any errors, then you are good to go. [node-triton](https://github.com/joyent/node-triton)
|
||||||
|
is also needed if deployment to Triton is required.
|
||||||
|
|
||||||
|
```
|
||||||
|
make && make install
|
||||||
|
```
|
||||||
|
|
||||||
|
Then to run each individual component locally (subject to change).
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run services
|
||||||
|
|
||||||
|
To run the stack locally:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker-compose -f local-compose.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
This will run the front-end at [http://127.0.0.1:8000](http://127.0.0.1:8000),
|
||||||
|
the UI framework at [http://127.0.0.1:8001](http://127.0.0.1:8001),
|
||||||
|
|
||||||
|
## Project Management
|
||||||
|
|
||||||
|
This project is using [Github Projects](https://www.youtube.com/watch?v=C6MGKHkNtxU) for organisation and development of the Joyent Dashboard.
|
||||||
|
|
||||||
|
## Repository Layout
|
||||||
|
|
||||||
|
Currently we are using this repository as a monolithic catch-all for all project communication, development and designs.
|
||||||
|
We will also include multiple PoC's of various bits of functionality from UI's prototypes to API development.
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── cloudapi-graphql
|
||||||
|
├── docs
|
||||||
|
├── frontend
|
||||||
|
├── nginx
|
||||||
|
├── ui
|
||||||
|
└── spikes
|
||||||
|
```
|
||||||
|
|
||||||
|
### cloudapi-graphql
|
||||||
|
|
||||||
|
An implementation of the [Joyent CloudAPI](https://apidocs.joyent.com/cloudapi/) in GraphQL.
|
||||||
|
|
||||||
|
### Docs
|
||||||
|
|
||||||
|
Documentation about the project, mainly focused on information for the technical runnings of this project.
|
||||||
|
Can be view online at the [documentation website](http://docs.svc.f4b20699-b323-4452-9091-977895896da6.eu-ams-1.triton.zone/)
|
||||||
|
|
||||||
|
### frontend
|
||||||
|
|
||||||
|
The client side code with a dev-server, this also includes the production server for the meantime, however we are looking at moving towards a deployment of the build artifacts to manta, and another server to host these assets.
|
||||||
|
|
||||||
|
### nginx
|
||||||
|
|
||||||
|
Nginx will be sitting in-front of the `ui` service, allowing the `ui` to scale out.
|
||||||
|
|
||||||
|
### ui
|
||||||
|
|
||||||
|
Code for the reusable UI framework.
|
||||||
|
|
||||||
|
### spikes
|
||||||
|
|
||||||
|
Implementation examples from spikes, this directory is experimental and is likely broken.
|
||||||
|
|
||||||
|
### Git LFS
|
||||||
|
- We are using Git LFS to track large files, such as design files in Sketch.
|
||||||
|
- Make sure you have this downloaded locally
|
||||||
|
`brew install git-lfs`
|
||||||
|
|
||||||
|
#### Helpful tips
|
||||||
|
- If there is an error cloning to a new machine, or there is an error cloning in the Circle CI process run `git lfs push origin master --all` from a machine that has it already checked out.
|
||||||
|
|
||||||
|
### Sketch Pre Commit
|
||||||
|
|
||||||
|
A pre-commit hook has been added to generate a PNG shot of each .sketch file "page".
|
||||||
|
|
||||||
|
To use, make sure the following are installed:
|
||||||
|
- [Sketch Toolbox](http://sketchtoolbox.com/)
|
||||||
|
- [Sketch Measure Plugin](https://github.com/utom/sketch-measure)
|
||||||
|
|
||||||
|
|
||||||
|
Then add following to your `.git/config`
|
||||||
|
|
||||||
|
```
|
||||||
|
[diff "sketchtool"]
|
||||||
|
textconv = "sketchtool dump"
|
||||||
|
cachetextconv = true
|
||||||
|
```
|
30
bin/deploy
Executable file
30
bin/deploy
Executable file
@ -0,0 +1,30 @@
|
|||||||
|
#! /usr/bin/env bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# Prelude - make bash behave sanely
|
||||||
|
# http://redsymbol.net/articles/unofficial-bash-strict-mode/
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Beware of CDPATH gotchas causing cd not to work correctly when a user
|
||||||
|
# has set this in their environment
|
||||||
|
# https://bosker.wordpress.com/2012/02/12/bash-scripters-beware-of-the-cdpath/
|
||||||
|
unset CDPATH
|
||||||
|
|
||||||
|
readonly INCLUDE="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
# shellcheck source=bin/setup-tools
|
||||||
|
. "${INCLUDE}"/setup-tools
|
||||||
|
|
||||||
|
echo ">> running triton deploy with docker-compose"
|
||||||
|
ensure_command triton
|
||||||
|
ensure_triton_cns_is_enabled
|
||||||
|
get_triton_details
|
||||||
|
write_env_file
|
||||||
|
|
||||||
|
export DOCKER_HOST=$_DOCKER_HOST
|
||||||
|
export DOCKER_CERT_PATH=$_DOCKER_CERT_PATH
|
||||||
|
# Do not TLS verify for now, incompatibilities between circleci and joyent
|
||||||
|
export DOCKER_TLS_VERIFY=
|
||||||
|
|
||||||
|
docker-compose pull
|
||||||
|
COMPOSE_PROJECT_NAME=${CIRCLE_BRANCH} docker-compose up -d
|
10
bin/docker-login
Executable file
10
bin/docker-login
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
#! /usr/bin/env bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# Prelude - make bash behave sanely
|
||||||
|
# http://redsymbol.net/articles/unofficial-bash-strict-mode/
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo ">> Logging into $_DOCKER_REGISTRY"
|
||||||
|
docker login -e="." -u="$_DOCKER_LOGIN_USERNAME" -p="$_DOCKER_LOGIN_PASSWORD" "$_DOCKER_REGISTRY"
|
203
bin/history-check
Executable file
203
bin/history-check
Executable file
@ -0,0 +1,203 @@
|
|||||||
|
#! /usr/bin/env bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# Prelude - make bash behave sanely
|
||||||
|
# http://redsymbol.net/articles/unofficial-bash-strict-mode/
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
IFS=$'\n\t'
|
||||||
|
|
||||||
|
#
|
||||||
|
# Globals
|
||||||
|
#
|
||||||
|
remember_git_start_and_end() {
|
||||||
|
HEAD="$(git rev-parse HEAD)"
|
||||||
|
ROOT="$(git log --pretty=format:%H | tail -n 1)"
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Utilities
|
||||||
|
#
|
||||||
|
die() {
|
||||||
|
local msg="$@"
|
||||||
|
[[ -z "${msg}" ]] || {
|
||||||
|
tput setaf 1 # red
|
||||||
|
tput bold
|
||||||
|
echo "${msg}"
|
||||||
|
tput sgr0 # reset
|
||||||
|
}
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
error() {
|
||||||
|
local msg="$@"
|
||||||
|
echo -n '| '
|
||||||
|
tput setaf 1 # red
|
||||||
|
echo -n ' ✖'
|
||||||
|
tput sgr0 # reset
|
||||||
|
echo " ${msg}"
|
||||||
|
}
|
||||||
|
|
||||||
|
success() {
|
||||||
|
local msg="$@"
|
||||||
|
echo -n '| '
|
||||||
|
tput setaf 2 # green
|
||||||
|
echo -n ' ✓'
|
||||||
|
tput sgr0 # reset
|
||||||
|
echo " ${msg}"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_commit() {
|
||||||
|
echo "○ $@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check a command is present
|
||||||
|
ensure_command() {
|
||||||
|
local cmd="$1"
|
||||||
|
|
||||||
|
command -v "${cmd}" > /dev/null 2>&1 || {
|
||||||
|
die "Couldn't find required command: ${cmd}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Signal handling
|
||||||
|
#
|
||||||
|
cleanup() {
|
||||||
|
git reset --hard "${HEAD}" > /dev/null 2>&1
|
||||||
|
rm -f $$_commit_message
|
||||||
|
}
|
||||||
|
|
||||||
|
trap cleanup SIGHUP SIGINT SIGTERM
|
||||||
|
|
||||||
|
#
|
||||||
|
# Git helpers
|
||||||
|
#
|
||||||
|
|
||||||
|
# Go back one commit in history (first parent for merges)
|
||||||
|
step_back_one_commit() {
|
||||||
|
git reset --hard HEAD^ > /dev/null
|
||||||
|
log_commit "$(git rev-parse HEAD)"
|
||||||
|
}
|
||||||
|
|
||||||
|
current_commit_message() {
|
||||||
|
GIT_PAGER= git log --format=%B -n 1
|
||||||
|
}
|
||||||
|
|
||||||
|
current_commit_sha() {
|
||||||
|
git rev-parse HEAD
|
||||||
|
}
|
||||||
|
|
||||||
|
exit_if_not_git_repo() {
|
||||||
|
local gitroot="$(git rev-parse --show-toplevel 2> /dev/null)"
|
||||||
|
|
||||||
|
[[ "${gitroot}" == "" ]] && die 'Current directory is not in a repository'
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Checks
|
||||||
|
#
|
||||||
|
check_commit_message() {
|
||||||
|
local lineno=0
|
||||||
|
local length=0
|
||||||
|
local succeded=1
|
||||||
|
|
||||||
|
while read -r line ; do
|
||||||
|
let succeded=1
|
||||||
|
let lineno+=1
|
||||||
|
length=${#line}
|
||||||
|
|
||||||
|
[[ "${lineno}" -eq "1" ]] && {
|
||||||
|
[[ "${length}" -gt 50 ]] && {
|
||||||
|
error "Commit message: Subject line longer than 50 characters";
|
||||||
|
succeded=0
|
||||||
|
};
|
||||||
|
|
||||||
|
[[ ! "${line}" =~ ^[A-Z].*$ ]] && {
|
||||||
|
error "Commit message: Subject line not capitalised";
|
||||||
|
succeded=0
|
||||||
|
};
|
||||||
|
|
||||||
|
[[ "${line}" == *. ]] && {
|
||||||
|
error "Commit message: Subject line ended with a full stop";
|
||||||
|
succeded=0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ "${lineno}" -eq "2" ]] && [[ -n "${line}" ]] && {
|
||||||
|
error "Commit message: Subject line not separated by a blank line";
|
||||||
|
succeded=0;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[ "${lineno}" -gt "1" ]] && [[ "${length}" -gt "72" ]] && {
|
||||||
|
error "Commit message: Body not wrapped at 72 characters";
|
||||||
|
succeded=0
|
||||||
|
};
|
||||||
|
done < $$_commit_message
|
||||||
|
|
||||||
|
[[ "${succeded}" -eq "1" ]] && success "Commit message"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
run_checks() {
|
||||||
|
current_commit_message > $$_commit_message
|
||||||
|
check_commit_message
|
||||||
|
rm -f $$_commit_message
|
||||||
|
set +e
|
||||||
|
npm run lint > /dev/null 2>&1
|
||||||
|
if [[ "$?" -eq 0 ]]; then
|
||||||
|
success 'Lint'
|
||||||
|
else
|
||||||
|
error 'Lint: script did not exit successfully'
|
||||||
|
fi
|
||||||
|
npm test > /dev/null 2>&1
|
||||||
|
if [[ "$?" -eq 0 ]]; then
|
||||||
|
success 'Test'
|
||||||
|
else
|
||||||
|
error 'Test: script did not exit successfully'
|
||||||
|
fi
|
||||||
|
set -e
|
||||||
|
}
|
||||||
|
|
||||||
|
check_project() {
|
||||||
|
exit_if_not_git_repo
|
||||||
|
|
||||||
|
[[ -f './package.json' ]] || {
|
||||||
|
die 'This does not appear to be a node project'
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ -z "$(json -f package.json 'scripts.lint')" ]] && {
|
||||||
|
die 'There is no lint script in the package.json'
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ -z "$(json -f package.json 'scripts.test')" ]] && {
|
||||||
|
die 'There is no test script in the package.json'
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
traverse_history() {
|
||||||
|
while [[ "${ROOT}" != "$(current_commit_sha)" ]] ; do
|
||||||
|
run_checks
|
||||||
|
step_back_one_commit
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Main
|
||||||
|
#
|
||||||
|
ensure_command git
|
||||||
|
ensure_command tail
|
||||||
|
ensure_command npm
|
||||||
|
ensure_command json
|
||||||
|
check_project
|
||||||
|
remember_git_start_and_end
|
||||||
|
log_commit "HEAD: $(current_commit_sha)"
|
||||||
|
traverse_history
|
||||||
|
run_checks
|
||||||
|
log_commit "ROOT: $(current_commit_sha)"
|
||||||
|
cleanup
|
||||||
|
|
||||||
|
# vim: syntax=sh et ts=2 sts=2 sw=2
|
16
bin/on-changes-publish-ui
Executable file
16
bin/on-changes-publish-ui
Executable file
@ -0,0 +1,16 @@
|
|||||||
|
#! /usr/bin/env bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# Prelude
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
set -x
|
||||||
|
# Set internal field seperator to `/` to split up urls
|
||||||
|
IFS='/'
|
||||||
|
|
||||||
|
read -ra ADDR <<< "$CIRCLE_COMPARE_URL"
|
||||||
|
|
||||||
|
if [[ "$(git diff --name-only """${ADDR[-1]}""")" == *"ui/"* ]]
|
||||||
|
then
|
||||||
|
make -C ui publish | sed '/NPM_TOKEN/d'
|
||||||
|
fi
|
60
bin/pre-commit.hook
Executable file
60
bin/pre-commit.hook
Executable file
@ -0,0 +1,60 @@
|
|||||||
|
#! /usr/bin/env bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# Prelude - make bash behave sanely
|
||||||
|
# http://redsymbol.net/articles/unofficial-bash-strict-mode/
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Make pushd & popd silent
|
||||||
|
pushd () {
|
||||||
|
command pushd "$@" > /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
popd () {
|
||||||
|
command popd "$@" > /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
export EXIT_CODE=0
|
||||||
|
|
||||||
|
|
||||||
|
function lint_changed() {
|
||||||
|
# Allow lint to be ran from outside of the root directory
|
||||||
|
local git_root
|
||||||
|
git_root=$(git rev-parse --show-cdup)
|
||||||
|
git_root=${git_root:-./}
|
||||||
|
|
||||||
|
local subdirs
|
||||||
|
subdirs=$(find "$git_root" -maxdepth 2 -mindepth 2 -name 'Makefile' -printf '%h\n')
|
||||||
|
|
||||||
|
|
||||||
|
for directory in $subdirs
|
||||||
|
do
|
||||||
|
pushd "$directory"
|
||||||
|
|
||||||
|
local npm_bin="node_modules/.bin"
|
||||||
|
local eslint="$npm_bin/eslint"
|
||||||
|
|
||||||
|
function lint() {
|
||||||
|
local to_lint
|
||||||
|
to_lint=$(git diff --staged --diff-filter=ACMTUXB --name-only -- '*.j'{s,sx})
|
||||||
|
echo $to_lint
|
||||||
|
echo $eslint
|
||||||
|
|
||||||
|
if [ "$to_lint" ]; then
|
||||||
|
$eslint "$to_lint" -c ".eslintrc" || EXIT_CODE=$?
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
lint
|
||||||
|
popd
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
lint_changed
|
||||||
|
if [[ "$EXIT_CODE" -gt "0" ]]; then
|
||||||
|
exit $EXIT_CODE
|
||||||
|
fi
|
||||||
|
make test
|
||||||
|
|
||||||
|
echo "⚡️ changed files pass eslint! ⚡️"
|
23
bin/setup
Executable file
23
bin/setup
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
#! /usr/bin/env bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# Prelude
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
IFS=$'\n\t'
|
||||||
|
# Beware of CDPATH gotchas causing cd not to work correctly when a user
|
||||||
|
# has set this in their environment
|
||||||
|
# https://bosker.wordpress.com/2012/02/12/bash-scripters-beware-of-the-cdpath/
|
||||||
|
unset CDPATH
|
||||||
|
|
||||||
|
readonly INCLUDE="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
# shellcheck source=bin/setup-tools
|
||||||
|
. "${INCLUDE}"/setup-tools
|
||||||
|
|
||||||
|
#
|
||||||
|
# Main
|
||||||
|
#
|
||||||
|
ensure_prerequisites
|
||||||
|
get_triton_details
|
||||||
|
check_docker_config
|
||||||
|
write_env_file
|
105
bin/setup-tools
Normal file
105
bin/setup-tools
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#! /usr/bin/env bash
|
||||||
|
|
||||||
|
# setup.sh - Checks that all the required tools are present and that they are
|
||||||
|
# appropriately configured for deploying to Triton.
|
||||||
|
#
|
||||||
|
# Adapted from https://github.com/autopilotpattern/mysql/blob/master/setup.sh
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Prelude
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
IFS=$'\n\t'
|
||||||
|
|
||||||
|
#
|
||||||
|
# Utilities
|
||||||
|
#
|
||||||
|
die() {
|
||||||
|
local msg="$*"
|
||||||
|
[[ -z "${msg}" ]] || {
|
||||||
|
echo
|
||||||
|
tput setaf 1 # red
|
||||||
|
tput bold
|
||||||
|
echo "${msg}"
|
||||||
|
tput sgr0 # reset
|
||||||
|
}
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check functions
|
||||||
|
#
|
||||||
|
ensure_command() {
|
||||||
|
local cmd="$1"
|
||||||
|
|
||||||
|
command -v "${cmd}" > /dev/null 2>&1 || {
|
||||||
|
die "Couldn't find required command: ${cmd}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get_triton_details() {
|
||||||
|
TRITON_USER=$(triton profile get | awk -F": " '/account:/{print $2}')
|
||||||
|
TRITON_DC=$(triton profile get | awk -F"/" '/url:/{print $3}' | awk -F'.' '{print $1}')
|
||||||
|
TRITON_URL=$(triton profile get | awk -F' ' '/url:/{print $2}')
|
||||||
|
TRITON_ACCOUNT=$(triton account get | awk -F": " '/id:/{print $2}')
|
||||||
|
TRITON_KEY=$(triton profile get | awk -F' ' '/keyId:/{print $2}')
|
||||||
|
}
|
||||||
|
|
||||||
|
check_docker_config() {
|
||||||
|
[[ "${DOCKER_HOST:=unset}" == "unset" ]] && {
|
||||||
|
echo "Run \"docker-compose -f local-compose.yml up\" to run locally"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_docker_config_matches_triton_config_and_capture_triton_details() {
|
||||||
|
local docker_user
|
||||||
|
docker_user=$(docker info 2>&1 | awk -F": " '/SDCAccount:/{print $2}')
|
||||||
|
local docker_dc
|
||||||
|
docker_dc="$(echo "${DOCKER_HOST}" | awk -F"/" '{print $3}' | awk -F'.' '{print $1}')"
|
||||||
|
get_triton_details
|
||||||
|
[[ ! "$docker_user" = "$TRITON_USER" ]] || [[ ! "$docker_dc" = "$TRITON_DC" ]] && {
|
||||||
|
echo "Docker user: ${docker_user}"
|
||||||
|
echo "Triton user: ${TRITON_USER}"
|
||||||
|
echo "Docker data center: ${docker_dc}"
|
||||||
|
echo "Triton data center: ${TRITON_DC}"
|
||||||
|
die "Your Triton config does not match your Docker configuration."
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_triton_cns_is_enabled() {
|
||||||
|
local triton_cns_enabled
|
||||||
|
triton_cns_enabled=$(triton account get | awk -F": " '/cns/{print $2}')
|
||||||
|
[[ "$triton_cns_enabled" == "true" ]] || {
|
||||||
|
die "Triton CNS is required and not enabled."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write_env_file() {
|
||||||
|
if [[ -f .env ]] ; then
|
||||||
|
echo "Env file already exists, not overwriting"
|
||||||
|
else
|
||||||
|
echo '# Consul discovery via Triton CNS' >> .env
|
||||||
|
[[ "${DOCKER_HOST:=unset}" == "*docker.joyent.com*" ]] || {
|
||||||
|
echo CONSUL="consul.svc.${TRITON_ACCOUNT}.${TRITON_DC}.cns.joyent.com" \
|
||||||
|
>> .env
|
||||||
|
}
|
||||||
|
echo SDC_KEY_ID=${TRITON_KEY} >> .env
|
||||||
|
echo SDC_ACCOUNT=${TRITON_ACCOUNT} >> .env
|
||||||
|
echo SDC_URL=${TRITON_URL} >> .env
|
||||||
|
echo >> .env
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_prerequisites() {
|
||||||
|
ensure_command docker
|
||||||
|
ensure_command docker-compose
|
||||||
|
ensure_command triton
|
||||||
|
}
|
||||||
|
|
||||||
|
# vim: syntax=sh et ts=2 sts=2 sw=2
|
57
bin/sketch-previews.rb
Executable file
57
bin/sketch-previews.rb
Executable file
@ -0,0 +1,57 @@
|
|||||||
|
#!/usr/bin/env ruby
|
||||||
|
require 'fileutils'
|
||||||
|
|
||||||
|
PROGNAME = 'pre-commit (auto-generate sketch previews)'
|
||||||
|
|
||||||
|
def main
|
||||||
|
progress "Installing sketchtool"
|
||||||
|
system!(%W[/Applications/Sketch.app/Contents/Resources/sketchtool/install.sh])
|
||||||
|
|
||||||
|
progress "Looking for changed or added .sketch files"
|
||||||
|
diff_output = capture!(%W[git diff --name-only --cached --pretty=format:])
|
||||||
|
sketch_files = diff_output.split("\n").grep(/\.sketch\z/)
|
||||||
|
if sketch_files.empty?
|
||||||
|
progress "No sketch files to create preview images for in this commit!"
|
||||||
|
end
|
||||||
|
puts sketch_files
|
||||||
|
|
||||||
|
sketch_files.each do |f|
|
||||||
|
unless File.exist?(f)
|
||||||
|
progress "#{f} does not exist (anymore?)"
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
png_output_dir = f.sub(/\.sketch\z/, '') + '-sketch-previews'
|
||||||
|
progress "deleting old previews"
|
||||||
|
FileUtils.rm_rf(png_output_dir)
|
||||||
|
|
||||||
|
progress "exporting pages"
|
||||||
|
cmd = %W[sketchtool --overwriting=YES --output=#{png_output_dir} export pages #{f}]
|
||||||
|
system!(cmd)
|
||||||
|
|
||||||
|
progress "adding to git"
|
||||||
|
system!(%W[git add #{png_output_dir}])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def system!(cmd)
|
||||||
|
puts "running: #{cmd.join(' ')}"
|
||||||
|
abort failure_message(cmd) unless system(*cmd)
|
||||||
|
end
|
||||||
|
|
||||||
|
def capture!(cmd)
|
||||||
|
puts "capturing: #{cmd.join(' ')}"
|
||||||
|
result = IO.popen(cmd) { |io| io.read }
|
||||||
|
abort failure_message(cmd) unless $?.success?
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def failure_message(cmd)
|
||||||
|
"#{PROGNAME}: command failed: #{cmd.join(' ')}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def progress(msg)
|
||||||
|
puts "#{PROGNAME}: #{msg}"
|
||||||
|
end
|
||||||
|
|
||||||
|
main
|
@ -1,8 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const { homedir } = require('os');
|
|
||||||
const { join } = require('path');
|
|
||||||
|
|
||||||
const { SDC_KEY_PATH } = process.env;
|
|
||||||
|
|
||||||
process.env.SDC_KEY_PATH = SDC_KEY_PATH || join(homedir(), './.ssh/id_rsa');
|
|
@ -1,20 +0,0 @@
|
|||||||
module.exports = [
|
|
||||||
{
|
|
||||||
name: 'Logout',
|
|
||||||
slug: 'logout',
|
|
||||||
description: 'Do the daggum logout',
|
|
||||||
url: '/logout'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Change Password',
|
|
||||||
slug: 'change-password',
|
|
||||||
description: 'Change yer own password',
|
|
||||||
url: '/password'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Account',
|
|
||||||
slug: 'account',
|
|
||||||
description: 'Your account information',
|
|
||||||
url: '/account'
|
|
||||||
}
|
|
||||||
];
|
|
@ -1,89 +0,0 @@
|
|||||||
module.exports = [
|
|
||||||
{
|
|
||||||
name: 'Compute',
|
|
||||||
services: [
|
|
||||||
{
|
|
||||||
name: 'VMs & Containers',
|
|
||||||
slug: 'instances',
|
|
||||||
description: 'Run VMs and bare metal containers'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Network',
|
|
||||||
services: [
|
|
||||||
{
|
|
||||||
name: 'VLANs',
|
|
||||||
slug: 'vlans',
|
|
||||||
description: 'Wire your application your way'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Subnets',
|
|
||||||
slug: 'subnets',
|
|
||||||
description: 'A network for everything'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Firewall Rules',
|
|
||||||
slug: 'firewall',
|
|
||||||
description: 'Control the bits coming and going'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Storage',
|
|
||||||
services: [
|
|
||||||
{
|
|
||||||
name: 'Triton Object Storage',
|
|
||||||
slug: 'object-storage',
|
|
||||||
description: 'Modern cloud object storage',
|
|
||||||
tags: ["'note'='was Manta'"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'S3 Compatibility Bridge',
|
|
||||||
slug: 's3-bridge',
|
|
||||||
description: 'Modern storage, legacy compability'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Triton Volumes',
|
|
||||||
slug: 'volumes',
|
|
||||||
description: 'Network filesystems for your apps',
|
|
||||||
tags: ["'is-new'='true'"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Access',
|
|
||||||
services: [
|
|
||||||
{
|
|
||||||
name: 'Role Based Access Control',
|
|
||||||
slug: 'rbac',
|
|
||||||
description: 'Manage users within your account'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Help & Support',
|
|
||||||
services: [
|
|
||||||
{
|
|
||||||
name: 'Service Status',
|
|
||||||
slug: 'status',
|
|
||||||
description: 'Find out about the status of our services'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Contact Support',
|
|
||||||
slug: 'contact-support',
|
|
||||||
description: 'Chat to us via phone or email'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Support Plans',
|
|
||||||
slug: 'support-plans',
|
|
||||||
description: 'Write here about Support Plans'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Getting Started',
|
|
||||||
slug: 'getting-started',
|
|
||||||
description: 'Write here about Getting Started'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
@ -1,86 +0,0 @@
|
|||||||
module.exports = [
|
|
||||||
{
|
|
||||||
name: 'Ashburn, Virginia, USA',
|
|
||||||
continent: 'NORTH_AMERICA',
|
|
||||||
datacenters: [
|
|
||||||
{
|
|
||||||
name: 'us-east-1',
|
|
||||||
url: 'http://localhost'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'us-east-2',
|
|
||||||
url: 'http://localhost'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'us-east-3',
|
|
||||||
url: 'http://localhost'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Las Vegas, Nevada, USA',
|
|
||||||
continent: 'NORTH_AMERICA',
|
|
||||||
datacenters: [
|
|
||||||
{
|
|
||||||
name: 'us-sw-1',
|
|
||||||
url: 'http://localhost'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Emeryville, California, USA',
|
|
||||||
continent: 'NORTH_AMERICA',
|
|
||||||
datacenters: [
|
|
||||||
{
|
|
||||||
name: 'us-west-1',
|
|
||||||
url: 'http://localhost'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Amsterdam, Netherlands',
|
|
||||||
continent: 'EUROPE',
|
|
||||||
datacenters: [
|
|
||||||
{
|
|
||||||
name: 'us-ams-1',
|
|
||||||
url: 'http://localhost'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Singapore',
|
|
||||||
continent: 'ASIA',
|
|
||||||
datacenters: [
|
|
||||||
{
|
|
||||||
name: 'ap-sg-1',
|
|
||||||
url: 'http://localhost'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'ap-sg-2',
|
|
||||||
url: 'http://localhost'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'ap-sg-3',
|
|
||||||
url: 'http://localhost'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Seoul, South Korea',
|
|
||||||
continent: 'ASIA',
|
|
||||||
datacenters: [
|
|
||||||
{
|
|
||||||
name: 'ap-kr-1',
|
|
||||||
url: 'http://localhost'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'ap-kr-2',
|
|
||||||
url: 'http://localhost'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'ap-kr-3',
|
|
||||||
url: 'http://localhost'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
@ -1,72 +0,0 @@
|
|||||||
// Requires .env.js file with the following exports:
|
|
||||||
// SDC_URL, SDC_KEY_ID, SDC_KEY_PATH
|
|
||||||
require('./.env.js');
|
|
||||||
|
|
||||||
const Main = require('apr-main');
|
|
||||||
const Hapi = require('hapi');
|
|
||||||
const H2O2 = require('h2o2');
|
|
||||||
const Execa = require('execa');
|
|
||||||
const Path = require('path');
|
|
||||||
const Fs = require('fs');
|
|
||||||
|
|
||||||
const { PORT = 4000 } = process.env;
|
|
||||||
const ROOT = Path.join(__dirname, 'src');
|
|
||||||
|
|
||||||
const calcPort = i => Number(PORT) + Number(i) + 1;
|
|
||||||
|
|
||||||
const namespaces = Fs.readdirSync(ROOT)
|
|
||||||
.filter(filename => /.js$/.test(filename))
|
|
||||||
.map(filename => filename.replace(/.js$/, ''))
|
|
||||||
.filter(filename => !['index', 'server'].includes(filename));
|
|
||||||
|
|
||||||
const routes = namespaces.map((namespace, i) => ({
|
|
||||||
method: '*',
|
|
||||||
path: `/${namespace}/{params*}`,
|
|
||||||
handler: {
|
|
||||||
proxy: {
|
|
||||||
uri: `{protocol}://0.0.0.0:${calcPort(i)}/${namespace}/{params}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
namespaces.forEach((namespace, i) => {
|
|
||||||
const child = Execa('node', [namespace], {
|
|
||||||
cwd: ROOT,
|
|
||||||
cleanup: true,
|
|
||||||
env: Object.assign({}, process.env, {
|
|
||||||
PORT: calcPort(i),
|
|
||||||
PREFIX: namespace
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
child.stdout.pipe(process.stdout);
|
|
||||||
child.stderr.pipe(process.stderr);
|
|
||||||
});
|
|
||||||
|
|
||||||
Main(async () => {
|
|
||||||
const server = Hapi.server({
|
|
||||||
port: PORT,
|
|
||||||
routes: {
|
|
||||||
cors: {
|
|
||||||
origin: ['*'],
|
|
||||||
credentials: true,
|
|
||||||
additionalHeaders: ['Cookie', 'X-CSRF-Token']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
debug: {
|
|
||||||
log: ['error'],
|
|
||||||
request: ['error']
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await server.register({
|
|
||||||
plugin: H2O2
|
|
||||||
});
|
|
||||||
|
|
||||||
routes.map(route => server.route(route));
|
|
||||||
|
|
||||||
await server.start();
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log(`server started at http://0.0.0.0:${server.info.port}`);
|
|
||||||
});
|
|
@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "joyent-portal-bundle",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"private": true,
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"scripts": {
|
|
||||||
"dev": "NODE_ENV=development PORT=4000 node index.js",
|
|
||||||
"build:test": "echo 0",
|
|
||||||
"build:lib": "echo 0",
|
|
||||||
"build:bundle": "echo 0",
|
|
||||||
"prepublish": "echo 0",
|
|
||||||
"test": "echo 0",
|
|
||||||
"test:ci": "echo 0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"apr-main": "^4.0.3",
|
|
||||||
"cloudapi-gql": "^8.0.0",
|
|
||||||
"execa": "^0.10.0",
|
|
||||||
"graphi": "^5.7.0",
|
|
||||||
"h2o2": "^8.1.2",
|
|
||||||
"hapi": "^17.5.0",
|
|
||||||
"hapi-triton-auth": "^3.0.0",
|
|
||||||
"hapi-webconsole-nav": "^2.1.0",
|
|
||||||
"my-joy-images": "*",
|
|
||||||
"my-joy-instances": "*",
|
|
||||||
"my-joy-navigation": "*",
|
|
||||||
"my-joy-service-groups": "*",
|
|
||||||
"my-joy-templates": "*",
|
|
||||||
"tsg-graphql": "^1.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
require('../.env.js');
|
|
||||||
|
|
||||||
const Main = require('apr-main');
|
|
||||||
const CloudApiGql = require('cloudapi-gql');
|
|
||||||
const Graphi = require('graphi');
|
|
||||||
const Url = require('url');
|
|
||||||
|
|
||||||
const Server = require('./server');
|
|
||||||
const Ui = require('my-joy-images');
|
|
||||||
|
|
||||||
const {
|
|
||||||
PORT = 4003,
|
|
||||||
BASE_URL = `http://0.0.0.0:${PORT}`,
|
|
||||||
PREFIX = 'images',
|
|
||||||
DC_NAME,
|
|
||||||
SDC_URL,
|
|
||||||
SDC_KEY_PATH,
|
|
||||||
SDC_ACCOUNT,
|
|
||||||
SDC_KEY_ID
|
|
||||||
} = process.env;
|
|
||||||
|
|
||||||
const dcName = DC_NAME || Url.parse(SDC_URL).host.split('.')[0];
|
|
||||||
const keyPath = SDC_KEY_PATH;
|
|
||||||
const keyId = `/${SDC_ACCOUNT}/keys/${SDC_KEY_ID}`;
|
|
||||||
const apiBaseUrl = SDC_URL;
|
|
||||||
|
|
||||||
Main(async () => {
|
|
||||||
const server = await Server({
|
|
||||||
PORT,
|
|
||||||
BASE_URL
|
|
||||||
});
|
|
||||||
|
|
||||||
await server.register([
|
|
||||||
{
|
|
||||||
plugin: Graphi,
|
|
||||||
options: {
|
|
||||||
graphqlPath: '/graphql',
|
|
||||||
graphiqlPath: '/graphiql',
|
|
||||||
authStrategy: 'sso'
|
|
||||||
},
|
|
||||||
routes: {
|
|
||||||
prefix: `/${PREFIX}`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
plugin: CloudApiGql,
|
|
||||||
options: {
|
|
||||||
authStrategy: 'sso',
|
|
||||||
keyPath,
|
|
||||||
keyId,
|
|
||||||
apiBaseUrl,
|
|
||||||
dcName
|
|
||||||
},
|
|
||||||
routes: {
|
|
||||||
prefix: `/${PREFIX}`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
plugin: Ui
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
await server.start();
|
|
||||||
});
|
|
@ -1,64 +0,0 @@
|
|||||||
require('../.env.js');
|
|
||||||
|
|
||||||
const Main = require('apr-main');
|
|
||||||
const CloudApiGql = require('cloudapi-gql');
|
|
||||||
const Graphi = require('graphi');
|
|
||||||
const Url = require('url');
|
|
||||||
|
|
||||||
const Server = require('./server');
|
|
||||||
const Ui = require('my-joy-instances');
|
|
||||||
|
|
||||||
const {
|
|
||||||
PORT = 4002,
|
|
||||||
BASE_URL = `http://0.0.0.0:${PORT}`,
|
|
||||||
PREFIX = 'instances',
|
|
||||||
DC_NAME,
|
|
||||||
SDC_URL,
|
|
||||||
SDC_KEY_PATH,
|
|
||||||
SDC_ACCOUNT,
|
|
||||||
SDC_KEY_ID
|
|
||||||
} = process.env;
|
|
||||||
|
|
||||||
const dcName = DC_NAME || Url.parse(SDC_URL).host.split('.')[0];
|
|
||||||
const keyPath = SDC_KEY_PATH;
|
|
||||||
const keyId = `/${SDC_ACCOUNT}/keys/${SDC_KEY_ID}`;
|
|
||||||
const apiBaseUrl = SDC_URL;
|
|
||||||
|
|
||||||
Main(async () => {
|
|
||||||
const server = await Server({
|
|
||||||
PORT,
|
|
||||||
BASE_URL
|
|
||||||
});
|
|
||||||
|
|
||||||
await server.register([
|
|
||||||
{
|
|
||||||
plugin: Graphi,
|
|
||||||
options: {
|
|
||||||
graphqlPath: '/graphql',
|
|
||||||
graphiqlPath: '/graphiql',
|
|
||||||
authStrategy: 'sso'
|
|
||||||
},
|
|
||||||
routes: {
|
|
||||||
prefix: `/${PREFIX}`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
plugin: CloudApiGql,
|
|
||||||
options: {
|
|
||||||
authStrategy: 'sso',
|
|
||||||
keyPath,
|
|
||||||
keyId,
|
|
||||||
apiBaseUrl,
|
|
||||||
dcName
|
|
||||||
},
|
|
||||||
routes: {
|
|
||||||
prefix: `/${PREFIX}`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
plugin: Ui
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
await server.start();
|
|
||||||
});
|
|
@ -1,72 +0,0 @@
|
|||||||
require('../.env.js');
|
|
||||||
|
|
||||||
const Main = require('apr-main');
|
|
||||||
const Nav = require('hapi-webconsole-nav');
|
|
||||||
const Graphi = require('graphi');
|
|
||||||
const Url = require('url');
|
|
||||||
|
|
||||||
const Server = require('./server');
|
|
||||||
const Ui = require('my-joy-navigation');
|
|
||||||
|
|
||||||
const Regions = require('../data/regions');
|
|
||||||
const Categories = require('../data/categories');
|
|
||||||
const Account = require('../data/account');
|
|
||||||
|
|
||||||
const {
|
|
||||||
PORT = 4001,
|
|
||||||
BASE_URL = `http://0.0.0.0:${PORT}`,
|
|
||||||
PREFIX = 'navigation',
|
|
||||||
DC_NAME,
|
|
||||||
SDC_URL,
|
|
||||||
SDC_KEY_PATH,
|
|
||||||
SDC_ACCOUNT,
|
|
||||||
SDC_KEY_ID
|
|
||||||
} = process.env;
|
|
||||||
|
|
||||||
const dcName = DC_NAME || Url.parse(SDC_URL).host.split('.')[0];
|
|
||||||
const keyPath = SDC_KEY_PATH;
|
|
||||||
const keyId = `/${SDC_ACCOUNT}/keys/${SDC_KEY_ID}`;
|
|
||||||
const apiBaseUrl = SDC_URL;
|
|
||||||
const baseUrl = BASE_URL;
|
|
||||||
|
|
||||||
Main(async () => {
|
|
||||||
const server = await Server({
|
|
||||||
PORT,
|
|
||||||
BASE_URL
|
|
||||||
});
|
|
||||||
|
|
||||||
await server.register([
|
|
||||||
{
|
|
||||||
plugin: Graphi,
|
|
||||||
options: {
|
|
||||||
graphqlPath: '/graphql',
|
|
||||||
graphiqlPath: '/graphiql',
|
|
||||||
authStrategy: 'sso'
|
|
||||||
},
|
|
||||||
routes: {
|
|
||||||
prefix: `/${PREFIX}`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
plugin: Nav,
|
|
||||||
options: {
|
|
||||||
keyPath,
|
|
||||||
keyId,
|
|
||||||
apiBaseUrl,
|
|
||||||
dcName,
|
|
||||||
baseUrl,
|
|
||||||
regions: Regions,
|
|
||||||
accountServices: Account,
|
|
||||||
categories: Categories
|
|
||||||
},
|
|
||||||
routes: {
|
|
||||||
prefix: `/${PREFIX}`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
plugin: Ui
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
await server.start();
|
|
||||||
});
|
|
@ -1,84 +0,0 @@
|
|||||||
require('../.env.js');
|
|
||||||
|
|
||||||
const Hapi = require('hapi');
|
|
||||||
const Sso = require('hapi-triton-auth');
|
|
||||||
|
|
||||||
const {
|
|
||||||
COOKIE_PASSWORD,
|
|
||||||
COOKIE_DOMAIN,
|
|
||||||
SDC_KEY_PATH,
|
|
||||||
SDC_ACCOUNT,
|
|
||||||
SDC_KEY_ID,
|
|
||||||
SDC_URL
|
|
||||||
} = process.env;
|
|
||||||
|
|
||||||
module.exports = async ({ PORT, BASE_URL }) => {
|
|
||||||
const keyPath = SDC_KEY_PATH;
|
|
||||||
const keyId = `/${SDC_ACCOUNT}/keys/${SDC_KEY_ID}`;
|
|
||||||
const apiBaseUrl = SDC_URL;
|
|
||||||
const ssoUrl = 'https://sso.joyent.com/login';
|
|
||||||
const baseUrl = BASE_URL;
|
|
||||||
const isDev = true;
|
|
||||||
|
|
||||||
const permissions = {
|
|
||||||
cloudapi: ['/my/*']
|
|
||||||
};
|
|
||||||
|
|
||||||
const cookie = {
|
|
||||||
password: COOKIE_PASSWORD,
|
|
||||||
domain: COOKIE_DOMAIN,
|
|
||||||
isSecure: false,
|
|
||||||
isHttpOnly: true,
|
|
||||||
ttl: 1000 * 60 * 60 // 1 hour
|
|
||||||
};
|
|
||||||
|
|
||||||
const server = Hapi.server({
|
|
||||||
port: PORT,
|
|
||||||
routes: {
|
|
||||||
cors: {
|
|
||||||
origin: ['*'],
|
|
||||||
credentials: true,
|
|
||||||
additionalHeaders: ['Cookie', 'X-CSRF-Token']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
debug: {
|
|
||||||
log: ['error'],
|
|
||||||
request: ['error']
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
server.events.on('log', (event, tags) => {
|
|
||||||
if (tags.error) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log(event);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
server.events.on('request', (request, event) => {
|
|
||||||
const { tags } = event;
|
|
||||||
if (tags.includes('error') && event.data && event.data.errors) {
|
|
||||||
event.data.errors.forEach(error => {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await server.register({
|
|
||||||
plugin: Sso,
|
|
||||||
options: {
|
|
||||||
keyPath,
|
|
||||||
keyId,
|
|
||||||
apiBaseUrl,
|
|
||||||
ssoUrl,
|
|
||||||
permissions,
|
|
||||||
baseUrl,
|
|
||||||
isDev,
|
|
||||||
cookie
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
server.auth.default('sso');
|
|
||||||
|
|
||||||
return server;
|
|
||||||
};
|
|
@ -1,78 +0,0 @@
|
|||||||
require('../.env.js');
|
|
||||||
|
|
||||||
const Main = require('apr-main');
|
|
||||||
const CloudApiGql = require('cloudapi-gql');
|
|
||||||
const Tsg = require('tsg-graphql');
|
|
||||||
const Graphi = require('graphi');
|
|
||||||
const Url = require('url');
|
|
||||||
|
|
||||||
const Server = require('./server');
|
|
||||||
const Ui = require('my-joy-service-groups');
|
|
||||||
|
|
||||||
const {
|
|
||||||
PORT = 4004,
|
|
||||||
BASE_URL = `http://0.0.0.0:${PORT}`,
|
|
||||||
PREFIX = 'service-groups',
|
|
||||||
DC_NAME,
|
|
||||||
TSG_URL = 'http://0.0.0.0:3000',
|
|
||||||
SDC_URL,
|
|
||||||
SDC_KEY_PATH,
|
|
||||||
SDC_ACCOUNT,
|
|
||||||
SDC_KEY_ID
|
|
||||||
} = process.env;
|
|
||||||
|
|
||||||
const dcName = DC_NAME || Url.parse(SDC_URL).host.split('.')[0];
|
|
||||||
const keyPath = SDC_KEY_PATH;
|
|
||||||
const keyId = `/${SDC_ACCOUNT}/keys/${SDC_KEY_ID}`;
|
|
||||||
|
|
||||||
Main(async () => {
|
|
||||||
const server = await Server({
|
|
||||||
PORT,
|
|
||||||
BASE_URL
|
|
||||||
});
|
|
||||||
|
|
||||||
await server.register([
|
|
||||||
{
|
|
||||||
plugin: Graphi,
|
|
||||||
options: {
|
|
||||||
graphqlPath: '/graphql',
|
|
||||||
graphiqlPath: '/graphiql',
|
|
||||||
authStrategy: 'sso'
|
|
||||||
},
|
|
||||||
routes: {
|
|
||||||
prefix: `/${PREFIX}`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
plugin: Tsg,
|
|
||||||
options: {
|
|
||||||
authStrategy: 'sso',
|
|
||||||
keyPath,
|
|
||||||
keyId,
|
|
||||||
apiBaseUrl: TSG_URL,
|
|
||||||
dcName
|
|
||||||
},
|
|
||||||
routes: {
|
|
||||||
prefix: `/${PREFIX}`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
plugin: CloudApiGql,
|
|
||||||
options: {
|
|
||||||
authStrategy: 'sso',
|
|
||||||
keyPath,
|
|
||||||
keyId,
|
|
||||||
apiBaseUrl: SDC_URL,
|
|
||||||
dcName
|
|
||||||
},
|
|
||||||
routes: {
|
|
||||||
prefix: `/${PREFIX}`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
plugin: Ui
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
await server.start();
|
|
||||||
});
|
|
@ -1,78 +0,0 @@
|
|||||||
require('../.env.js');
|
|
||||||
|
|
||||||
const Main = require('apr-main');
|
|
||||||
const CloudApiGql = require('cloudapi-gql');
|
|
||||||
const Tsg = require('tsg-graphql');
|
|
||||||
const Graphi = require('graphi');
|
|
||||||
const Url = require('url');
|
|
||||||
|
|
||||||
const Server = require('./server');
|
|
||||||
const Ui = require('my-joy-templates');
|
|
||||||
|
|
||||||
const {
|
|
||||||
PORT = 4005,
|
|
||||||
BASE_URL = `http://0.0.0.0:${PORT}`,
|
|
||||||
PREFIX = 'templates',
|
|
||||||
DC_NAME,
|
|
||||||
TSG_URL = 'http://0.0.0.0:3000',
|
|
||||||
SDC_URL,
|
|
||||||
SDC_KEY_PATH,
|
|
||||||
SDC_ACCOUNT,
|
|
||||||
SDC_KEY_ID
|
|
||||||
} = process.env;
|
|
||||||
|
|
||||||
const dcName = DC_NAME || Url.parse(SDC_URL).host.split('.')[0];
|
|
||||||
const keyPath = SDC_KEY_PATH;
|
|
||||||
const keyId = `/${SDC_ACCOUNT}/keys/${SDC_KEY_ID}`;
|
|
||||||
|
|
||||||
Main(async () => {
|
|
||||||
const server = await Server({
|
|
||||||
PORT,
|
|
||||||
BASE_URL
|
|
||||||
});
|
|
||||||
|
|
||||||
await server.register([
|
|
||||||
{
|
|
||||||
plugin: Graphi,
|
|
||||||
options: {
|
|
||||||
graphqlPath: '/graphql',
|
|
||||||
graphiqlPath: '/graphiql',
|
|
||||||
authStrategy: 'sso'
|
|
||||||
},
|
|
||||||
routes: {
|
|
||||||
prefix: `/${PREFIX}`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
plugin: Tsg,
|
|
||||||
options: {
|
|
||||||
authStrategy: 'sso',
|
|
||||||
keyPath,
|
|
||||||
keyId,
|
|
||||||
apiBaseUrl: TSG_URL,
|
|
||||||
dcName
|
|
||||||
},
|
|
||||||
routes: {
|
|
||||||
prefix: `/${PREFIX}`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
plugin: CloudApiGql,
|
|
||||||
options: {
|
|
||||||
authStrategy: 'sso',
|
|
||||||
keyPath,
|
|
||||||
keyId,
|
|
||||||
apiBaseUrl: SDC_URL,
|
|
||||||
dcName
|
|
||||||
},
|
|
||||||
routes: {
|
|
||||||
prefix: `/${PREFIX}`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
plugin: Ui
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
await server.start();
|
|
||||||
});
|
|
51
circle.yml
Normal file
51
circle.yml
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
## Customize the test machine
|
||||||
|
machine:
|
||||||
|
pre:
|
||||||
|
- git config --global user.email "circleci@joyent.zone"
|
||||||
|
- git config --global user.name "circlebot"
|
||||||
|
- curl -sSL https://s3.amazonaws.com/circle-downloads/install-circleci-docker.sh | bash -s -- 1.10.0
|
||||||
|
|
||||||
|
services:
|
||||||
|
- docker
|
||||||
|
node:
|
||||||
|
version: 7.7.3
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
pre:
|
||||||
|
- sudo curl -L https://github.com/docker/compose/releases/download/1.8.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
|
||||||
|
- sudo chmod +x /usr/local/bin/docker-compose
|
||||||
|
- yarn global add triton@4.15.0 || cat /home/ubuntu/.yarn-config/global/yarn-error.log
|
||||||
|
- echo '{"url":"https://eu-ams-1.api.joyent.com","account":"'$SDC_ACCOUNT'","keyId":"c3:30:35:9b:85:48:73:44:31:cc:4b:2e:6a:00:16:e2","name":"eu-ams-1","curr":true}' | triton profile create -f -
|
||||||
|
- triton env --docker eu-ams-1
|
||||||
|
- mkdir -p ${CIRCLE_TEST_REPORTS}/tap-xunit/
|
||||||
|
- echo -e "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
|
||||||
|
override:
|
||||||
|
- make && make install
|
||||||
|
# Install git-lfs - TODO: Move to make task
|
||||||
|
- curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
|
||||||
|
- sudo apt-get install git-lfs
|
||||||
|
- ssh git@github.com git-lfs-authenticate yldio/joyent-portal.git download
|
||||||
|
- git config credential.helper manager
|
||||||
|
- git lfs pull
|
||||||
|
|
||||||
|
test:
|
||||||
|
override:
|
||||||
|
- make -j2 lint-ci test-ci
|
||||||
|
|
||||||
|
deployment:
|
||||||
|
development:
|
||||||
|
branch: master
|
||||||
|
commands:
|
||||||
|
- ./bin/docker-login
|
||||||
|
- ./bin/on-changes-publish-ui
|
||||||
|
- make -j2 build
|
||||||
|
- make -j2 push
|
||||||
|
- ./bin/deploy
|
||||||
|
staging:
|
||||||
|
tag: /release.*/
|
||||||
|
commands:
|
||||||
|
- CIRCLE_BRANCH=staging ./bin/docker-login
|
||||||
|
- CIRCLE_BRANCH=staging ./bin/on-changes-publish-ui
|
||||||
|
- CIRCLE_BRANCH=staging make -j2 build
|
||||||
|
- CIRCLE_BRANCH=staging make -j2 push
|
||||||
|
- CIRCLE_BRANCH=staging ./bin/deploy
|
27
cloudapi-graphql/.eslintrc
Normal file
27
cloudapi-graphql/.eslintrc
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"prettier"
|
||||||
|
],
|
||||||
|
"plugins": [
|
||||||
|
"prettier"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"no-console": 0,
|
||||||
|
"prettier/prettier": ["error", {
|
||||||
|
"useTabs": false,
|
||||||
|
"printWidth": 80,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"jsxBracketSameLine": false,
|
||||||
|
"parser": "flow",
|
||||||
|
"semi": true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"es6": true,
|
||||||
|
"node": true
|
||||||
|
}
|
||||||
|
}
|
50
cloudapi-graphql/.gitignore
vendored
Normal file
50
cloudapi-graphql/.gitignore
vendored
Normal file
@ -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
|
1
cloudapi-graphql/Dockerfile
Normal file
1
cloudapi-graphql/Dockerfile
Normal file
@ -0,0 +1 @@
|
|||||||
|
FROM quay.io/yldio/alpine-node-containerpilot:6.9.4-3
|
54
cloudapi-graphql/Makefile
Normal file
54
cloudapi-graphql/Makefile
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
NAME := $(lastword $(subst /, ,$(CURDIR)))
|
||||||
|
|
||||||
|
bindir := $(shell yarn bin)
|
||||||
|
AVA := $(bindir)/ava
|
||||||
|
NYC := $(bindir)/nyc
|
||||||
|
|
||||||
|
.PHONY: install
|
||||||
|
install:
|
||||||
|
yarn install --prefer-offline
|
||||||
|
|
||||||
|
.PHONY: install-production
|
||||||
|
install-production:
|
||||||
|
yarn install --production --pure-lockfile --prefer-offline
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
@rm -rf node_modules
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test:
|
||||||
|
$(AVA) $(TEST_ARGS)
|
||||||
|
|
||||||
|
XUNIT_DIR := ${CIRCLE_TEST_REPORTS}/tap-xunit
|
||||||
|
XUNIT := $(bindir)/tap-xunit
|
||||||
|
XUNIT_OUTPUT := >> ${CIRCLE_TEST_REPORTS}/tap-xunit/xunit-$(NAME)
|
||||||
|
.PHONY: test-ci
|
||||||
|
test-ci:
|
||||||
|
mkdir -p $(XUNIT_DIR)
|
||||||
|
$(NYC) $(AVA) -t | $(XUNIT) $(XUNIT_OUTPUT).xml
|
||||||
|
|
||||||
|
.PHONY: start
|
||||||
|
start:
|
||||||
|
yarn run start
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
build:
|
||||||
|
docker build -t quay.io/yldio/joyent-dashboard-$(NAME):$(CIRCLE_BRANCH) .
|
||||||
|
|
||||||
|
.PHONY: push
|
||||||
|
push:
|
||||||
|
docker push quay.io/yldio/joyent-dashboard-$(NAME)
|
||||||
|
|
||||||
|
.PHONY: lint
|
||||||
|
lint:
|
||||||
|
$(bindir)/eslint .
|
||||||
|
|
||||||
|
.PHONY: lint-ci
|
||||||
|
lint-ci:
|
||||||
|
mkdir -p $(XUNIT_DIR)
|
||||||
|
-$(bindir)/eslint . --format tap | $(XUNIT) $(XUNIT_OUTPUT)-lint.xml
|
||||||
|
|
||||||
|
.PHONY: licence-check
|
||||||
|
licence-check:
|
||||||
|
../node_modules/.bin/license-to-fail ../licence.js
|
166
cloudapi-graphql/README.md
Normal file
166
cloudapi-graphql/README.md
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
[![Docker Repository on Quay](https://quay.io/repository/yldio/joyent-dashboard-cloudapi-graphql/status?token=bddd694a-a913-4b66-b7bc-fb71992672c4 "Docker Repository on Quay")](https://quay.io/repository/yldio/joyent-dashboard-cloudapi-graphql)
|
||||||
|
# cloudapi-graphql
|
||||||
|
|
||||||
|
Proof-of-Concept of the [Joyent Cloud API](https://apidocs.joyent.com/cloudapi/) running on GraphQL.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
### Setup Credentials
|
||||||
|
|
||||||
|
Create `credentials.json`:
|
||||||
|
|
||||||
|
```json5
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively you can just use ENV variables:
|
||||||
|
|
||||||
|
```
|
||||||
|
SDC_URL
|
||||||
|
SDC_ACCOUNT
|
||||||
|
SDC_USER
|
||||||
|
SDC_KEY_ID
|
||||||
|
```
|
||||||
|
|
||||||
|
As a third option you can use a `.env` file.
|
||||||
|
|
||||||
|
### Install Dependencies and run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn install
|
||||||
|
yarn start
|
||||||
|
```
|
||||||
|
|
||||||
|
### Visit GraphiQL
|
||||||
|
|
||||||
|
Go-to http://0.0.0.0:4000/graphql to use the REPL with interactive documentation.
|
||||||
|
|
||||||
|
![GraphiQL](https://cloud.githubusercontent.com/assets/524382/19242455/1e371978-8f0b-11e6-9563-d6f5b93fa63c.png)
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
38
cloudapi-graphql/etc/containerpilot.json
Normal file
38
cloudapi-graphql/etc/containerpilot.json
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"consul": "{{ .CONSUL }}:8500",
|
||||||
|
"services": [{
|
||||||
|
"name": "joyent-portal-cloudapi-graphql",
|
||||||
|
"port": 4000,
|
||||||
|
"health": "/usr/bin/curl -o /dev/null --fail -s http://localhost:4000/graphql",
|
||||||
|
"poll": 3,
|
||||||
|
"ttl": 10
|
||||||
|
}],
|
||||||
|
"telemetry": {
|
||||||
|
"port": 9090,
|
||||||
|
"sensors": [{
|
||||||
|
"name": "graphql_memory_percent",
|
||||||
|
"help": "percentage of memory used",
|
||||||
|
"type": "gauge",
|
||||||
|
"poll": 5,
|
||||||
|
"check": ["/bin/sensors", "memory"]
|
||||||
|
}, {
|
||||||
|
"name": "graphql_cpu_load",
|
||||||
|
"help": "cpu load",
|
||||||
|
"type": "gauge",
|
||||||
|
"poll": 5,
|
||||||
|
"check": ["/bin/sensors", "cpu"]
|
||||||
|
}, {
|
||||||
|
"name": "graphql_disk_capacity",
|
||||||
|
"help": "disk capacity",
|
||||||
|
"type": "gauge",
|
||||||
|
"poll": 60,
|
||||||
|
"check": ["/bin/sensors", "diskcapacity"]
|
||||||
|
}, {
|
||||||
|
"name": "graphql_disk_usage",
|
||||||
|
"help": "disk usage",
|
||||||
|
"type": "gauge",
|
||||||
|
"poll": 60,
|
||||||
|
"check": ["/bin/sensors", "diskusage"]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
31
cloudapi-graphql/package.json
Normal file
31
cloudapi-graphql/package.json
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"name": "cloudapi-graphql",
|
||||||
|
"private": true,
|
||||||
|
"license": "MPL-2.0",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "src/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"lint": "eslint src --fix",
|
||||||
|
"start": "node src/index.js",
|
||||||
|
"test": "make test"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"bunyan": "^1.8.10",
|
||||||
|
"dotenv": "^4.0.0",
|
||||||
|
"express": "^4.15.2",
|
||||||
|
"express-graphql": "^0.6.4",
|
||||||
|
"got": "^6.7.1",
|
||||||
|
"graphql": "^0.9.3",
|
||||||
|
"smartdc-auth": "^2.5.2",
|
||||||
|
"triton": "^5.2.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"ava": "^0.19.1",
|
||||||
|
"eslint": "^3.19.0",
|
||||||
|
"eslint-config-prettier": "^1.7.0",
|
||||||
|
"eslint-plugin-prettier": "^2.0.1",
|
||||||
|
"nyc": "^10.2.0",
|
||||||
|
"prettier": "^1.2.2",
|
||||||
|
"tap-xunit": "^1.7.0"
|
||||||
|
}
|
||||||
|
}
|
9
cloudapi-graphql/src/api/account.js
Normal file
9
cloudapi-graphql/src/api/account.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
const request = require('./request');
|
||||||
|
|
||||||
|
module.exports.get = () => {
|
||||||
|
return request('getAccount');
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.update = ctx => {
|
||||||
|
return request('updateAccount', ctx);
|
||||||
|
};
|
5
cloudapi-graphql/src/api/config.js
Normal file
5
cloudapi-graphql/src/api/config.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// const request = require('./request');
|
||||||
|
|
||||||
|
module.exports.get = () => {
|
||||||
|
// return request('', ctx);
|
||||||
|
};
|
5
cloudapi-graphql/src/api/datacenters.js
Normal file
5
cloudapi-graphql/src/api/datacenters.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const request = require('./request');
|
||||||
|
|
||||||
|
module.exports = () => {
|
||||||
|
return request('listDatacenters');
|
||||||
|
};
|
9
cloudapi-graphql/src/api/fabrics.js
Normal file
9
cloudapi-graphql/src/api/fabrics.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
const request = require('./request');
|
||||||
|
|
||||||
|
module.exports.list = () => {
|
||||||
|
return request('listFirewallRules', {});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.get = ctx => {
|
||||||
|
return request('getFirewallRule', ctx);
|
||||||
|
};
|
37
cloudapi-graphql/src/api/firewall-rules.js
Normal file
37
cloudapi-graphql/src/api/firewall-rules.js
Normal file
@ -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);
|
||||||
|
};
|
25
cloudapi-graphql/src/api/images.js
Normal file
25
cloudapi-graphql/src/api/images.js
Normal file
@ -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);
|
||||||
|
// };
|
16
cloudapi-graphql/src/api/index.js
Normal file
16
cloudapi-graphql/src/api/index.js
Normal file
@ -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')
|
||||||
|
};
|
35
cloudapi-graphql/src/api/keys.js
Normal file
35
cloudapi-graphql/src/api/keys.js
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
108
cloudapi-graphql/src/api/machines.js
Normal file
108
cloudapi-graphql/src/api/machines.js
Normal file
@ -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;
|
9
cloudapi-graphql/src/api/networks.js
Normal file
9
cloudapi-graphql/src/api/networks.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
const request = require('./request');
|
||||||
|
|
||||||
|
module.exports.list = () => {
|
||||||
|
return request('listNetworks');
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.get = ctx => {
|
||||||
|
return request('getNetwork', ctx);
|
||||||
|
};
|
9
cloudapi-graphql/src/api/nics.js
Normal file
9
cloudapi-graphql/src/api/nics.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
const request = require('./request');
|
||||||
|
|
||||||
|
module.exports.list = () => {
|
||||||
|
return request('listNics');
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.get = ctx => {
|
||||||
|
return request('getNic', ctx);
|
||||||
|
};
|
9
cloudapi-graphql/src/api/packages.js
Normal file
9
cloudapi-graphql/src/api/packages.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
const request = require('./request');
|
||||||
|
|
||||||
|
module.exports.list = ctx => {
|
||||||
|
return request('listPackages', ctx);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.get = ctx => {
|
||||||
|
return request('getPackage', ctx);
|
||||||
|
};
|
21
cloudapi-graphql/src/api/policies.js
Normal file
21
cloudapi-graphql/src/api/policies.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
const request = require('./request');
|
||||||
|
|
||||||
|
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);
|
||||||
|
};
|
40
cloudapi-graphql/src/api/request.js
Normal file
40
cloudapi-graphql/src/api/request.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
const credentials = require('../credentials');
|
||||||
|
const auth = require('smartdc-auth');
|
||||||
|
const cloudapi = require('triton/lib/cloudapi2');
|
||||||
|
const bunyan = require('bunyan');
|
||||||
|
const pkg = require('../../package.json');
|
||||||
|
|
||||||
|
var log = bunyan.createLogger({
|
||||||
|
name: pkg.name
|
||||||
|
});
|
||||||
|
|
||||||
|
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;
|
31
cloudapi-graphql/src/api/roles.js
Normal file
31
cloudapi-graphql/src/api/roles.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
const request = require('./request');
|
||||||
|
|
||||||
|
module.exports.list = () => {
|
||||||
|
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 ? `/${ctx.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);
|
||||||
|
};
|
5
cloudapi-graphql/src/api/services.js
Normal file
5
cloudapi-graphql/src/api/services.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const request = require('./request');
|
||||||
|
|
||||||
|
module.exports = () => {
|
||||||
|
return request('listServices');
|
||||||
|
};
|
21
cloudapi-graphql/src/api/users.js
Normal file
21
cloudapi-graphql/src/api/users.js
Normal file
@ -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);
|
||||||
|
};
|
27
cloudapi-graphql/src/credentials.js
Normal file
27
cloudapi-graphql/src/credentials.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
const json = (() => {
|
||||||
|
try {
|
||||||
|
const res = require('dotenv').config({
|
||||||
|
path: '../.env',
|
||||||
|
silent: true
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.error) {
|
||||||
|
throw res.error;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
try {
|
||||||
|
return require('../credentials.json');
|
||||||
|
} catch (err) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
url: process.env.SDC_URL || json.SDC_URL || json.url || '',
|
||||||
|
account: process.env.SDC_ACCOUNT || json.SDC_ACCOUNT || json.account || '',
|
||||||
|
user: process.env.SDC_USER || json.SDC_USER || json.user || '',
|
||||||
|
keyId: process.env.SDC_KEY_ID || json.SDC_KEY_ID || json.keyId || ''
|
||||||
|
};
|
8
cloudapi-graphql/src/endpoint.js
Normal file
8
cloudapi-graphql/src/endpoint.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
const graphqlHTTP = require('express-graphql');
|
||||||
|
const schema = require('./schema');
|
||||||
|
|
||||||
|
module.exports = graphqlHTTP(() => ({
|
||||||
|
schema: schema,
|
||||||
|
graphiql: true,
|
||||||
|
pretty: true
|
||||||
|
}));
|
14
cloudapi-graphql/src/index.js
Normal file
14
cloudapi-graphql/src/index.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
const express = require('express');
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
app.use('/graphql', require('./endpoint'));
|
||||||
|
|
||||||
|
const server = app.listen(4000, err => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Listening at http://0.0.0.0:${server.address().port}/graphql`);
|
||||||
|
});
|
10
cloudapi-graphql/src/schema/index.js
Normal file
10
cloudapi-graphql/src/schema/index.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
const graphql = require('graphql');
|
||||||
|
const mutation = require('./mutations');
|
||||||
|
const query = require('./queries');
|
||||||
|
|
||||||
|
const { GraphQLSchema } = graphql;
|
||||||
|
|
||||||
|
module.exports = new GraphQLSchema({
|
||||||
|
query,
|
||||||
|
mutation
|
||||||
|
});
|
56
cloudapi-graphql/src/schema/mutations/account.js
Normal file
56
cloudapi-graphql/src/schema/mutations/account.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
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
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
98
cloudapi-graphql/src/schema/mutations/firewall-rules.js
Normal file
98
cloudapi-graphql/src/schema/mutations/firewall-rules.js
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
54
cloudapi-graphql/src/schema/mutations/images.js
Normal file
54
cloudapi-graphql/src/schema/mutations/images.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
16
cloudapi-graphql/src/schema/mutations/index.js
Normal file
16
cloudapi-graphql/src/schema/mutations/index.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
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')
|
||||||
|
)
|
||||||
|
});
|
49
cloudapi-graphql/src/schema/mutations/keys.js
Normal file
49
cloudapi-graphql/src/schema/mutations/keys.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
320
cloudapi-graphql/src/schema/mutations/machines.js
Normal file
320
cloudapi-graphql/src/schema/mutations/machines.js
Normal file
@ -0,0 +1,320 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
71
cloudapi-graphql/src/schema/mutations/policies.js
Normal file
71
cloudapi-graphql/src/schema/mutations/policies.js
Normal file
@ -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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
103
cloudapi-graphql/src/schema/mutations/roles.js
Normal file
103
cloudapi-graphql/src/schema/mutations/roles.js
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
60
cloudapi-graphql/src/schema/mutations/snapshots.js
Normal file
60
cloudapi-graphql/src/schema/mutations/snapshots.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
144
cloudapi-graphql/src/schema/mutations/users.js
Normal file
144
cloudapi-graphql/src/schema/mutations/users.js
Normal file
@ -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);
|
||||||
|
// }
|
||||||
|
// };
|
13
cloudapi-graphql/src/schema/queries/account.js
Normal file
13
cloudapi-graphql/src/schema/queries/account.js
Normal file
@ -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
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
19
cloudapi-graphql/src/schema/queries/datacenters.js
Normal file
19
cloudapi-graphql/src/schema/queries/datacenters.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
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
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
12
cloudapi-graphql/src/schema/queries/fabrics.js
Normal file
12
cloudapi-graphql/src/schema/queries/fabrics.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
};
|
20
cloudapi-graphql/src/schema/queries/firewall-rules.js
Normal file
20
cloudapi-graphql/src/schema/queries/firewall-rules.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
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]);
|
||||||
|
}
|
||||||
|
};
|
52
cloudapi-graphql/src/schema/queries/images.js
Normal file
52
cloudapi-graphql/src/schema/queries/images.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
20
cloudapi-graphql/src/schema/queries/index.js
Normal file
20
cloudapi-graphql/src/schema/queries/index.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
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')
|
||||||
|
}
|
||||||
|
});
|
74
cloudapi-graphql/src/schema/queries/machines.js
Normal file
74
cloudapi-graphql/src/schema/queries/machines.js
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
19
cloudapi-graphql/src/schema/queries/networks.js
Normal file
19
cloudapi-graphql/src/schema/queries/networks.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
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]);
|
||||||
|
}
|
||||||
|
};
|
19
cloudapi-graphql/src/schema/queries/nics.js
Normal file
19
cloudapi-graphql/src/schema/queries/nics.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
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]);
|
||||||
|
}
|
||||||
|
};
|
56
cloudapi-graphql/src/schema/queries/packages.js
Normal file
56
cloudapi-graphql/src/schema/queries/packages.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
20
cloudapi-graphql/src/schema/queries/policies.js
Normal file
20
cloudapi-graphql/src/schema/queries/policies.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
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]);
|
||||||
|
}
|
||||||
|
};
|
20
cloudapi-graphql/src/schema/queries/roles.js
Normal file
20
cloudapi-graphql/src/schema/queries/roles.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
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]);
|
||||||
|
}
|
||||||
|
};
|
19
cloudapi-graphql/src/schema/queries/services.js
Normal file
19
cloudapi-graphql/src/schema/queries/services.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
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
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
26
cloudapi-graphql/src/schema/queries/users.js
Normal file
26
cloudapi-graphql/src/schema/queries/users.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
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
|
||||||
|
? list()
|
||||||
|
: get(args).then(user => [user]).then(user => {
|
||||||
|
return Object.assign(user, {
|
||||||
|
isUser: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
54
cloudapi-graphql/src/schema/types/audit.js
Normal file
54
cloudapi-graphql/src/schema/types/audit.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
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'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
14
cloudapi-graphql/src/schema/types/datacenter.js
Normal file
14
cloudapi-graphql/src/schema/types/datacenter.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
const { GraphQLString, GraphQLObjectType } = require('graphql');
|
||||||
|
|
||||||
|
module.exports = new GraphQLObjectType({
|
||||||
|
name: 'DatacenterType',
|
||||||
|
fields: {
|
||||||
|
name: {
|
||||||
|
type: GraphQLString,
|
||||||
|
description: 'location of the datacenter'
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: GraphQLString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
41
cloudapi-graphql/src/schema/types/dynamic-object.js
Normal file
41
cloudapi-graphql/src/schema/types/dynamic-object.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
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
|
||||||
|
});
|
19
cloudapi-graphql/src/schema/types/fabric.js
Normal file
19
cloudapi-graphql/src/schema/types/fabric.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
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'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
90
cloudapi-graphql/src/schema/types/firewall-rule.js
Normal file
90
cloudapi-graphql/src/schema/types/firewall-rule.js
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
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 !!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: {
|
||||||
|
// 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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
116
cloudapi-graphql/src/schema/types/image.js
Normal file
116
cloudapi-graphql/src/schema/types/image.js
Normal file
@ -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": "<string error code>", "message": "<string desc>"}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
16
cloudapi-graphql/src/schema/types/key.js
Normal file
16
cloudapi-graphql/src/schema/types/key.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
const { GraphQLString, GraphQLObjectType } = require('graphql');
|
||||||
|
|
||||||
|
module.exports = new GraphQLObjectType({
|
||||||
|
name: 'KeyType',
|
||||||
|
fields: {
|
||||||
|
name: {
|
||||||
|
type: GraphQLString
|
||||||
|
},
|
||||||
|
fingerprint: {
|
||||||
|
type: GraphQLString
|
||||||
|
},
|
||||||
|
key: {
|
||||||
|
type: GraphQLString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
108
cloudapi-graphql/src/schema/types/login.js
Normal file
108
cloudapi-graphql/src/schema/types/login.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
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'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
162
cloudapi-graphql/src/schema/types/machine.js
Normal file
162
cloudapi-graphql/src/schema/types/machine.js
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
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',
|
||||||
|
// 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'
|
||||||
|
},
|
||||||
|
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: {
|
||||||
|
// circular dependency
|
||||||
|
type: new GraphQLList(require('./firewall-rule')),
|
||||||
|
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
|
||||||
|
},
|
||||||
|
near: {
|
||||||
|
type: new GraphQLList(GraphQLID)
|
||||||
|
},
|
||||||
|
far: {
|
||||||
|
type: new GraphQLList(GraphQLID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user