feat(refactor): * (#173)
* 1. user docker remote api instead of docker golang sdk to do stuff 2. remote gRPC code 3. simplify command * fix(dep): remove private import * chore(*): clean up * chore(*): clean up * chore(*): commit source * fix(test): * * fix(env): enable docker remote api * fix(env): enable docker remote api * chore(*): clean up * fix(ci): use machine to do build * fix(ci): use machine to do build * fix(ci): use machine to do build * fix(ci): use machine to do build * fix(ci): use machine to do build * fix(ci): use machine to do build * fix(ci): use machine to do build * fix(ci): use machine to do build * fix(ci): use machine to do build * fix(ci): use machine to do build * fix(ci): use machine to do build * fix(ci): use machine to do build * fix(ci): use machine to do build * fix(ci): use machine to do build * feat(timeout): longger timeout * fix(test): * * fix(typo): flag is name * chore(*): debug * chore(*): debug * chore(*): decrease test time * fix(type): disable call test since not well design yet * fix(typo): remove, * feat(images): pull images * fix(Pkg): using Pkg first * fix(Pkg): using Pkg first * feat(julia): fix version * chore(*): clean up * fix(file): ensure file exist * feat(http): remote http test * fix(circleci): fix deploy job * chore(*): update info * feat(init): update script * doc(architect): update readme * refactor(api): refactor api code * refacot(api): seperate version * refactor(build): service build as single file * feat(concurrent): down concurrent * refactor(api): refactor API * fix(endpoint): valid endpoint * fix(path): path change * feat(release): fix release script * fix(path): correct path * feat(api): seperate service run * fix(release): install goreleaser * fix(cc): fix cc * fix(releaser): install releaser from script outside of circleci config * fix(env): init logic move env * fix(cli): fix init * fix(env): avoid conflict * chore(*): update output * test(stop): add test for stop * feat(label):apply default label * doc(readme): update workflow graph * fix(init): should just start when container exist * feat(state): update container by state
This commit is contained in:
@@ -1,15 +1,23 @@
|
||||
defaults: &defaults
|
||||
docker:
|
||||
- image: circleci/golang:1.10
|
||||
working_directory: /go/src/github.com/metrue/fx
|
||||
machine: true
|
||||
environment:
|
||||
IMPORT_PATH: "github.com/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME"
|
||||
working_directory: /home/circleci/.go_workspace/src/github.com/metrue/fx
|
||||
|
||||
attach_workspace: &attach_workspace
|
||||
attach_workspace:
|
||||
at: /go/src/github.com/metrue/fx
|
||||
|
||||
setup_remote_docker: &setup_remote_docker
|
||||
setup_remote_docker:
|
||||
docker_layer_caching: true
|
||||
install_dep: &install_packr
|
||||
run:
|
||||
name: Install packr
|
||||
command: |
|
||||
go get -u github.com/gobuffalo/packr/packr
|
||||
|
||||
install_dep: &install_dep
|
||||
run:
|
||||
name: Install dep
|
||||
command: |
|
||||
go get github.com/golang/dep
|
||||
cd /home/circleci/.go_workspace/src/github.com/golang/dep
|
||||
go install ./...
|
||||
|
||||
install_httpie: &install_httpie
|
||||
run:
|
||||
@@ -44,37 +52,28 @@ cli_test: &cli_test
|
||||
name: cli test
|
||||
command: make cli-test
|
||||
|
||||
http_test: &http_test
|
||||
run:
|
||||
name: http test
|
||||
command: make http-test
|
||||
|
||||
grpc_test: &grpc_test
|
||||
run:
|
||||
name: grpc test
|
||||
command: make grpc-test
|
||||
|
||||
version: 2
|
||||
jobs:
|
||||
test:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- checkout
|
||||
- *setup_remote_docker
|
||||
- *install_httpie
|
||||
- *install_jq
|
||||
- *install_packr
|
||||
- *install_dep
|
||||
- *install_dependencies
|
||||
- *build_binary
|
||||
- *unit_test
|
||||
- *cli_test
|
||||
- *http_test
|
||||
- *grpc_test
|
||||
deploy:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- checkout
|
||||
- *setup_remote_docker
|
||||
- *install_packr
|
||||
- *install_dep
|
||||
- *install_dependencies
|
||||
- *build_binary
|
||||
- run:
|
||||
name: Release
|
||||
command: make release
|
||||
@@ -82,7 +81,6 @@ jobs:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- checkout
|
||||
- *setup_remote_docker
|
||||
- *install_dependencies
|
||||
- run:
|
||||
name: Release
|
||||
@@ -107,4 +105,4 @@ workflows:
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- production
|
||||
- production
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,6 +1,3 @@
|
||||
[submodule "third_party/googleapis"]
|
||||
path = third_party/googleapis
|
||||
url = https://github.com/googleapis/googleapis
|
||||
[submodule "wiki"]
|
||||
path = wiki
|
||||
url = https://github.com/metrue/fx.wiki.git
|
||||
|
||||
307
Gopkg.lock
generated
Normal file
307
Gopkg.lock
generated
Normal file
@@ -0,0 +1,307 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
digest = "1:317998b1359366dda9f69cdbd108c39c7b3813a69002246fac4e3548646c1620"
|
||||
name = "github.com/apex/log"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "941dea75d3ebfbdd905a5d8b7b232965c5e5c684"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0deddd908b6b4b768cfc272c16ee61e7088a60f7fe2f06c547bd3d8e1f8b8e77"
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
pruneopts = ""
|
||||
revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:0e2a96f87af56565ab9c5ad79104b84a142192fbb0a969f79b1baab26c6c50a9"
|
||||
name = "github.com/docker/docker"
|
||||
packages = [
|
||||
"api/types",
|
||||
"api/types/blkiodev",
|
||||
"api/types/container",
|
||||
"api/types/filters",
|
||||
"api/types/mount",
|
||||
"api/types/network",
|
||||
"api/types/registry",
|
||||
"api/types/strslice",
|
||||
"api/types/swarm",
|
||||
"api/types/swarm/runtime",
|
||||
"api/types/versions",
|
||||
"errdefs",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "46036c230805d55eed797c45678e5e69ef9c1386"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ebe593d8b65a2947b78b6e164a2dac1a230b977a700b694da3a398b03b7afb04"
|
||||
name = "github.com/docker/go-connections"
|
||||
packages = ["nat"]
|
||||
pruneopts = ""
|
||||
revision = "7395e3f8aa162843a74ed6d48e79627d9792ac55"
|
||||
version = "v0.4.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:582d54fcb7233da8dde1dfd2210a5b9675d0685f84246a8d317b07d680c18b1b"
|
||||
name = "github.com/docker/go-units"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "47565b4f722fb6ceae66b95f853feed578a4a51c"
|
||||
version = "v0.3.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ba9a3ee3359edeeec2c6c1ddb6976db4b7ca6ad045e73b43471e32f01b5786e4"
|
||||
name = "github.com/dsnet/compress"
|
||||
packages = [
|
||||
".",
|
||||
"bzip2",
|
||||
"bzip2/internal/sais",
|
||||
"internal",
|
||||
"internal/errors",
|
||||
"internal/prefix",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "da652975a8eea9fa0735aba8056747a751db0bd3"
|
||||
version = "v0.0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:83e42cd058ee568f8897de6fb1ec66ba5751ab88436e8d9759824502a9fbed27"
|
||||
name = "github.com/gobuffalo/envy"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "fa0dfdc10b5366ce365b7d9d1755a03e4e797bc5"
|
||||
version = "v1.6.15"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:4dc3a807179b54e44ee710e30cae87ea4ba5f3ee6b96a1929ab8042ece05fe19"
|
||||
name = "github.com/gobuffalo/packd"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "d04dd98aca5b9aa7ca7c36ee639a21bcc69de32a"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:169b0f13452aa130cad334e8398aa8358759ab96e4d045bd8b6cba3e27ccda4d"
|
||||
name = "github.com/gobuffalo/packr"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "5aa3f2df6770adb7f8719a43ef25c2522af176ed"
|
||||
version = "v2.0.3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:03179c4a6eecf90cbfbb07648e6202dd999904531c9757ba034f009904de3a9c"
|
||||
name = "github.com/gobuffalo/syncx"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "33c29581e754bd354236e977dfe426e55331c45d"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:fd53b471edb4c28c7d297f617f4da0d33402755f58d6301e7ca1197ef0a90937"
|
||||
name = "github.com/gogo/protobuf"
|
||||
packages = ["proto"]
|
||||
pruneopts = ""
|
||||
revision = "ba06b47c162d49f2af050fb4c75bcbc86a159d5c"
|
||||
version = "v1.2.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:530233672f656641b365f8efb38ed9fba80e420baff2ce87633813ab3755ed6d"
|
||||
name = "github.com/golang/mock"
|
||||
packages = ["gomock"]
|
||||
pruneopts = ""
|
||||
revision = "51421b967af1f557f93a59e0057aaf15ca02e29c"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:6a6322a15aa8e99bd156fbba0aae4e5d67b4bb05251d860b348a45dfdcba9cce"
|
||||
name = "github.com/golang/snappy"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "2a8bb927dd31d8daada140a5d09578521ce5c36a"
|
||||
version = "v0.0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:cea4aa2038169ee558bf507d5ea02c94ca85bcca28a4c7bb99fd59b31e43a686"
|
||||
name = "github.com/google/go-querystring"
|
||||
packages = ["query"]
|
||||
pruneopts = ""
|
||||
revision = "44c6ddd0a2342c386950e880b658017258da92fc"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ad92aa49f34cbc3546063c7eb2cabb55ee2278b72842eda80e2a20a8a06a8d73"
|
||||
name = "github.com/google/uuid"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "0cd6bf5da1e1c83f8b45653022c74f71af0538a4"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0f31ddb2589297fc1d716f45b34e34bff34e968de1aa239543274c87522e86f4"
|
||||
name = "github.com/h2non/parth"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "b4df798d65426f8c8ab5ca5f9987aec5575d26c9"
|
||||
version = "v2.0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7df5a9695a743c3e1626b28bb8741602c8c15527e1efaeaec48ab2ff9a23f74c"
|
||||
name = "github.com/joho/godotenv"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "23d116af351c84513e1946b527c88823e476be13"
|
||||
version = "v1.3.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e26c759de83ce6fe27f99082458a7ad9fcc51a95215b4f5bbacd1345b61bc6ba"
|
||||
name = "github.com/mholt/archiver"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "d572b2e8b82726cee9476d1b9d63a7fe9b601ff1"
|
||||
version = "v3.1.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b93a939355dc613ca1c23bf39f6d4c207da431a31dd8af001cc334ad24cab9d3"
|
||||
name = "github.com/nwaples/rardecode"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "cc3e4b2381762c56dbcdf9f93be03349a1dc1c14"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:5d9b668b0b4581a978f07e7d2e3314af18eb27b3fb5d19b70185b7c575723d11"
|
||||
name = "github.com/opencontainers/go-digest"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf"
|
||||
version = "v1.0.0-rc1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f26c8670b11e29a49c8e45f7ec7f2d5bac62e8fd4e3c0ae1662baa4a697f984a"
|
||||
name = "github.com/opencontainers/image-spec"
|
||||
packages = [
|
||||
"specs-go",
|
||||
"specs-go/v1",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "d60099175f88c47cd379c4738d158884749ed235"
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7879c0c194c2befcb7e9aaf0163f21daf9f33e5c74372949bed08b6396736ed0"
|
||||
name = "github.com/phayes/freeport"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "b8543db493a5ed890c5499e935e2cad7504f3a04"
|
||||
version = "1.0.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:21b276e792044150a96175edd51d653649b9fd175c51a4613f2741b411c6d674"
|
||||
name = "github.com/pierrec/lz4"
|
||||
packages = [
|
||||
".",
|
||||
"internal/xxh32",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "062282ea0dcff40c9fb8525789eef9644b1fbd6e"
|
||||
version = "v2.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:1d7e1867c49a6dd9856598ef7c3123604ea3daabf5b83f303ff457bcbc410b1d"
|
||||
name = "github.com/pkg/errors"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4"
|
||||
version = "v0.8.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:256484dbbcd271f9ecebc6795b2df8cad4c458dd0f5fd82a8c2fa0c29f233411"
|
||||
name = "github.com/pmezard/go-difflib"
|
||||
packages = ["difflib"]
|
||||
pruneopts = ""
|
||||
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:d367886e3a8134415fad58fb2ac44e2f38aa88068adca7a02d59a555f87085c0"
|
||||
name = "github.com/rogpeppe/go-internal"
|
||||
packages = [
|
||||
"modfile",
|
||||
"module",
|
||||
"semver",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "1cf9852c553c5b7da2d5a4a091129a7822fed0c9"
|
||||
version = "v1.2.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:381bcbeb112a51493d9d998bbba207a529c73dbb49b3fd789e48c63fac1f192c"
|
||||
name = "github.com/stretchr/testify"
|
||||
packages = ["assert"]
|
||||
pruneopts = ""
|
||||
revision = "ffdc059bfe9ce6a4e144ba849dbedead332c6053"
|
||||
version = "v1.3.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:cc4c87dc4fa2a87abd2a0901cbd8c0ca10a4a83929d62947de0ad111ab830e01"
|
||||
name = "github.com/ulikunitz/xz"
|
||||
packages = [
|
||||
".",
|
||||
"internal/hash",
|
||||
"internal/xlog",
|
||||
"lzma",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "6f934d456d51e742b4eeab20d925a827ef22320a"
|
||||
version = "v0.5.6"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e85837cb04b78f61688c6eba93ea9d14f60d611e2aaf8319999b1a60d2dafbfa"
|
||||
name = "github.com/urfave/cli"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1"
|
||||
version = "v1.20.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:5d5ea0c53c32b0465b910eb1d98b045c2f14c416880c54dd5356a1c6b4569041"
|
||||
name = "github.com/xi2/xz"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "48954b6210f8d154cb5f8484d3a3e1f83489309e"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:5eeb4bfc6db411dbb34a6d9e5d49a9956b160d59fd004ee8f03fe53c9605c082"
|
||||
name = "gopkg.in/h2non/gock.v1"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "ba88c4862a27596539531ce469478a91bc5a0511"
|
||||
version = "v1.0.14"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
input-imports = [
|
||||
"github.com/apex/log",
|
||||
"github.com/docker/docker/api/types",
|
||||
"github.com/docker/docker/api/types/container",
|
||||
"github.com/docker/docker/api/types/network",
|
||||
"github.com/docker/go-connections/nat",
|
||||
"github.com/gobuffalo/packr",
|
||||
"github.com/golang/mock/gomock",
|
||||
"github.com/google/go-querystring/query",
|
||||
"github.com/google/uuid",
|
||||
"github.com/mholt/archiver",
|
||||
"github.com/phayes/freeport",
|
||||
"github.com/stretchr/testify/assert",
|
||||
"github.com/urfave/cli",
|
||||
"gopkg.in/h2non/gock.v1",
|
||||
]
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
49
Gopkg.toml
Normal file
49
Gopkg.toml
Normal file
@@ -0,0 +1,49 @@
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
#
|
||||
# [prune]
|
||||
# non-go = false
|
||||
# go-tests = true
|
||||
# unused-packages = true
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/docker/docker"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/golang/mock"
|
||||
version = "1.2.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/mholt/archiver"
|
||||
version = "3.1.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/google/uuid"
|
||||
version = "1.1.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/google/go-querystring"
|
||||
version = "1.0.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "gopkg.in/h2non/gock.v1"
|
||||
version = "1.0.14"
|
||||
20
Makefile
20
Makefile
@@ -2,22 +2,10 @@ OUTPUT_DIR=./build
|
||||
DIST_DIR=./dist
|
||||
|
||||
install-deps:
|
||||
git submodule update --init --recursive
|
||||
go get -u github.com/olekukonko/tablewriter
|
||||
go get -u github.com/jteeuwen/go-bindata/...
|
||||
go get -u golang.org/x/sys/...
|
||||
go get -u golang.org/x/text/...
|
||||
go get -u google.golang.org/grpc
|
||||
go get -u github.com/urfave/cli
|
||||
go get github.com/goreleaser/goreleaser
|
||||
# install protoc and plugins
|
||||
./scripts/install_protoc.sh third_party/protoc
|
||||
dep ensure
|
||||
|
||||
generate:
|
||||
# generate gRPC related code
|
||||
cd api && ./gen.sh
|
||||
# bundle assert into binary
|
||||
go-bindata -pkg common -o common/asset.go ./assets/dockerfiles/fx/...
|
||||
packr
|
||||
|
||||
build: generate
|
||||
go build -o ${OUTPUT_DIR}/fx fx.go
|
||||
@@ -33,6 +21,7 @@ clean:
|
||||
rm -rf ${DIST_DIR}
|
||||
|
||||
unit-test: generate
|
||||
./scripts/init.sh
|
||||
./scripts/coverage.sh
|
||||
|
||||
cli-test: generate
|
||||
@@ -41,9 +30,6 @@ cli-test: generate
|
||||
http-test: generate
|
||||
./scripts/http_test.sh
|
||||
|
||||
grpc-test: generate
|
||||
echo "TODO"
|
||||
|
||||
zip:
|
||||
zip -r images.zip images/
|
||||
.PHONY: test build start list clean generate
|
||||
|
||||
34
README.md
34
README.md
@@ -1,5 +1,39 @@
|
||||
fx
|
||||
------
|
||||
┌────────┐
|
||||
│fx init │ fx━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
└────────┘ ┃ ┌───────────────────────┐ ┃
|
||||
────────────────────────╋─────────▶│Environment initialize │ ┃
|
||||
┌──────┐ ┃ │* proxy docker sock │ ┃
|
||||
│fx up │ ┃ │* pull fx base docker │ ┃
|
||||
┌ ─ ─ ─ ┴──────┘─ ─ ┐ ┃ └───────────────────────┘ ┃
|
||||
Function Source ┃ ┌──────────────┐ ┌─────────────────────────────┐ ┃
|
||||
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘────╋──┬──────▶│ Pack │ │ │ ┃
|
||||
┃ │ └──────┬───────┘ │ │ ┃
|
||||
┌────────┐ ┃ │ ┌──────▼───────┐ │ │ ┃
|
||||
│fx call │ ┃ │ │Build Service │◀─────▶│ │ ┃
|
||||
└────────┘ ┃ │ └──────┬───────┘ │ │ ┃
|
||||
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ ┃ │ ┌──────▼───────┐ │ │ ┃
|
||||
Function Source ┃ │ │ Run Service │◀─────▶│ │ ┃
|
||||
│ (with params) │────╋──┤ └──────────────┘ │ │ ┃
|
||||
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┃ │ │ │ ┃
|
||||
┃ │ │ │ ┃
|
||||
┃ │ ┌──────────────┐ │ Docker API │ ┃
|
||||
┌────────┐ ┃ └──────▶│ Call Service │ │ │ ┃
|
||||
│fx down │ ┃ │ (http) │ │ │ ┃
|
||||
└────────┘ ┃ └──────────────┘ │ │ ┃
|
||||
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┃ ┌──────────────┐ │ │ ┃
|
||||
Service Name │────╋─────────▶│ Stop Service │◀─────▶│ │ ┃
|
||||
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┃ └──────────────┘ │ │ ┃
|
||||
┌────────┐ ┃ │ │ ┃
|
||||
│fx list │ ┃ │ │ ┃
|
||||
└────────┘ ┃ │ │ ┃
|
||||
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┃ ┌──────────────┐ │ │ ┃
|
||||
Service Name │────╋─────────▶│List Services │◀─────▶│ │ ┃
|
||||
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┃ └──────────────┘ └─────────────────────────────┘ ┃
|
||||
┃ ┃
|
||||
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
|
||||
|
||||
Poor man's function as a service.
|
||||
<br/>
|
||||
|
||||
196
api/api.go
Normal file
196
api/api.go
Normal file
@@ -0,0 +1,196 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
dockerTypes "github.com/docker/docker/api/types"
|
||||
"github.com/gobuffalo/packr"
|
||||
"github.com/google/go-querystring/query"
|
||||
"github.com/metrue/fx/types"
|
||||
)
|
||||
|
||||
const serviceNamePrefix = "fx_"
|
||||
|
||||
// API interact with dockerd http api
|
||||
type API struct {
|
||||
endpoint string
|
||||
version string
|
||||
box packr.Box
|
||||
}
|
||||
|
||||
// NewWithDockerRemoteAPI create a api with docker remote api
|
||||
func NewWithDockerRemoteAPI(url string, version string) *API {
|
||||
box := packr.NewBox("./images")
|
||||
endpoint := fmt.Sprintf("%s/v%s", url, version)
|
||||
return &API{
|
||||
endpoint: endpoint,
|
||||
box: box,
|
||||
}
|
||||
}
|
||||
|
||||
func (api *API) get(path string, qs string, v interface{}) error {
|
||||
url := fmt.Sprintf("%s%s", api.endpoint, path)
|
||||
if !strings.HasPrefix(url, "http") {
|
||||
url = "http://" + url
|
||||
}
|
||||
if qs != "" {
|
||||
url += "?" + qs
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client := &http.Client{Timeout: 20 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return fmt.Errorf("request %s failed: %d - %s", url, resp.StatusCode, resp.Status)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(body, &v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (api *API) post(path string, body []byte, expectStatus int, v interface{}) error {
|
||||
url := fmt.Sprintf("%s%s", api.endpoint, path)
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Accept", "application/json")
|
||||
|
||||
client := &http.Client{Timeout: 20 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != expectStatus {
|
||||
return fmt.Errorf("request %s (%s) failed: %d - %s", url, string(body), resp.StatusCode, resp.Status)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(b, &v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// List list service
|
||||
func (api *API) list(name string) ([]types.Service, error) {
|
||||
if name != "" {
|
||||
info, err := api.inspect(name)
|
||||
if err != nil {
|
||||
return []types.Service{}, err
|
||||
}
|
||||
|
||||
port, err := strconv.Atoi(info.HostConfig.PortBindings["3000/tcp"][0].HostPort)
|
||||
if err != nil {
|
||||
return []types.Service{}, err
|
||||
}
|
||||
return []types.Service{
|
||||
types.Service{
|
||||
Name: name,
|
||||
Image: info.Image,
|
||||
Status: types.ServiceStatusRunning,
|
||||
Instances: []types.Instance{
|
||||
types.Instance{
|
||||
ID: info.ID,
|
||||
Host: info.HostConfig.PortBindings["3000/tcp"][0].HostIP,
|
||||
Port: port,
|
||||
State: info.State.Status,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
type filterItem struct {
|
||||
Status []string `json:"url,omitempty"`
|
||||
Label []string `json:"label,omitempty"`
|
||||
Name []string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
type Filters struct {
|
||||
Items string `url:"filters"`
|
||||
}
|
||||
|
||||
filter := filterItem{
|
||||
// Status: []string{"running"},
|
||||
Label: []string{"belong-to=fx"},
|
||||
}
|
||||
|
||||
q, err := json.Marshal(filter)
|
||||
if err != nil {
|
||||
return []types.Service{}, err
|
||||
}
|
||||
|
||||
filters := Filters{Items: string(q)}
|
||||
qs, err := query.Values(filters)
|
||||
if err != nil {
|
||||
return []types.Service{}, err
|
||||
}
|
||||
|
||||
var containers []dockerTypes.Container
|
||||
if err := api.get("/containers/json", qs.Encode(), &containers); err != nil {
|
||||
return []types.Service{}, err
|
||||
}
|
||||
|
||||
svs := make(map[string]types.Service)
|
||||
for _, container := range containers {
|
||||
// container name have extra forward slash
|
||||
// https://github.com/moby/moby/issues/6705
|
||||
if strings.HasPrefix(container.Names[0], fmt.Sprintf("/%s", name)) {
|
||||
instance := types.Instance{
|
||||
ID: container.ID,
|
||||
Host: container.Ports[0].IP,
|
||||
Port: int(container.Ports[0].PublicPort),
|
||||
State: container.State,
|
||||
}
|
||||
if svs[container.Image].Instances != nil {
|
||||
instances := append(svs[container.Image].Instances, instance)
|
||||
svs[container.Image] = types.Service{Instances: instances}
|
||||
} else {
|
||||
svs[container.Image] = types.Service{
|
||||
Name: name,
|
||||
Image: container.Image,
|
||||
Status: types.ServiceStatusRunning,
|
||||
Instances: []types.Instance{instance},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
services := []types.Service{}
|
||||
for _, s := range svs {
|
||||
services = append(services, s)
|
||||
}
|
||||
|
||||
return services, nil
|
||||
}
|
||||
91
api/api_test.go
Normal file
91
api/api_test.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/metrue/fx/types"
|
||||
)
|
||||
|
||||
func TestDockerHTTP(t *testing.T) {
|
||||
dockerRemoteAPI := "http://127.0.0.1:1234"
|
||||
version, err := Version(dockerRemoteAPI)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
api := NewWithDockerRemoteAPI(dockerRemoteAPI, version)
|
||||
|
||||
serviceName := "a-test-service"
|
||||
project := types.Project{
|
||||
Name: serviceName,
|
||||
Language: "node",
|
||||
Files: []types.ProjectSourceFile{
|
||||
types.ProjectSourceFile{
|
||||
Path: "Dockerfile",
|
||||
Body: `
|
||||
FROM metrue/fx-node-base
|
||||
|
||||
COPY . .
|
||||
EXPOSE 3000
|
||||
CMD ["node", "app.js"]`,
|
||||
IsHandler: false,
|
||||
},
|
||||
types.ProjectSourceFile{
|
||||
Path: "app.js",
|
||||
Body: `
|
||||
const Koa = require('koa');
|
||||
const bodyParser = require('koa-bodyparser');
|
||||
const func = require('./fx');
|
||||
|
||||
const app = new Koa();
|
||||
app.use(bodyParser());
|
||||
app.use(ctx => {
|
||||
const msg = func(ctx.request.body);
|
||||
ctx.body = msg;
|
||||
});
|
||||
|
||||
app.listen(3000);`,
|
||||
IsHandler: false,
|
||||
},
|
||||
types.ProjectSourceFile{
|
||||
Path: "fx.js",
|
||||
Body: `
|
||||
module.exports = (input) => {
|
||||
return input.a + input.b
|
||||
}
|
||||
`,
|
||||
IsHandler: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
service, err := api.Build(project)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if service.Status != types.ServiceStatusInit {
|
||||
t.Fatalf("should get %d but got %d", types.ServiceStatusInit, service.Status)
|
||||
}
|
||||
if service.Name != serviceName {
|
||||
t.Fatalf("should get %s but got %s", serviceName, service.Name)
|
||||
}
|
||||
|
||||
if err := api.Run(&service); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
services, err := api.list(serviceName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(services) != 1 {
|
||||
t.Fatal("service number should be 1")
|
||||
}
|
||||
|
||||
if err := api.Stop(serviceName); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
5
api/asserts/dockerfiles/base/d/Dockerfile
Normal file
5
api/asserts/dockerfiles/base/d/Dockerfile
Normal file
@@ -0,0 +1,5 @@
|
||||
FROM ubuntu:16.04
|
||||
|
||||
RUN apt-get update && apt-get install -y build-essential curl libcurl3 \
|
||||
&& curl -OL http://downloads.dlang.org/releases/2.x/2.077.1/dmd_2.077.1-0_amd64.deb \
|
||||
&& apt install ./dmd_2.077.1-0_amd64.deb
|
||||
12
api/asserts/dockerfiles/base/java/Dockerfile
Normal file
12
api/asserts/dockerfiles/base/java/Dockerfile
Normal file
@@ -0,0 +1,12 @@
|
||||
FROM java:8
|
||||
|
||||
# Install maven
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y maven
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
# Prepare by downloading dependencies
|
||||
ADD pom.xml /code/pom.xml
|
||||
RUN ["mvn", "dependency:resolve"]
|
||||
RUN ["mvn", "verify"]
|
||||
3
api/asserts/dockerfiles/base/java/Makefile
Normal file
3
api/asserts/dockerfiles/base/java/Makefile
Normal file
@@ -0,0 +1,3 @@
|
||||
build:
|
||||
docker build -t metrue/fx-java-base:latest .
|
||||
docker push metrue/fx-java-base
|
||||
3
api/asserts/dockerfiles/base/julia/Dockerfile
Normal file
3
api/asserts/dockerfiles/base/julia/Dockerfile
Normal file
@@ -0,0 +1,3 @@
|
||||
FROM julia:latest
|
||||
|
||||
RUN apt-get update && apt-get install -y gcc apt-utils unzip make libhttp-parser-dev
|
||||
3
api/asserts/dockerfiles/base/julia/Makefile
Normal file
3
api/asserts/dockerfiles/base/julia/Makefile
Normal file
@@ -0,0 +1,3 @@
|
||||
build:
|
||||
docker build -t metrue/fx-julia-base:latest .
|
||||
docker push metrue/fx-julia-base
|
||||
4
api/asserts/dockerfiles/base/node/Dockerfile
Normal file
4
api/asserts/dockerfiles/base/node/Dockerfile
Normal file
@@ -0,0 +1,4 @@
|
||||
FROM node:latest
|
||||
|
||||
COPY . .
|
||||
RUN npm install
|
||||
21
api/asserts/dockerfiles/base/node/package.json
Normal file
21
api/asserts/dockerfiles/base/node/package.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "aok",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"get-port": "^3.2.0",
|
||||
"is-generator-function": "^1.0.6",
|
||||
"koa": "^2.3.0",
|
||||
"koa-bodyparser": "^4.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"get-port-cli": "^1.1.0"
|
||||
}
|
||||
}
|
||||
5
api/asserts/dockerfiles/base/python/Dockerfile
Normal file
5
api/asserts/dockerfiles/base/python/Dockerfile
Normal file
@@ -0,0 +1,5 @@
|
||||
FROM python:3
|
||||
|
||||
RUN pip install flask
|
||||
ENV FLASK_APP=app.py
|
||||
|
||||
970
api/asserts/dockerfiles/base/rust/Cargo.lock
generated
Normal file
970
api/asserts/dockerfiles/base/rust/Cargo.lock
generated
Normal file
@@ -0,0 +1,970 @@
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cloudabi"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "devise"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"devise_codegen 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"devise_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "devise_codegen"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"devise_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "devise_core"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.1.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.10.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify-sys"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iovec"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "isatty"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "language-tags"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.6.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-extras"
|
||||
version = "2.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "net2"
|
||||
version = "0.2.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "4.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "owning_ref"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pear"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"pear_codegen 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pear_codegen"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"yansi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.13.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rocket"
|
||||
version = "0.4.0-rc.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"isatty 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pear 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rocket_codegen 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rocket_http 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"state 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rocket_codegen"
|
||||
version = "0.4.0-rc.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"devise 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rocket_http 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rocket_contrib"
|
||||
version = "0.4.0-rc.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"notify 4.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rocket 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rocket_http"
|
||||
version = "0.4.0-rc.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pear 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"state 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rocket 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rocket_contrib 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "safemem"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "state"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-executor"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-io"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-reactor"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-utils 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "traitobject"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "typeable"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unreachable"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "1.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ws2_32-sys"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "621fc7ecb8008f86d7fb9b95356cd692ce9514b80a86d85b397f32a22da7b9e2"
|
||||
"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
|
||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
|
||||
"checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa"
|
||||
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
|
||||
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
||||
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||
"checksum cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1465f8134efa296b4c19db34d909637cb2bf0f7aaf21299e23e18fa29ac557cf"
|
||||
"checksum crossbeam-utils 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c55913cc2799171a550e307918c0a360e8c16004820291bf3b638969b4a01816"
|
||||
"checksum devise 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e04ba2d03c5fa0d954c061fc8c9c288badadffc272ebb87679a89846de3ed3"
|
||||
"checksum devise_codegen 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "066ceb7928ca93a9bedc6d0e612a8a0424048b0ab1f75971b203d01420c055d7"
|
||||
"checksum devise_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf41c59b22b5e3ec0ea55c7847e5f358d340f3a8d6d53a5cf4f1564967f96487"
|
||||
"checksum filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a2df5c1a8c4be27e7707789dc42ae65976e60b394afd293d1419ab915833e646"
|
||||
"checksum fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c4bbbf71584aeed076100b5665ac14e3d85eeb31fdbb45fbd41ef9a682b5ec05"
|
||||
"checksum fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a772d36c338d07a032d5375a36f15f9a7043bf0cb8ce7cee658e037c6032874"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b"
|
||||
"checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83"
|
||||
"checksum hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)" = "df0caae6b71d266b91b4a83111a61d2b94ed2e2bea024c532b933dcff867e58c"
|
||||
"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
|
||||
"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d"
|
||||
"checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718"
|
||||
"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0"
|
||||
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
|
||||
"checksum isatty 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e31a8281fc93ec9693494da65fbf28c0c2aa60a2eaec25dc58e2f31952e95edc"
|
||||
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
|
||||
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
|
||||
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
|
||||
"checksum libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)" = "10923947f84a519a45c8fefb7dd1b3e8c08747993381adee176d7a82b4195311"
|
||||
"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
|
||||
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
|
||||
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
|
||||
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||
"checksum memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0a3eb002f0535929f1199681417029ebea04aadc0c7a4224b46be99c7f5d6a16"
|
||||
"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0"
|
||||
"checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432"
|
||||
"checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40"
|
||||
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
|
||||
"checksum notify 4.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "873ecfd8c174964ae30f401329d140142312c8e5590719cf1199d5f1717d8078"
|
||||
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
|
||||
"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
|
||||
"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5"
|
||||
"checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c"
|
||||
"checksum pear 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c26d2b92e47063ffce70d3e3b1bd097af121a9e0db07ca38a6cc1cf0cc85ff25"
|
||||
"checksum pear_codegen 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "336db4a192cc7f54efeb0c4e11a9245394824cc3bcbd37ba3ff51240c35d7a6e"
|
||||
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
|
||||
"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09"
|
||||
"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
|
||||
"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c"
|
||||
"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372"
|
||||
"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db"
|
||||
"checksum redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "679da7508e9a6390aeaf7fbd02a800fdc64b73fe2204dd2c8ae66d22d9d5ad5d"
|
||||
"checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a"
|
||||
"checksum rocket 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eaa997ea8de9b14112aa38b2b6a0ecf3e651ff2c08d2fdf384fa765b5f9c2c98"
|
||||
"checksum rocket_codegen 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fc68f90452ac88c6c1e02a922a0a23ef0ade08f9af899056d0c919b25fa7768c"
|
||||
"checksum rocket_contrib 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2cc6a37cb7a6256efe6648f2d0ab9978c49ab883909ea4fabefb81d7c685d841"
|
||||
"checksum rocket_http 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c7d555ce896830602aedf4bce2eec8d64713d45a2492c5a3625c3faa5f719b0f"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
|
||||
"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9"
|
||||
"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267"
|
||||
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
|
||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "15c141fc7027dd265a47c090bf864cf62b42c4d228bbcf4e51a0c9e2b0d3f7ef"
|
||||
"checksum serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "225de307c6302bec3898c51ca302fc94a7a1697ef0845fcee6448f33c032249c"
|
||||
"checksum serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "c37ccd6be3ed1fdf419ee848f7c758eb31b054d7cd3ae3600e3bae0adf569811"
|
||||
"checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d"
|
||||
"checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db"
|
||||
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
|
||||
"checksum state 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7345c971d1ef21ffdbd103a75990a15eb03604fc8b8852ca8cb418ee1a099028"
|
||||
"checksum syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)" = "ae8b29eb5210bc5cf63ed6149cbf9adfc82ac0be023d8735c176ee74a2db4da7"
|
||||
"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
|
||||
"checksum tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c117b6cf86bb730aab4834f10df96e4dd586eff2c3c27d3781348da49e255bde"
|
||||
"checksum tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "7392fe0a70d5ce0c882c4778116c519bd5dbaa8a7c3ae3d04578b3afafdcda21"
|
||||
"checksum tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "502b625acb4ee13cbb3b90b8ca80e0addd263ddacf6931666ef751e610b07fb5"
|
||||
"checksum toml 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "19782e145d5abefb03758958f06ea35f7b1d8421b534140e0238fd3d0bfd66e3"
|
||||
"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079"
|
||||
"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887"
|
||||
"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33"
|
||||
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
||||
"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||
"checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f"
|
||||
"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
|
||||
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||
"checksum yansi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d60c3b48c9cdec42fb06b3b84b5b087405e1fa1c644a1af3930e4dfafe93de48"
|
||||
"checksum yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71"
|
||||
13
api/asserts/dockerfiles/base/rust/Cargo.toml
Normal file
13
api/asserts/dockerfiles/base/rust/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "rust"
|
||||
version = "0.1.0"
|
||||
authors = ["FrontMage <xbgxwh@outlook.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
rocket = "0.4.0-rc.2"
|
||||
rocket_contrib = "0.4.0-rc.2"
|
||||
serde_json = "1.0"
|
||||
serde_derive = "1.0.70"
|
||||
serde = "1.0.70"
|
||||
|
||||
7
api/asserts/dockerfiles/base/rust/Dockerfile
Normal file
7
api/asserts/dockerfiles/base/rust/Dockerfile
Normal file
@@ -0,0 +1,7 @@
|
||||
FROM liuchong/rustup
|
||||
|
||||
WORKDIR /usr/src/myapp
|
||||
COPY . .
|
||||
RUN cp ./config ~/.cargo/ && rustup default nightly && cargo build
|
||||
EXPOSE 3000
|
||||
CMD ["cargo", "run"]
|
||||
5
api/asserts/dockerfiles/base/rust/Rocket.toml
Normal file
5
api/asserts/dockerfiles/base/rust/Rocket.toml
Normal file
@@ -0,0 +1,5 @@
|
||||
[development]
|
||||
address = "0.0.0.0"
|
||||
port = 3000
|
||||
log = "normal"
|
||||
|
||||
6
api/asserts/dockerfiles/base/rust/config
Normal file
6
api/asserts/dockerfiles/base/rust/config
Normal file
@@ -0,0 +1,6 @@
|
||||
[source.crates-io]
|
||||
registry = "https://github.com/rust-lang/crates.io-index"
|
||||
replace-with = 'ustc'
|
||||
[source.ustc]
|
||||
registry = "git://mirrors.ustc.edu.cn/crates.io-index"
|
||||
|
||||
18
api/asserts/dockerfiles/base/rust/fx.rs
Normal file
18
api/asserts/dockerfiles/base/rust/fx.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
pub mod fns {
|
||||
#[derive(Serialize)]
|
||||
pub struct Response {
|
||||
pub result: i32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Request {
|
||||
pub a: i32,
|
||||
pub b: i32,
|
||||
}
|
||||
|
||||
pub fn func(req: Request) -> Response {
|
||||
Response {
|
||||
result: req.a + req.b,
|
||||
}
|
||||
}
|
||||
}
|
||||
18
api/asserts/dockerfiles/base/rust/src/fns/mod.rs
Normal file
18
api/asserts/dockerfiles/base/rust/src/fns/mod.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
pub mod fns {
|
||||
#[derive(Serialize)]
|
||||
pub struct Response {
|
||||
pub result: i32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Request {
|
||||
pub a: i32,
|
||||
pub b: i32,
|
||||
}
|
||||
|
||||
pub fn func(req: Request) -> Response {
|
||||
Response {
|
||||
result: req.a + req.b,
|
||||
}
|
||||
}
|
||||
}
|
||||
22
api/asserts/dockerfiles/base/rust/src/main.rs
Normal file
22
api/asserts/dockerfiles/base/rust/src/main.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
#![feature(proc_macro_hygiene, decl_macro, plugin)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rocket;
|
||||
extern crate rocket_contrib;
|
||||
extern crate serde;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate serde_json;
|
||||
|
||||
mod fns;
|
||||
|
||||
use rocket_contrib::json::Json;
|
||||
|
||||
#[post("/", format = "application/json", data = "<req>")]
|
||||
fn index(req: Json<fns::fns::Request>) -> Json<fns::fns::Response> {
|
||||
Json(fns::fns::func(req.0))
|
||||
}
|
||||
|
||||
fn main() {
|
||||
rocket::ignite().mount("/", routes![index]).launch();
|
||||
}
|
||||
83
api/call.go
Normal file
83
api/call.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/apex/log"
|
||||
"github.com/google/uuid"
|
||||
"github.com/metrue/fx/types"
|
||||
"github.com/metrue/fx/utils"
|
||||
)
|
||||
|
||||
// Call function directly with given params
|
||||
func (api *API) Call(file string, param string) error {
|
||||
src, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
log.Fatalf("Read Source: %v", err)
|
||||
return err
|
||||
}
|
||||
log.Info("Read Source: \u2713")
|
||||
|
||||
lang := utils.GetLangFromFileName(file)
|
||||
fn := types.ServiceFunctionSource{
|
||||
Language: lang,
|
||||
Source: string(src),
|
||||
}
|
||||
|
||||
project, err := api.Pack(uuid.New().String(), fn)
|
||||
if err != nil {
|
||||
log.Fatalf("Pack Service: %v", err)
|
||||
return err
|
||||
}
|
||||
log.Info("Pack Service: \u2713")
|
||||
|
||||
service, err := api.Build(project)
|
||||
if err != nil {
|
||||
log.Fatalf("Build Service: %v", err)
|
||||
return err
|
||||
}
|
||||
log.Info("Build Service: \u2713")
|
||||
|
||||
if err := api.Run(&service); err != nil {
|
||||
log.Fatalf("Run Service: %v", err)
|
||||
return err
|
||||
}
|
||||
log.Info("Run Service: \u2713")
|
||||
|
||||
params := utils.PairsToParams(strings.Fields(param))
|
||||
body, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait 2 seconds for service startup
|
||||
time.Sleep(time.Second * 2)
|
||||
|
||||
url := fmt.Sprintf("http://%s:%d", service.Instances[0].Host, service.Instances[0].Port)
|
||||
r, err := http.NewRequest("POST", url, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Header.Set("Content-Type", "application/json")
|
||||
client := &http.Client{Timeout: 20 * time.Second}
|
||||
resp, err := client.Do(r)
|
||||
if err != nil {
|
||||
log.Fatalf("Call Service: %v", err)
|
||||
return err
|
||||
}
|
||||
buf, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Fatalf("Call Service: %v", err)
|
||||
return err
|
||||
}
|
||||
log.Info("Call Service: \u2713")
|
||||
utils.OutputJSON(string(buf))
|
||||
|
||||
return nil
|
||||
}
|
||||
26
api/container_inspect.go
Normal file
26
api/container_inspect.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
dockerTypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
)
|
||||
|
||||
type containerInfo struct {
|
||||
ID string `json:"Id"`
|
||||
State dockerTypes.ContainerState `json:"State"`
|
||||
Image string `json:"Image"`
|
||||
HostConfig container.HostConfig `json:"HostConfig"`
|
||||
}
|
||||
|
||||
func (api *API) inspect(identify string) (containerInfo, error) {
|
||||
var info containerInfo
|
||||
|
||||
path := fmt.Sprintf("/containers/%s/json", identify)
|
||||
if err := api.get(path, "", &info); err != nil {
|
||||
return info, err
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
1
api/container_inspect_test.go
Normal file
1
api/container_inspect_test.go
Normal file
@@ -0,0 +1 @@
|
||||
package api
|
||||
48
api/docker_api_version.go
Normal file
48
api/docker_api_version.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
dockerTypes "github.com/docker/docker/api/types"
|
||||
)
|
||||
|
||||
// Version get version of dockerd server
|
||||
func Version(endpoint string) (string, error) {
|
||||
path := "/version"
|
||||
url := fmt.Sprintf("%s%s", endpoint, path)
|
||||
if !strings.HasPrefix(url, "http") {
|
||||
url = "http://" + url
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
client := &http.Client{Timeout: 20 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return "", fmt.Errorf("request %s failed: %d - %s", url, resp.StatusCode, resp.Status)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var res dockerTypes.Version
|
||||
err = json.Unmarshal(body, &res)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return res.APIVersion, nil
|
||||
}
|
||||
26
api/docker_api_version_test.go
Normal file
26
api/docker_api_version_test.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
gock "gopkg.in/h2non/gock.v1"
|
||||
)
|
||||
|
||||
func TestDockerAPIVersion(t *testing.T) {
|
||||
defer gock.Off()
|
||||
|
||||
dockerRemoteAPI := "http://127.0.0.1:1234"
|
||||
gock.New(dockerRemoteAPI).
|
||||
Get("/version").
|
||||
Reply(200).
|
||||
JSON(map[string]string{
|
||||
"ApiVersion": "0.2.1",
|
||||
})
|
||||
v, err := Version(dockerRemoteAPI)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if v != "0.2.1" {
|
||||
t.Fatalf("should get %s but got %s", "0.2.1", v)
|
||||
}
|
||||
}
|
||||
28
api/down.go
Normal file
28
api/down.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/apex/log"
|
||||
)
|
||||
|
||||
// Down destroy services
|
||||
func (api *API) Down(names []string) error {
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for _, name := range names {
|
||||
wg.Add(1)
|
||||
go func(s string) {
|
||||
if err := api.Stop(s); err != nil {
|
||||
log.Fatalf("Down Service %s: %v", s, err)
|
||||
} else {
|
||||
log.Infof("Down Service %s: \u2713", s)
|
||||
}
|
||||
defer wg.Done()
|
||||
}(name)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return nil
|
||||
}
|
||||
7
api/down_test.go
Normal file
7
api/down_test.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package api
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestDown(t *testing.T) {
|
||||
|
||||
}
|
||||
106
api/fx.proto
106
api/fx.proto
@@ -1,106 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package api;
|
||||
|
||||
import "googleapis/google/api/annotations.proto";
|
||||
|
||||
message FunctionMeta {
|
||||
string Lang = 1;
|
||||
string Content = 2;
|
||||
}
|
||||
|
||||
message CallRequest {
|
||||
string Lang = 1;
|
||||
string Content = 2;
|
||||
string Params = 3;
|
||||
}
|
||||
|
||||
message CallResponse {
|
||||
string Error = 1;
|
||||
string Data = 2;
|
||||
}
|
||||
|
||||
message UpRequest {
|
||||
repeated FunctionMeta Functions = 1;
|
||||
}
|
||||
|
||||
message DownRequest {
|
||||
repeated string ID = 1;
|
||||
}
|
||||
|
||||
message ListRequest {
|
||||
repeated string ID = 1;
|
||||
}
|
||||
|
||||
message UpMsgMeta {
|
||||
string FunctionID = 1;
|
||||
string LocalAddress = 2;
|
||||
string RemoteAddress = 3;
|
||||
string Error = 4;
|
||||
}
|
||||
|
||||
message UpResponse {
|
||||
repeated UpMsgMeta Instances = 1;
|
||||
}
|
||||
|
||||
message DownMsgMeta {
|
||||
string ContainerId = 1;
|
||||
string ContainerStatus = 2;
|
||||
string ImageStatus = 3;
|
||||
string Error = 4;
|
||||
}
|
||||
|
||||
message DownResponse {
|
||||
repeated DownMsgMeta Instances = 1;
|
||||
}
|
||||
|
||||
message ListItem {
|
||||
string FunctionID = 1;
|
||||
string State = 2;
|
||||
string ServiceURL = 3;
|
||||
}
|
||||
|
||||
message ListResponse {
|
||||
repeated ListItem Instances = 1;
|
||||
}
|
||||
|
||||
|
||||
message PingRequest {}
|
||||
|
||||
message PingResponse {
|
||||
string Status = 1;
|
||||
}
|
||||
|
||||
service FxService {
|
||||
rpc Ping(PingRequest) returns (PingResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/ping"
|
||||
};
|
||||
}
|
||||
|
||||
rpc Up (UpRequest) returns (UpResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/v1/up"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
rpc Down (DownRequest) returns (DownResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/v1/down"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
rpc List (ListRequest) returns (ListResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/v1/list"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
|
||||
rpc Call (CallRequest) returns (CallResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/v1/call"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
}
|
||||
44
api/gen.sh
44
api/gen.sh
@@ -1,44 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
HERE=$( cd "$( dirname "${0}" )" && pwd )
|
||||
ROOT=$( cd ${HERE}/.. && pwd )
|
||||
PROTOSRC="./fx.proto"
|
||||
|
||||
protoc_bin="${ROOT}/third_party/protoc/bin/protoc"
|
||||
protoc_include="${ROOT}/third_party/protoc/include"
|
||||
|
||||
VENDOR="${ROOT}/vendor"
|
||||
|
||||
# generate the gRPC code
|
||||
${protoc_bin} -I/usr/local/include \
|
||||
-I${protoc_include} \
|
||||
-I. \
|
||||
--go_out=plugins=grpc:. \
|
||||
$PROTOSRC
|
||||
|
||||
# generate the JSON interface code
|
||||
${protoc_bin} -I/usr/local/include \
|
||||
-I${protoc_include} \
|
||||
-I. \
|
||||
-I$GOPATH/src \
|
||||
-I${VENDOR}/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
|
||||
--go_out=plugins=grpc:. \
|
||||
$PROTOSRC
|
||||
|
||||
# generate the reverse proxy
|
||||
${protoc_bin} -I/usr/local/include \
|
||||
-I${protoc_include} \
|
||||
-I. \
|
||||
-I$GOPATH/src \
|
||||
-I${VENDOR}/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
|
||||
--grpc-gateway_out=logtostderr=true:. \
|
||||
$PROTOSRC
|
||||
|
||||
# generate the swagger definitions
|
||||
${protoc_bin} -I/usr/local/include \
|
||||
-I. \
|
||||
-I${protoc_include} \
|
||||
-I$GOPATH/src \
|
||||
-I${VENDOR}/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
|
||||
--swagger_out=logtostderr=true:../swagger \
|
||||
$PROTOSRC
|
||||
@@ -1 +0,0 @@
|
||||
../third_party/googleapis/google
|
||||
@@ -1 +0,0 @@
|
||||
../third_party/googleapis
|
||||
30
api/image_pull.go
Normal file
30
api/image_pull.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (api *API) pull(name string) error {
|
||||
path := fmt.Sprintf("/%s/images/create?fromImage=%s&tag=latest", api.version, name)
|
||||
url := fmt.Sprintf("http://%s%s", api.endpoint, path)
|
||||
req, err := http.NewRequest("POST", url, nil)
|
||||
client := &http.Client{Timeout: 120 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
scanner := bufio.NewScanner(resp.Body)
|
||||
|
||||
for scanner.Scan() {
|
||||
fmt.Printf("%s\n", scanner.Text())
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
6
api/image_pull_test.go
Normal file
6
api/image_pull_test.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package api
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestPull(t *testing.T) {
|
||||
}
|
||||
51
api/images/java/pom.xml
Normal file
51
api/images/java/pom.xml
Normal file
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>fx-app-java</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>0.1.0</version>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<transformers>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>fx.app</mainClass>
|
||||
</transformer>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.javalin</groupId>
|
||||
<artifactId>javalin</artifactId>
|
||||
<version>1.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.json</groupId>
|
||||
<artifactId>json</artifactId>
|
||||
<version>20171018</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM julia:latest
|
||||
FROM julia:0.7
|
||||
|
||||
COPY . /app
|
||||
|
||||
@@ -6,4 +6,4 @@ RUN apt-get update && apt-get install -y gcc apt-utils unzip make libhttp-parser
|
||||
RUN julia /app/deps.jl
|
||||
|
||||
CMD julia /app/app.jl
|
||||
EXPOSE 3000
|
||||
EXPOSE 3000
|
||||
@@ -5,8 +5,8 @@ const func = require('./fx');
|
||||
const app = new Koa();
|
||||
app.use(bodyParser());
|
||||
app.use(ctx => {
|
||||
const msg = func(ctx.request.body);
|
||||
ctx.body = msg;
|
||||
const msg = func(ctx.request.body);
|
||||
ctx.body = msg;
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
55
api/init.go
Normal file
55
api/init.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"sync"
|
||||
|
||||
"github.com/apex/log"
|
||||
)
|
||||
|
||||
// Init init a host to be a fx running
|
||||
func (api *API) Init() error {
|
||||
// enable docker remote api
|
||||
// docker run -d -v /var/run/docker.sock:/var/run/docker.sock -p 127.0.0.1:1234:1234 bobrik/socat TCP-LISTEN:1234,fork UNIX-CONNECT:/var/run/docker.sock
|
||||
cmd := exec.Command(
|
||||
"docker",
|
||||
"run",
|
||||
"-d",
|
||||
"-v",
|
||||
"/var/run/docker.sock:/var/run/docker.sock",
|
||||
"-p",
|
||||
"127.0.0.1:1234:1234",
|
||||
"bobrik/socat",
|
||||
"TCP-LISTEN:1234,fork",
|
||||
"UNIX-CONNECT:/var/run/docker.sock",
|
||||
)
|
||||
stdoutStderr, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Fatalf("Initialize Environment: %v", err)
|
||||
return err
|
||||
}
|
||||
log.Infof("Initialize Environment: \u2713 %s", stdoutStderr)
|
||||
|
||||
baseImages := []string{
|
||||
"metrue/fx-java-base",
|
||||
"metrue/fx-julia-base",
|
||||
"metrue/fx-python-base",
|
||||
"metrue/fx-node-base",
|
||||
"metrue/fx-d-base",
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for _, image := range baseImages {
|
||||
wg.Add(1)
|
||||
go func(img string) {
|
||||
if err := api.pull(img); err != nil {
|
||||
log.Fatalf("Pulling %s failed", img)
|
||||
} else {
|
||||
log.Infof("Pull %s ok", img)
|
||||
}
|
||||
wg.Done()
|
||||
}(image)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
20
api/list.go
Normal file
20
api/list.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/apex/log"
|
||||
"github.com/metrue/fx/utils"
|
||||
)
|
||||
|
||||
// List services
|
||||
func (api *API) List(name string) error {
|
||||
services, err := api.list(name)
|
||||
if err != nil {
|
||||
log.Fatalf("List Services: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, service := range services {
|
||||
utils.OutputJSON(service)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
50
api/pack.go
Normal file
50
api/pack.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/metrue/fx/types"
|
||||
)
|
||||
|
||||
func isHandler(lang string, name string) bool {
|
||||
basename := filepath.Base(name)
|
||||
nameWithoutExt := strings.TrimSuffix(basename, filepath.Ext(basename))
|
||||
return nameWithoutExt == "fx" || nameWithoutExt == "Fx" // Fx is for Java
|
||||
}
|
||||
|
||||
// Pack pack a single function source code to be project
|
||||
func (api *API) Pack(serviceName string, fn types.ServiceFunctionSource) (types.Project, error) {
|
||||
var files []types.ProjectSourceFile
|
||||
for _, name := range api.box.List() {
|
||||
prefix := fmt.Sprintf("%s/", fn.Language)
|
||||
if strings.HasPrefix(name, prefix) {
|
||||
content, err := api.box.FindString(name)
|
||||
if err != nil {
|
||||
return types.Project{}, err
|
||||
}
|
||||
|
||||
// if preset's file is handler function of project, replace it with give one
|
||||
if isHandler(fn.Language, name) {
|
||||
files = append(files, types.ProjectSourceFile{
|
||||
Path: strings.Replace(name, prefix, "", 1),
|
||||
Body: fn.Source,
|
||||
IsHandler: true,
|
||||
})
|
||||
} else {
|
||||
files = append(files, types.ProjectSourceFile{
|
||||
Path: strings.Replace(name, prefix, "", 1),
|
||||
Body: content,
|
||||
IsHandler: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return types.Project{
|
||||
Name: serviceName,
|
||||
Files: files,
|
||||
Language: fn.Language,
|
||||
}, nil
|
||||
}
|
||||
58
api/pack_test.go
Normal file
58
api/pack_test.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/metrue/fx/types"
|
||||
)
|
||||
|
||||
func TestPacker(t *testing.T) {
|
||||
api := NewWithDockerRemoteAPI("127.0.0.1:1234", "0.2.1")
|
||||
|
||||
mockSource := `
|
||||
module.exports = ({a, b}) => {
|
||||
return a + b
|
||||
}
|
||||
`
|
||||
fn := types.ServiceFunctionSource{
|
||||
Language: "node",
|
||||
Source: mockSource,
|
||||
}
|
||||
|
||||
serviceName := "service-mock"
|
||||
project, err := api.Pack(serviceName, fn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if project.Name != serviceName {
|
||||
t.Fatalf("should get %s but got %s", serviceName, project.Name)
|
||||
}
|
||||
|
||||
if project.Language != "node" {
|
||||
t.Fatal("incorrect Language")
|
||||
}
|
||||
|
||||
if len(project.Files) != 3 {
|
||||
t.Fatal("node project should have 3 files")
|
||||
}
|
||||
|
||||
for _, file := range project.Files {
|
||||
if file.Path == "fx.js" {
|
||||
if file.IsHandler == false {
|
||||
t.Fatal("fx.js should be handler")
|
||||
}
|
||||
if file.Body != mockSource {
|
||||
t.Fatalf("should get %s but got %v", mockSource, file.Body)
|
||||
}
|
||||
} else if file.Path == "Dockerfile" {
|
||||
if file.IsHandler == true {
|
||||
t.Fatalf("should get %v but got %v", false, file.IsHandler)
|
||||
}
|
||||
} else {
|
||||
if file.IsHandler == true {
|
||||
t.Fatalf("should get %v but %v", false, file.IsHandler)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
115
api/service_build.go
Normal file
115
api/service_build.go
Normal file
@@ -0,0 +1,115 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-querystring/query"
|
||||
"github.com/google/uuid"
|
||||
"github.com/metrue/fx/types"
|
||||
"github.com/metrue/fx/utils"
|
||||
)
|
||||
|
||||
func makeTar(project types.Project, tarFilePath string) error {
|
||||
dir, err := ioutil.TempDir("/tmp", "fx-build-dir")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
for _, file := range project.Files {
|
||||
tmpfn := filepath.Join(dir, file.Path)
|
||||
if err := utils.EnsureFile(tmpfn); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(tmpfn, []byte(file.Body), 0666); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return utils.TarDir(dir, tarFilePath)
|
||||
}
|
||||
|
||||
// Build build a project
|
||||
func (api *API) Build(project types.Project) (types.Service, error) {
|
||||
tarDir, err := ioutil.TempDir("/tmp", "fx-tar")
|
||||
if err != nil {
|
||||
return types.Service{}, err
|
||||
}
|
||||
defer os.RemoveAll(tarDir)
|
||||
|
||||
imageID := uuid.New().String()
|
||||
tarFilePath := filepath.Join(tarDir, fmt.Sprintf("%s.tar", imageID))
|
||||
if err := makeTar(project, tarFilePath); err != nil {
|
||||
return types.Service{}, err
|
||||
}
|
||||
dockerBuildContext, err := os.Open(tarFilePath)
|
||||
if err != nil {
|
||||
return types.Service{}, err
|
||||
}
|
||||
defer dockerBuildContext.Close()
|
||||
|
||||
type buildQuery struct {
|
||||
Labels string `url:"labels,omitempty"`
|
||||
Tags string `url:"t,omitempty"`
|
||||
Dockerfile string `url:"dockerfile,omitempty"`
|
||||
}
|
||||
|
||||
// Apply default labels
|
||||
labelsJSON, _ := json.Marshal(
|
||||
map[string]string{
|
||||
"belong-to": "fx",
|
||||
},
|
||||
)
|
||||
|
||||
q := buildQuery{
|
||||
Tags: imageID,
|
||||
Labels: string(labelsJSON),
|
||||
Dockerfile: "Dockerfile",
|
||||
}
|
||||
qs, err := query.Values(q)
|
||||
if err != nil {
|
||||
return types.Service{}, err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return types.Service{}, err
|
||||
}
|
||||
path := "/build"
|
||||
url := fmt.Sprintf("%s%s?%s", api.endpoint, path, qs.Encode())
|
||||
req, err := http.NewRequest("POST", url, dockerBuildContext)
|
||||
if err != nil {
|
||||
return types.Service{}, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/x-tar")
|
||||
client := &http.Client{Timeout: 120 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return types.Service{}, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
scanner := bufio.NewScanner(resp.Body)
|
||||
|
||||
for scanner.Scan() {
|
||||
// TODO Maybe need log something out
|
||||
// fmt.Printf("%s\n", scanner.Text())
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return types.Service{}, err
|
||||
}
|
||||
|
||||
return types.Service{
|
||||
Name: project.Name,
|
||||
Status: types.ServiceStatusInit,
|
||||
Image: imageID,
|
||||
}, nil
|
||||
}
|
||||
157
api/service_build_test.go
Normal file
157
api/service_build_test.go
Normal file
@@ -0,0 +1,157 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/metrue/fx/types"
|
||||
gock "gopkg.in/h2non/gock.v1"
|
||||
)
|
||||
|
||||
func TestMakeTar(t *testing.T) {
|
||||
serviceName := "mock-service-abc"
|
||||
project := types.Project{
|
||||
Name: serviceName,
|
||||
Language: "node",
|
||||
Files: []types.ProjectSourceFile{
|
||||
types.ProjectSourceFile{
|
||||
Path: "Dockerfile",
|
||||
Body: `
|
||||
FROM metrue/fx-node-base
|
||||
|
||||
COPY . .
|
||||
EXPOSE 3000
|
||||
CMD ["node", "app.js"]`,
|
||||
IsHandler: false,
|
||||
},
|
||||
types.ProjectSourceFile{
|
||||
Path: "app.js",
|
||||
Body: `
|
||||
const Koa = require('koa');
|
||||
const bodyParser = require('koa-bodyparser');
|
||||
const func = require('./fx');
|
||||
|
||||
const app = new Koa();
|
||||
app.use(bodyParser());
|
||||
app.use(ctx => {
|
||||
const msg = func(ctx.request.body);
|
||||
ctx.body = msg;
|
||||
});
|
||||
|
||||
app.listen(3000);`,
|
||||
IsHandler: false,
|
||||
},
|
||||
types.ProjectSourceFile{
|
||||
Path: "fx.js",
|
||||
Body: `
|
||||
module.exports = (input) => {
|
||||
return input.a + input.b
|
||||
}
|
||||
`,
|
||||
IsHandler: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
tarDir, err := ioutil.TempDir("/tmp", "fx-tar")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tarDir)
|
||||
|
||||
tarFilePath := filepath.Join(tarDir, fmt.Sprintf("%s.tar", serviceName))
|
||||
if err := makeTar(project, tarFilePath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
file, err := os.Open(tarFilePath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
stat, err := file.Stat()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if stat.Name() != serviceName+".tar" {
|
||||
t.Fatalf("should get %s but got %s", serviceName+".tar", stat.Name())
|
||||
}
|
||||
if stat.Size() <= 0 {
|
||||
t.Fatalf("tarfile invalid: size %d", stat.Size())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuild(t *testing.T) {
|
||||
defer gock.Off()
|
||||
|
||||
dockerRemoteAPI := "http://127.0.0.1:1234"
|
||||
version := "0.2.1"
|
||||
|
||||
gock.New(dockerRemoteAPI).
|
||||
Post("/v0.2.1/build").
|
||||
AddMatcher(func(req *http.Request, ereq *gock.Request) (bool, error) {
|
||||
return true, nil
|
||||
}).
|
||||
Reply(200).
|
||||
JSON(map[string]string{
|
||||
"stream": "Step 1/5...",
|
||||
})
|
||||
|
||||
serviceName := "mock-service-abc"
|
||||
project := types.Project{
|
||||
Name: serviceName,
|
||||
Language: "node",
|
||||
Files: []types.ProjectSourceFile{
|
||||
types.ProjectSourceFile{
|
||||
Path: "Dockerfile",
|
||||
Body: `
|
||||
FROM metrue/fx-node-base
|
||||
|
||||
COPY . .
|
||||
EXPOSE 3000
|
||||
CMD ["node", "app.js"]`,
|
||||
IsHandler: false,
|
||||
},
|
||||
types.ProjectSourceFile{
|
||||
Path: "app.js",
|
||||
Body: `
|
||||
const Koa = require('koa');
|
||||
const bodyParser = require('koa-bodyparser');
|
||||
const func = require('./fx');
|
||||
|
||||
const app = new Koa();
|
||||
app.use(bodyParser());
|
||||
app.use(ctx => {
|
||||
const msg = func(ctx.request.body);
|
||||
ctx.body = msg;
|
||||
});
|
||||
|
||||
app.listen(3000);`,
|
||||
IsHandler: false,
|
||||
},
|
||||
types.ProjectSourceFile{
|
||||
Path: "fx.js",
|
||||
Body: `
|
||||
module.exports = (input) => {
|
||||
return input.a + input.b
|
||||
}
|
||||
`,
|
||||
IsHandler: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
api := NewWithDockerRemoteAPI(dockerRemoteAPI, version)
|
||||
service, err := api.Build(project)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if service.Name != serviceName {
|
||||
t.Fatalf("should get %s but got %s", serviceName, service.Name)
|
||||
}
|
||||
if service.Image == "" {
|
||||
t.Fatal("service image should not be empty")
|
||||
}
|
||||
}
|
||||
122
api/service_run.go
Normal file
122
api/service_run.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/metrue/fx/types"
|
||||
"github.com/phayes/freeport"
|
||||
)
|
||||
|
||||
type healtCheck struct {
|
||||
Test []string `json:"Test"`
|
||||
Interval float64 `json:"Interval"`
|
||||
Timeout float64 `json:"Timeout"`
|
||||
Retries int64 `json:"Retries"`
|
||||
StartPeriod float64 `json:"StartPeriod"`
|
||||
}
|
||||
|
||||
// ContainerCreateRequestPayload request paylaod
|
||||
type ContainerCreateRequestPayload struct {
|
||||
Hostname string `json:"Hostname,omitempty"`
|
||||
Domainname string `json:"Domainname,omitempty"`
|
||||
User string `json:"User,omitempty"`
|
||||
AttachStdin bool `json:"AttachStdin,omitempty"`
|
||||
AttachStdout bool `json:"AttachStdout,omitempty"`
|
||||
AttachStderr bool `json:"AttachStderr,omitempty"`
|
||||
Tty bool `json:"Tty,omitempty"`
|
||||
OpenStdin bool `json:"OpenStdin,omitempty"`
|
||||
StdinOnce bool `json:"StdinOnce,omitempty"`
|
||||
Env []string `json:"Env,omitempty"`
|
||||
Cmd []string `json:"Cmd,omitempty"`
|
||||
Entrypoint string `json:"Entrypoint,omitempty"`
|
||||
Image string `json:"Image,omitempty"`
|
||||
Labels map[string]string `json:"Labels,omitempty"`
|
||||
Volumes map[string]interface{} `json:"Volumes,omitempty"`
|
||||
Healthcheck healtCheck `json:"Healthcheck,omitempty"`
|
||||
WorkingDir string `json:"WorkingDir,omitempty"`
|
||||
NetworkDisabled bool `json:"NetworkDisabled,omitempty"`
|
||||
MacAddress string `json:"MacAddress,omitempty"`
|
||||
ExposedPorts nat.PortSet `json:"ExposedPorts,omitempty"`
|
||||
StopSignal string `json:"StopSignal,omitempty"`
|
||||
HostConfig container.HostConfig `json:"HostConfig,omitempty"`
|
||||
NetworkingConfig network.NetworkingConfig `json:"NetworkingConfig,omitempty"`
|
||||
}
|
||||
|
||||
// Run a service
|
||||
func (api *API) Run(service *types.Service) error {
|
||||
port, err := freeport.GetFreePort()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req := ContainerCreateRequestPayload{
|
||||
Image: service.Image,
|
||||
Labels: map[string]string{},
|
||||
ExposedPorts: nat.PortSet{
|
||||
"3000/tcp": struct{}{},
|
||||
},
|
||||
HostConfig: container.HostConfig{
|
||||
AutoRemove: true,
|
||||
PortBindings: nat.PortMap{
|
||||
"3000/tcp": []nat.PortBinding{
|
||||
{
|
||||
HostIP: types.DefaultHost,
|
||||
HostPort: fmt.Sprintf("%d", port),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
body, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("/containers/create?name=%s", service.Name)
|
||||
type containerCreateResponse struct {
|
||||
ID string `json:"Id"`
|
||||
Warnings []string `json:"Warnings"`
|
||||
}
|
||||
var res containerCreateResponse
|
||||
err = api.post(path, body, 201, &res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if res.ID == "" {
|
||||
return fmt.Errorf("container id is missing")
|
||||
}
|
||||
|
||||
path = fmt.Sprintf("/containers/%s/start", res.ID)
|
||||
url := fmt.Sprintf("%s%s", api.endpoint, path)
|
||||
request, err := http.NewRequest("POST", url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client := &http.Client{Timeout: 20 * time.Second}
|
||||
_, err = client.Do(request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
info, err := api.inspect(service.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
instance := types.Instance{
|
||||
ID: info.ID,
|
||||
Host: info.HostConfig.PortBindings["3000/tcp"][0].HostIP,
|
||||
Port: port,
|
||||
State: info.State.Status,
|
||||
}
|
||||
service.Instances = append(service.Instances, instance)
|
||||
|
||||
return nil
|
||||
}
|
||||
47
api/service_run_test.go
Normal file
47
api/service_run_test.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/metrue/fx/types"
|
||||
|
||||
gock "gopkg.in/h2non/gock.v1"
|
||||
)
|
||||
|
||||
func TestServiceRun(t *testing.T) {
|
||||
defer gock.Off()
|
||||
|
||||
dockerRemoteAPI := "http://127.0.0.1:1234"
|
||||
version := "0.2.1"
|
||||
|
||||
service := types.Service{
|
||||
Name: "a-mock-service",
|
||||
Image: "a-mock-image-id",
|
||||
}
|
||||
|
||||
mockContainerID := "mock-container-id"
|
||||
gock.New(dockerRemoteAPI).
|
||||
Post("/v0.2.1/containers").
|
||||
AddMatcher(func(req *http.Request, ereq *gock.Request) (m bool, e error) {
|
||||
// TODO multiple matching not supported by gock
|
||||
if req.URL.String() == dockerRemoteAPI+"/v0.2.1/containers/"+mockContainerID+"/start" {
|
||||
return true, nil
|
||||
} else if req.URL.String() == dockerRemoteAPI+"/v0.2.1/containers/create?name="+service.Name {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}).
|
||||
Reply(201).
|
||||
JSON(map[string]interface{}{
|
||||
"Id": mockContainerID,
|
||||
"Warnings": []string{},
|
||||
})
|
||||
|
||||
api := NewWithDockerRemoteAPI(dockerRemoteAPI, version)
|
||||
// FIXME
|
||||
if err := api.Run(&service); err == nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
24
api/stop.go
Normal file
24
api/stop.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Stop a container by name
|
||||
func (api *API) Stop(name string) error {
|
||||
path := fmt.Sprintf("/containers/%s/stop", name)
|
||||
url := fmt.Sprintf("%s%s", api.endpoint, path)
|
||||
request, err := http.NewRequest("POST", url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client := &http.Client{Timeout: 20 * time.Second}
|
||||
_, err = client.Do(request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
23
api/stop_test.go
Normal file
23
api/stop_test.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
gock "gopkg.in/h2non/gock.v1"
|
||||
)
|
||||
|
||||
func TestStop(t *testing.T) {
|
||||
defer gock.Off()
|
||||
|
||||
dockerRemoteAPI := "http://127.0.0.1:1234"
|
||||
version := "0.2.1"
|
||||
api := NewWithDockerRemoteAPI(dockerRemoteAPI, version)
|
||||
|
||||
mockServiceName := "mock-service-name"
|
||||
gock.New(dockerRemoteAPI).
|
||||
Post("/v0.2.1/containers/" + mockServiceName + "/stop").
|
||||
Reply(204)
|
||||
if err := api.Stop(mockServiceName); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
47
api/up.go
Normal file
47
api/up.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/apex/log"
|
||||
"github.com/metrue/fx/types"
|
||||
"github.com/metrue/fx/utils"
|
||||
)
|
||||
|
||||
// Up up a source code of function to be a service
|
||||
func (api *API) Up(name string, file string) error {
|
||||
src, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
log.Fatalf("Read Source: %v", err)
|
||||
return err
|
||||
}
|
||||
log.Info("Read Source: \u2713")
|
||||
|
||||
lang := utils.GetLangFromFileName(file)
|
||||
fn := types.ServiceFunctionSource{
|
||||
Language: lang,
|
||||
Source: string(src),
|
||||
}
|
||||
|
||||
project, err := api.Pack(name, fn)
|
||||
if err != nil {
|
||||
log.Fatalf("Pack Service: %v", err)
|
||||
return err
|
||||
}
|
||||
log.Info("Pack Service: \u2713")
|
||||
|
||||
service, err := api.Build(project)
|
||||
if err != nil {
|
||||
log.Fatalf("Build Service: %v", err)
|
||||
return err
|
||||
}
|
||||
log.Info("Build Service: \u2713")
|
||||
|
||||
if err := api.Run(&service); err != nil {
|
||||
log.Fatalf("Run Service: %v", err)
|
||||
return err
|
||||
}
|
||||
log.Info("Run Service: \u2713")
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/metrue/fx/api"
|
||||
"github.com/metrue/fx/pkg/client"
|
||||
"github.com/metrue/fx/pkg/utils"
|
||||
)
|
||||
|
||||
type CallOutput struct {
|
||||
Error string `json:"error"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func InvokeCallRequest(address string, function string, params string) (*api.CallResponse, error) {
|
||||
data, err := ioutil.ReadFile(function)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := &api.CallRequest{
|
||||
Lang: utils.GetLangFromFileName(function),
|
||||
Content: string(data),
|
||||
Params: params,
|
||||
}
|
||||
|
||||
client, conn, err := client.NewClient(address)
|
||||
if err != nil {
|
||||
fmt.Println(client, conn, err)
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
res, err := client.Call(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func Call(address string, function string, params string) error {
|
||||
res, err := InvokeCallRequest(address, function, params)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return utils.OutputJSON(res)
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package commands_test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/metrue/fx/commands"
|
||||
"github.com/metrue/fx/pkg/server"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCall(t *testing.T) {
|
||||
addr := "localhost:23451"
|
||||
|
||||
s := server.NewFxServiceServer(addr)
|
||||
go func() {
|
||||
s.Start()
|
||||
}()
|
||||
time.Sleep(2 * time.Second)
|
||||
defer s.Stop()
|
||||
|
||||
code := `
|
||||
module.exports = (input) => {
|
||||
console.log("acc")
|
||||
return parseInt(input.a, 10) + parseInt(input.b, 10)
|
||||
}
|
||||
`
|
||||
content := []byte(code)
|
||||
tmpDir, err := ioutil.TempDir("", "fx")
|
||||
assert.Nil(t, err)
|
||||
assert.NotEqual(t, "", tmpDir)
|
||||
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
tmpfn := filepath.Join(tmpDir, "func.js")
|
||||
err = ioutil.WriteFile(tmpfn, content, 0666)
|
||||
assert.Nil(t, err)
|
||||
|
||||
params := "a=1 b=1"
|
||||
err = Call(addr, tmpfn, params)
|
||||
assert.Nil(t, err)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/metrue/fx/api"
|
||||
"github.com/metrue/fx/pkg/client"
|
||||
"github.com/metrue/fx/pkg/utils"
|
||||
)
|
||||
|
||||
func InvokeDownRequest(address string, functions []string) (*api.DownResponse, error) {
|
||||
client, conn, err := client.NewClient(address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
req := &api.DownRequest{
|
||||
ID: functions,
|
||||
}
|
||||
res, err := client.Down(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func Down(address string, functions []string) error {
|
||||
res, err := InvokeDownRequest(address, functions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return utils.OutputJSON(res)
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package commands_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/metrue/fx/commands"
|
||||
"github.com/metrue/fx/pkg/server"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDown(t *testing.T) {
|
||||
addr := "localhost:23451"
|
||||
functions := []string{"id-should-not-exist"}
|
||||
|
||||
s := server.NewFxServiceServer(addr)
|
||||
go func() {
|
||||
s.Start()
|
||||
}()
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
err := Down(addr, functions)
|
||||
assert.Nil(t, err)
|
||||
|
||||
s.Stop()
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/metrue/fx/api"
|
||||
"github.com/metrue/fx/pkg/client"
|
||||
"github.com/metrue/fx/pkg/utils"
|
||||
)
|
||||
|
||||
// List lists all running function services
|
||||
func List(address string, functions []string) error {
|
||||
client, conn, err := client.NewClient(address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
req := &api.ListRequest{
|
||||
ID: functions,
|
||||
}
|
||||
|
||||
res, err := client.List(ctx, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utils.OutputJSON(res)
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package commands_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/metrue/fx/commands"
|
||||
"github.com/metrue/fx/pkg/server"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
addr := "localhost:23453"
|
||||
s := server.NewFxServiceServer(addr)
|
||||
go func() {
|
||||
s.Start()
|
||||
}()
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
functions := []string{"*"}
|
||||
|
||||
err := List(addr, functions)
|
||||
assert.Nil(t, err)
|
||||
|
||||
s.Stop()
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/metrue/fx/api"
|
||||
"github.com/metrue/fx/pkg/client"
|
||||
"github.com/metrue/fx/pkg/utils"
|
||||
)
|
||||
|
||||
func Status(address string) error {
|
||||
client, conn, err := client.NewClient(address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
req := &api.PingRequest{}
|
||||
_, err = client.Ping(ctx, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return utils.OutputJSON(map[string]string{
|
||||
"status": "ok",
|
||||
"server": address,
|
||||
})
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package commands_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/metrue/fx/commands"
|
||||
"github.com/metrue/fx/pkg/server"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStatus(t *testing.T) {
|
||||
addr := "localhost:23453"
|
||||
s := server.NewFxServiceServer(addr)
|
||||
go func() {
|
||||
s.Start()
|
||||
}()
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
err := Status(addr)
|
||||
assert.Nil(t, err)
|
||||
|
||||
s.Stop()
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/metrue/fx/api"
|
||||
"github.com/metrue/fx/pkg/client"
|
||||
"github.com/metrue/fx/pkg/utils"
|
||||
)
|
||||
|
||||
func InvokeUpRequest(address string, functions []string) (*api.UpResponse, error) {
|
||||
var funcList []*api.FunctionMeta
|
||||
for _, function := range functions {
|
||||
data, err := ioutil.ReadFile(function)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
funcMeta := &api.FunctionMeta{
|
||||
Lang: utils.GetLangFromFileName(function),
|
||||
Content: string(data),
|
||||
}
|
||||
funcList = append(funcList, funcMeta)
|
||||
}
|
||||
|
||||
req := &api.UpRequest{
|
||||
Functions: funcList,
|
||||
}
|
||||
|
||||
client, conn, err := client.NewClient(address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
res, err := client.Up(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func Up(address string, functions []string) error {
|
||||
res, err := InvokeUpRequest(address, functions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
utils.OutputJSON(res)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package commands_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUp(t *testing.T) {
|
||||
assert.Equal(t, nil, nil)
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package commands
|
||||
|
||||
import "github.com/metrue/fx/config"
|
||||
|
||||
func Use(address string) error {
|
||||
config := config.GetConfig()
|
||||
return config.SetHost(address)
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package commands_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/metrue/fx/commands"
|
||||
"github.com/metrue/fx/config"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUse(t *testing.T) {
|
||||
config.CONFIG = "/tmp/fx.json"
|
||||
|
||||
addr := "a.b.c.d"
|
||||
err := Use(addr)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, config.GetHttpServerAddr(), "a.b.c.d:30080")
|
||||
assert.Equal(t, config.GetGrpcEndpoint(), "a.b.c.d:50000")
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/metrue/fx/pkg/utils"
|
||||
)
|
||||
|
||||
type FxConfig struct {
|
||||
Http string `json:"http"`
|
||||
Grpc string `json:"grpc"`
|
||||
}
|
||||
|
||||
var CONFIG = path.Join(os.Getenv("HOME"), ".fx/config.json")
|
||||
var HTTP_PORT = 30080
|
||||
var GRPC_PORT = 50000
|
||||
var DEFAULT_CONFIG = &FxConfig{
|
||||
Http: fmt.Sprintf("localhost:%d", HTTP_PORT),
|
||||
Grpc: fmt.Sprintf("localhost:%d", GRPC_PORT),
|
||||
}
|
||||
|
||||
func GetConfig() *FxConfig {
|
||||
_, err := os.Stat(CONFIG)
|
||||
if err != nil {
|
||||
DEFAULT_CONFIG.save()
|
||||
return DEFAULT_CONFIG
|
||||
}
|
||||
|
||||
raw, err := ioutil.ReadFile(CONFIG)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var c FxConfig
|
||||
json.Unmarshal(raw, &c)
|
||||
|
||||
if len(c.Http) > 0 && len(c.Grpc) > 0 {
|
||||
return &c
|
||||
}
|
||||
|
||||
return DEFAULT_CONFIG
|
||||
}
|
||||
|
||||
func (c *FxConfig) save() error {
|
||||
os.Remove(CONFIG)
|
||||
|
||||
utils.EnsureFile(CONFIG)
|
||||
|
||||
configFile, err := os.OpenFile(CONFIG, os.O_APPEND|os.O_WRONLY, os.ModeAppend)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
configContent, err := json.Marshal(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = configFile.Write(configContent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *FxConfig) SetHost(addr string) error {
|
||||
c.Http = fmt.Sprintf("%s:%d", addr, HTTP_PORT)
|
||||
c.Grpc = fmt.Sprintf("%s:%d", addr, GRPC_PORT)
|
||||
|
||||
err := c.save()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func GetGrpcEndpoint() string {
|
||||
c := GetConfig()
|
||||
return c.Grpc
|
||||
}
|
||||
|
||||
func GetHttpServerAddr() string {
|
||||
c := GetConfig()
|
||||
return c.Http
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package config_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
. "github.com/metrue/fx/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
|
||||
c := GetConfig()
|
||||
assert.NotNil(t, c)
|
||||
|
||||
assert.Equal(t, GetHttpServerAddr(), "localhost:30080")
|
||||
assert.Equal(t, GetGrpcEndpoint(), "localhost:50000")
|
||||
}
|
||||
|
||||
func TestSetHost(t *testing.T) {
|
||||
CONFIG = "/tmp/fx.config.json"
|
||||
|
||||
c := GetConfig()
|
||||
assert.Equal(t, GetHttpServerAddr(), "localhost:30080")
|
||||
assert.Equal(t, GetGrpcEndpoint(), "localhost:50000")
|
||||
|
||||
err := c.SetHost("124.124.124.124")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "124.124.124.124:30080", GetHttpServerAddr())
|
||||
assert.Equal(t, "124.124.124.124:50000", GetGrpcEndpoint())
|
||||
}
|
||||
|
||||
func cleanup() {
|
||||
CONFIG = "/tmp/fx.config.json"
|
||||
os.Remove(CONFIG)
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cleanup()
|
||||
|
||||
m.Run()
|
||||
|
||||
// cleanup()
|
||||
}
|
||||
122
env/env.go
vendored
Normal file
122
env/env.go
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os/exec"
|
||||
"sync"
|
||||
|
||||
"github.com/apex/log"
|
||||
dockerTypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
)
|
||||
|
||||
// DockerRemoteAPIEndpoint docker remote api
|
||||
const DockerRemoteAPIEndpoint = "127.0.0.1:1234"
|
||||
|
||||
type containerInfo struct {
|
||||
ID string `json:"Id"`
|
||||
State dockerTypes.ContainerState `json:"State"`
|
||||
Image string `json:"Image"`
|
||||
HostConfig container.HostConfig `json:"HostConfig"`
|
||||
}
|
||||
|
||||
func proxyDockerSock() error {
|
||||
name := "docker-sock-proxy-for-fx"
|
||||
cmd := exec.Command(
|
||||
"docker",
|
||||
"inspect",
|
||||
name,
|
||||
)
|
||||
var infos []containerInfo
|
||||
stdoutStderr, err := cmd.CombinedOutput()
|
||||
if err := json.Unmarshal(stdoutStderr, &infos); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
const containerStateCreated = "created"
|
||||
const containerStateRestarting = "restarting"
|
||||
const containerStateRunning = "running"
|
||||
const containerStatePaused = "paused"
|
||||
const containerStateExited = "exited"
|
||||
|
||||
state := infos[0].State.Status
|
||||
if state == containerStateRestarting ||
|
||||
state == containerStateRunning { // FIXME should wait for it ready
|
||||
return nil
|
||||
}
|
||||
|
||||
if state == containerStateCreated ||
|
||||
state == containerStatePaused ||
|
||||
state == containerStateExited {
|
||||
cmd := exec.Command(
|
||||
"docker",
|
||||
"start",
|
||||
name,
|
||||
)
|
||||
_, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// enable docker remote api
|
||||
// docker run -d -v /var/run/docker.sock:/var/run/docker.sock -p 127.0.0.1:1234:1234 bobrik/socat TCP-LISTEN:1234,fork UNIX-CONNECT:/var/run/docker.sock
|
||||
cmd = exec.Command(
|
||||
"docker",
|
||||
"run",
|
||||
"--name="+name,
|
||||
"-d",
|
||||
"-v",
|
||||
"/var/run/docker.sock:/var/run/docker.sock",
|
||||
"-p",
|
||||
DockerRemoteAPIEndpoint+":1234",
|
||||
"bobrik/socat",
|
||||
"TCP-LISTEN:1234,fork",
|
||||
"UNIX-CONNECT:/var/run/docker.sock",
|
||||
)
|
||||
_, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Init init a host to make fx runnable
|
||||
func Init() error {
|
||||
if err := proxyDockerSock(); err != nil {
|
||||
log.Fatalf("Proxy Docker Remote API Sock Failed: %v", err)
|
||||
return err
|
||||
}
|
||||
log.Info("Proxy Docker Remote API Sock: \u2713")
|
||||
|
||||
baseImages := []string{
|
||||
"metrue/fx-java-base",
|
||||
"metrue/fx-julia-base",
|
||||
"metrue/fx-python-base",
|
||||
"metrue/fx-node-base",
|
||||
"metrue/fx-d-base",
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for _, image := range baseImages {
|
||||
wg.Add(1)
|
||||
go func(img string) {
|
||||
cmd := exec.Command(
|
||||
"docker",
|
||||
"pull",
|
||||
img,
|
||||
)
|
||||
stdoutStderr, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Fatalf("Pulling %s failed: %v", img, string(stdoutStderr))
|
||||
} else {
|
||||
log.Infof("%s Pulled: \u2713", img)
|
||||
}
|
||||
wg.Done()
|
||||
}(image)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
return nil
|
||||
}
|
||||
9
env/env_test.go
vendored
Normal file
9
env/env_test.go
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package env
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
if err := Init(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
104
fx.go
104
fx.go
@@ -1,28 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/metrue/fx/commands"
|
||||
"github.com/metrue/fx/config"
|
||||
"github.com/metrue/fx/server"
|
||||
"github.com/apex/log"
|
||||
"github.com/google/uuid"
|
||||
"github.com/metrue/fx/api"
|
||||
"github.com/metrue/fx/env"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func fx() *api.API {
|
||||
endpoint := "http://" + env.DockerRemoteAPIEndpoint
|
||||
version, err := api.Version(endpoint)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return api.NewWithDockerRemoteAPI(endpoint, version)
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := cli.NewApp()
|
||||
app.Name = "fx"
|
||||
app.Usage = "make function as a service"
|
||||
app.Version = "0.2.2"
|
||||
app.Usage = "makes function as a service"
|
||||
app.Version = "0.3.0"
|
||||
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "serve",
|
||||
Usage: "start fx server on current host",
|
||||
Name: "init",
|
||||
Usage: "initialize fx running enviroment",
|
||||
Action: func(c *cli.Context) error {
|
||||
return server.Start(true)
|
||||
log.Info("Init Enviroment ....")
|
||||
err := env.Init()
|
||||
if err != nil {
|
||||
log.Fatalf("Init Enviroment%v", err)
|
||||
} else {
|
||||
log.Info("Init Enviroment: \u2713")
|
||||
}
|
||||
return err
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -31,54 +47,31 @@ func main() {
|
||||
ArgsUsage: "[func.go func.js func.py func.rb ...]",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "host, H",
|
||||
Usage: "fx server host, default is localhost",
|
||||
Name: "name, n",
|
||||
Usage: "service name",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
host := c.String("host")
|
||||
if host == "" {
|
||||
host = config.GetGrpcEndpoint()
|
||||
name := c.String("name")
|
||||
if name == "" {
|
||||
name = uuid.New().String()
|
||||
}
|
||||
functionSources := c.Args()
|
||||
return commands.Up(host, functionSources)
|
||||
return fx().Up(name, c.Args().First())
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "down",
|
||||
Usage: "destroy a function or a group of functions",
|
||||
ArgsUsage: "[id1, id2, ...]",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "host, H",
|
||||
Usage: "fx server host, default is localhost",
|
||||
},
|
||||
},
|
||||
Usage: "destroy a service",
|
||||
ArgsUsage: "[service 1, service 2, ....]",
|
||||
Action: func(c *cli.Context) error {
|
||||
host := c.String("host")
|
||||
if host == "" {
|
||||
host = config.GetGrpcEndpoint()
|
||||
}
|
||||
functions := c.Args()
|
||||
return commands.Down(host, functions)
|
||||
return fx().Down(c.Args())
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "list",
|
||||
Usage: "list deployed services",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "host, H",
|
||||
Usage: "fx server host, default is localhost",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
host := c.String("host")
|
||||
if host == "" {
|
||||
host = config.GetGrpcEndpoint()
|
||||
}
|
||||
functions := c.Args()
|
||||
return commands.List(host, functions)
|
||||
return fx().List(c.Args().First())
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -91,37 +84,14 @@ func main() {
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
host := c.String("host")
|
||||
if host == "" {
|
||||
host = config.GetGrpcEndpoint()
|
||||
}
|
||||
params := strings.Join(c.Args()[1:], " ")
|
||||
functions := c.Args()[0]
|
||||
return commands.Call(host, functions, params)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "use",
|
||||
Usage: "set target deploy server address, default is localhost",
|
||||
Action: func(c *cli.Context) error {
|
||||
return commands.Use(c.Args().First())
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "status",
|
||||
Usage: "show fx status",
|
||||
Action: func(c *cli.Context) error {
|
||||
host := c.String("host")
|
||||
if host == "" {
|
||||
host = config.GetGrpcEndpoint()
|
||||
}
|
||||
return commands.Status(host)
|
||||
return fx().Call(c.Args().First(), params)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := app.Run(os.Args)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Fatalf("fx startup with fatal: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
FROM r-base
|
||||
|
||||
COPY . /usr/local/src/fx
|
||||
WORKDIR /usr/local/src/fx
|
||||
RUN R -f packages.R
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["Rscript", "app.R"]
|
||||
@@ -1,11 +0,0 @@
|
||||
library(jug)
|
||||
library(jsonlite)
|
||||
source('./fx.R')
|
||||
|
||||
jug() %>%
|
||||
post("/", function(req, res, err) {
|
||||
input <- fromJSON(req$body)
|
||||
fx(input)
|
||||
}) %>%
|
||||
simple_error_handler_json() %>%
|
||||
serve_it(port = 3000)
|
||||
@@ -1,3 +0,0 @@
|
||||
fx <- function(input) {
|
||||
return (strtoi(input$a) + strtoi(input$b))
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
install.packages(c("jug", "jsonlite"), repos="http://cran.us.r-project.org", dependencies=TRUE)
|
||||
@@ -1,108 +0,0 @@
|
||||
package bundler
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/metrue/fx/common"
|
||||
"github.com/metrue/fx/pkg/utils"
|
||||
)
|
||||
|
||||
var funcNames = map[string]string{
|
||||
"go": "/fx.go",
|
||||
"node": "/fx.js",
|
||||
"ruby": "/fx.rb",
|
||||
"python": "/fx.py",
|
||||
"php": "/fx.php",
|
||||
"julia": "/fx.jl",
|
||||
"java": "/src/main/java/fx/Fx.java",
|
||||
"d": "/fx.d",
|
||||
}
|
||||
|
||||
var assetsMap = map[string][]string{
|
||||
"go": {
|
||||
"assets/dockerfiles/fx/go/Dockerfile",
|
||||
"assets/dockerfiles/fx/go/app.go",
|
||||
"assets/dockerfiles/fx/go/fx.go",
|
||||
},
|
||||
"java": {
|
||||
"assets/dockerfiles/fx/java/Dockerfile",
|
||||
"assets/dockerfiles/fx/java/pom.xml",
|
||||
"assets/dockerfiles/fx/java/src/main/java/fx/Fx.java",
|
||||
"assets/dockerfiles/fx/java/src/main/java/fx/app.java",
|
||||
},
|
||||
"julia": {
|
||||
"assets/dockerfiles/fx/julia/Dockerfile",
|
||||
"assets/dockerfiles/fx/julia/REQUIRE",
|
||||
"assets/dockerfiles/fx/julia/app.jl",
|
||||
"assets/dockerfiles/fx/julia/deps.jl",
|
||||
"assets/dockerfiles/fx/julia/fx.jl",
|
||||
},
|
||||
"node": {
|
||||
"assets/dockerfiles/fx/node/Dockerfile",
|
||||
"assets/dockerfiles/fx/node/app.js",
|
||||
"assets/dockerfiles/fx/node/fx.js",
|
||||
},
|
||||
"php": {
|
||||
"assets/dockerfiles/fx/php/Dockerfile",
|
||||
"assets/dockerfiles/fx/php/fx.php",
|
||||
"assets/dockerfiles/fx/php/index.php",
|
||||
},
|
||||
"python": {
|
||||
"assets/dockerfiles/fx/python/Dockerfile",
|
||||
"assets/dockerfiles/fx/python/app.py",
|
||||
"assets/dockerfiles/fx/python/fx.py",
|
||||
},
|
||||
"ruby": {
|
||||
"assets/dockerfiles/fx/ruby/Dockerfile",
|
||||
"assets/dockerfiles/fx/ruby/app.rb",
|
||||
"assets/dockerfiles/fx/ruby/fx.rb",
|
||||
},
|
||||
"d": {
|
||||
"assets/dockerfiles/fx/d/Dockerfile",
|
||||
"assets/dockerfiles/fx/d/app.d",
|
||||
"assets/dockerfiles/fx/d/fx.d",
|
||||
"assets/dockerfiles/fx/d/arsd/cgi.d",
|
||||
},
|
||||
}
|
||||
|
||||
func removePrefix(lang string, filename string) (name string) {
|
||||
prefix := "assets/dockerfiles/fx" + "/" + lang + "/"
|
||||
return strings.Split(filename, prefix)[1]
|
||||
}
|
||||
|
||||
func isFxFuncSource(lang string, name string) (ret bool) {
|
||||
basename := filepath.Base(name)
|
||||
nameWithoutExt := strings.TrimSuffix(basename, filepath.Ext(basename))
|
||||
return nameWithoutExt == "fx" || nameWithoutExt == "Fx" // Fx is for Java
|
||||
}
|
||||
|
||||
//Bundle Prepare a container base image and insert the function body
|
||||
func Bundle(dir string, lang string, body []byte) (err error) {
|
||||
names := assetsMap[lang]
|
||||
err = nil
|
||||
for _, name := range names {
|
||||
data, assetErr := common.Asset(name)
|
||||
if assetErr != nil {
|
||||
err = assetErr
|
||||
}
|
||||
|
||||
name = removePrefix(lang, name)
|
||||
targetPath := path.Join(dir, name)
|
||||
|
||||
dir := filepath.Dir(targetPath)
|
||||
utils.EnsurerDir(dir)
|
||||
|
||||
if isFxFuncSource(lang, targetPath) {
|
||||
data = body
|
||||
}
|
||||
|
||||
writeErr := ioutil.WriteFile(targetPath, data, 0644)
|
||||
if writeErr != nil {
|
||||
err = writeErr
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package bundler
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBundle(t *testing.T) {
|
||||
targetDir, _ := ioutil.TempDir("", "image_test")
|
||||
Bundle(targetDir, "go", []byte("import \"fmt\""))
|
||||
|
||||
files, _ := ioutil.ReadDir(targetDir)
|
||||
if len(files) != 3 {
|
||||
t.Errorf("files number not correct, got: %d, want: %d.", len(files), 3)
|
||||
}
|
||||
|
||||
if files[0].Name() != "Dockerfile" {
|
||||
t.Errorf("Dockerfile not correct, got: %s, want: %s.", files[0], "Dockerfile")
|
||||
}
|
||||
|
||||
if files[1].Name() != "app.go" {
|
||||
t.Errorf("app.go not correct, got: %s, want: %s.", files[1], "app.go")
|
||||
}
|
||||
|
||||
if files[2].Name() != "fx.go" {
|
||||
t.Errorf("fx.go not correct, got: %s, want: %s.", files[2], "fx.go")
|
||||
}
|
||||
|
||||
filePath := path.Join(targetDir, files[2].Name())
|
||||
data, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
t.Errorf("open fx.go error: %s", err)
|
||||
}
|
||||
|
||||
if string(data) != "import \"fmt\"" {
|
||||
t.Errorf("content of fx.go not correct, got: %s, want: %s.", data, "import \"fmt\"")
|
||||
}
|
||||
|
||||
defer os.RemoveAll(targetDir)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user