You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by su...@apache.org on 2020/11/21 11:11:16 UTC
[apisix-dashboard] branch master updated: release: release 2.0-rc
version. (#598)
This is an automated email from the ASF dual-hosted git repository.
sunyi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-dashboard.git
The following commit(s) were added to refs/heads/master by this push:
new b989a0f release: release 2.0-rc version. (#598)
b989a0f is described below
commit b989a0f7d9630088991eadec844efeed39c0cf57
Author: litesun <7s...@gmail.com>
AuthorDate: Sat Nov 21 19:11:08 2020 +0800
release: release 2.0-rc version. (#598)
* Update CHANGELOG.md
* Update CHANGELOG.zh-CN.md
* Update CHANGELOG.md
* Update CHANGELOG.zh-CN.md
* Update CHANGELOG.md
* feat: update deploy docs
* feat: separate build and run to 2 scripts (#600)
* feat: separate build and run
* doc: update doc about build and run
* doc: update doc about build and run
* Update schema-sync.sh
* Update develop.md
* Update develop.zh-CN.md
Co-authored-by: 琚致远 <ju...@apache.org>
* feat: remove unused dist folder
* doc: add etcd api version tips (#604)
* doc: add etcd version tips(#602)
* Update README.md
* Update README.zh-CN.md
Co-authored-by: 琚致远 <ju...@apache.org>
* Update deploy.md
* Update deploy.zh-CN.md
* feat(docs): update deploy docs
* feat(doc): added tip in deploy
* feat(doc): update run part in deploy
* feat(doc): added FAQ about how to redeploy
* fix: 2.0 release issues (#606)
* fix: remove json schema generation from ci
* fix: use json schema generated from APISIX v2.0
* fix: ant-design/ant-design/issues/27396
* fix: using relative path to read conf (#617)
* fix: using relative path
* fix path
* fix path
* feat: support custom server host, port and DAG lib path (#625)
* feat: support custom server port and dag lib path
* test: custom host
* test: add test case
* fix bug
* test
* test
* test
* feat support config etcd endpoints
* Update conf.json
* Update conf.go
* Update test-api.yml
* Update deploy.md
* Update deploy.zh-CN.md
* Update deploy.md
* Update conf.json
Co-authored-by: 琚致远 <ju...@apache.org>
* feat(doc): update config file
* feat(doc): update Note
* feat(docs): update NOTE
* feat(doc): update ETCD endpoints
* Update deploy.md
* feat: refactor folders (#629)
* feat: refactor api & frontend
* feat: remove some actions
* feat: added - v2.0
* feat: added ignored files for checker
* feat: trigger ci
* feat: trigger CI
* feat: added conf.json
* fix: build dashboard
* feat: remove demo temp
* feat: update build.sh
* chore: improve issue template and vscode (#660)
* test: add e2e test for field hosts in `route` api (#612)
* feat: ETCD cluster and APISIX cluster for CI
* feat: add test cases
* feat: add upstream service in docker compose
* fix: comment
* test: add test cases
* fix: code format
* test: add ci
* fix ci
* fix ci
* fix ci
* fix: remove consumer test
* test: sleep for sync
* test: e2e as an independent subproject
* fix CI error
* test: run docker
* fix: remove json schema generate script in docker build
* fix: check host and hosts config together
* fix ci
* test: add test cases for `host` in route
* remove useless code
* fix: using relative path to read conf (#617)
* fix: using relative path
* fix path
* fix path
* fix conf path
* fix ci error
* fix etcd ip
* fix: code format
* run backend e2e test ci on v2 branch
* fix: code format
* fix: code format
* fix: CI error
* test: remove deploy CI again
* remove useless codes
* fix: go fmt
* test: don't use `go fmt`
* fix: code format
* fix: var name
* fix lint
* fix CI error
* debug
* fix: docker container name
* fix CI error
* fix CI error
* test: add more test cases
* fix CI error
* chore: remove useless code
* fix: go fmt
* fix: refactor test code
* fix: check body
* fix small issue
* fix: update docker compose
* fix CI
* test
* test
* test: build image first
* test: revert subnet ip in docker compose
* fix by review
* fix: docker compose
* test: add test cases
* fix: remove useless code
* fix: code format
* test: code format
* feat: added e2e test for Login page (#619)
* feat: added Front-end e2e test YAML file
* feat: added login e2e test
* feat: update Login.e2e.js
* Update Login.e2e.js
* feat: added e2e readme
* feat: added licence
* feat: added start-server-and-test package
* feat: update login test case
* Update frontend-e2e-test.yml
* feat: added logout test case
* Update frontend-e2e-test.yml
* feat: added login failed with empty input
* feat: update CI
* feat: update text
* feat: added public.js
* feat: change logout timeout
* feat: Added e2e test documentation link to development.md
* Update develop.md
* Update develop.zh-CN.md
* Update README.md
Co-authored-by: 琚致远 <ju...@apache.org>
* CI: collect golang unit test code coverage (#654)
* fix: promethus incorrect value when update route (#666)
* feat: deploy with Docker (#657)
* feat: added Docker
* feat: added License header
* feat: added line in docs
* Update test-docker.yml
* feat(doc): update docs
* feat: added extra line
* feat: added Go Proxy in Dockerfile
* feat: update Dockerfile
* chore: update docs
* fix: copy correct files
* feat: improve Dockerfile
* Revert "feat: improve Dockerfile"
This reverts commit c68a4c4e479147e65efae4611ba162bd2c465928.
* fix run fail
* feat: update docs
* fix: compatible with Golang conf
* Squashed commit of the following:
commit 94450bf6ad52cdcac8d527c7e7fbf9e8fa1c4ab3
Author: litesun <7s...@gmail.com>
Date: Tue Nov 3 10:19:04 2020 +0800
fix: promethus incorrect value when update route (#666)
commit de8bdbf6ff867a05dffbd05151b1ba07603f46d2
Author: nic-chen <33...@users.noreply.github.com>
Date: Tue Nov 3 07:50:29 2020 +0800
CI: collect golang unit test code coverage (#654)
commit 722c0fdeddbc34723f730e36a4cff004889f7093
Author: litesun <7s...@gmail.com>
Date: Tue Nov 3 00:03:06 2020 +0800
feat: added e2e test for Login page (#619)
* feat: added Front-end e2e test YAML file
* feat: added login e2e test
* feat: update Login.e2e.js
* Update Login.e2e.js
* feat: added e2e readme
* feat: added licence
* feat: added start-server-and-test package
* feat: update login test case
* Update frontend-e2e-test.yml
* feat: added logout test case
* Update frontend-e2e-test.yml
* feat: added login failed with empty input
* feat: update CI
* feat: update text
* feat: added public.js
* feat: change logout timeout
* feat: Added e2e test documentation link to development.md
* Update develop.md
* Update develop.zh-CN.md
* Update README.md
Co-authored-by: 琚致远 <ju...@apache.org>
commit 915ce8300b8138eb986737e6df1201fff63d3b57
Author: nic-chen <33...@users.noreply.github.com>
Date: Mon Nov 2 21:13:34 2020 +0800
test: add e2e test for field hosts in `route` api (#612)
* feat: ETCD cluster and APISIX cluster for CI
* feat: add test cases
* feat: add upstream service in docker compose
* fix: comment
* test: add test cases
* fix: code format
* test: add ci
* fix ci
* fix ci
* fix ci
* fix: remove consumer test
* test: sleep for sync
* test: e2e as an independent subproject
* fix CI error
* test: run docker
* fix: remove json schema generate script in docker build
* fix: check host and hosts config together
* fix ci
* test: add test cases for `host` in route
* remove useless code
* fix: using relative path to read conf (#617)
* fix: using relative path
* fix path
* fix path
* fix conf path
* fix ci error
* fix etcd ip
* fix: code format
* run backend e2e test ci on v2 branch
* fix: code format
* fix: code format
* fix: CI error
* test: remove deploy CI again
* remove useless codes
* fix: go fmt
* test: don't use `go fmt`
* fix: code format
* fix: var name
* fix lint
* fix CI error
* debug
* fix: docker container name
* fix CI error
* fix CI error
* test: add more test cases
* fix CI error
* chore: remove useless code
* fix: go fmt
* fix: refactor test code
* fix: check body
* fix small issue
* fix: update docker compose
* fix CI
* test
* test
* test: build image first
* test: revert subnet ip in docker compose
* fix by review
* fix: docker compose
* test: add test cases
* fix: remove useless code
* fix: code format
* test: code format
commit 94d024544df0caff6aef69f6ca9792954a285304
Author: 琚致远 <ju...@apache.org>
Date: Mon Nov 2 13:17:42 2020 +0800
chore: improve issue template and vscode (#660)
* Revert "Squashed commit of the following:"
This reverts commit 93d38eef07058f5c65ac1eb83aac9d04ec12d24d.
* feat: remove output from ignore files
Co-authored-by: nic-chen <jo...@163.com>
* feat: use web instead of frontend (#674)
* feat: use web instead of frontend
* feat: rename frontend to web
* feat: remove all frontend to web
* feat: support get plugin schema based on schema_type (#651)
* feat: support get plugin schema based on schema_type
* fix: ci errors
* fix: run error casued by api-breaker.lua
* fix: get schema_type from query and add some test
* fix: update schema.json file
* fix: update validate to support schematype
* fix: properties:{} validate failed
* fix: some code errors refer to the review
* test: add linter for manager api (#655)
* test: add go lint
* fix lint
* fix by review
* fix errors
* test: run lint on v2.0
* fix: text format
* fix: os check
* fix typo
* fix: fmt --> log
* fix log
* fix: unnecessary nil check around range for lint
* fix: trigger lint for push to branch v2.0
* feat: update plugin to 1.0.10
* fix: enable HTTPS setting unsuccessful in Route (#692)
* fix: wrong stepHeader after edit MatchingRules
* feat: disable plugin orchestration when select forcehttps
* feat: update Route transform
* feat: cache Front-end e2e CI node_modules (#696)
* chore: refactor `conf` of `manager api` (#693)
* feat: refactor conf
* fix default listen port
* fix build and run scripts
* fix: docs
* chore: remove useless file
* fix docker for test
* fix CI
* fix CI
* fix ci
* fix: `-c` conf dir --> `-p` work dir
* fix go test error
* fix conf
* fix: revert changes
* fix: remove useless comment
* fix: remove useless comment
* doc: add comment for config
* doc: todo
* fix: config format
* fix: if secret use default value, should generate a random string to replace it.
* fix comment style
* fix: change web dir in docker file
* doc: update comments
* fix:bug that dirty data exists after updating route and wrong mod for prod env (#704)
* fix: route bug, dirty data exists after updating
* fix mod for env
* fix mod for env
* fix error log
* fix error log
* chore: refactor error log for `manager api` (#689)
* chore: refactor log
* fix: custom log by conf
* feat: add error log
* fix default config
* fix CI fail
* fix: should not save log to file by default
* test: add test case
* test: add test case
* fix CI fail
* fix error
* fix CI
* fix error
* fix according to reviews
* test: more test cases
* fix error
* chore: use `/dev/stdout` as default log file path
* fix typo
* fix docker for logs dir
* fix CI fail
* fix: delete useless files
* fix: change file name
* bugfix: dashboard 2.0 failed to fetch ssl certificate not found (#719)
* fix: set ssl status, since it's default 0
* add test cases
* test: add test cases
* fix: update test cases
* fix: test case fail
* test: remove hosts in hosts setting
* fix: according review
* fix: according review
* chore: add comment
* fix: update order (#744)
* feat(Consumer): use username instead of id (#742)
* feat(Consumer): use username instead of id
* feat: remove duplicated var
* chore: exit if any error and specify the download file name when download by `wget`. (#751)
fix #646
* fix: an error will occur if `pass_host` is set to `node` when creating upstream (#750)
* fix: bug #749
* fix: bug #749
* test: add test cases
* fix: CI
* fix: CI fail
* test: add e2e test cases for upstream (#738)
* fix: react warnings (#747)
* fix: update json schema (#754)
* chore: move the Dockerfile to `test` folder, because it was used for testing (#753)
* feat: convert uri to uris (#740)
* feat: deploy with docker (#701)
* feat: added deploy with docker CD
* feat: docker deploy test
* fix: CI
* fix: path of `config.yaml`
* fix: CI fail
* docs: update doc for docker deploy
* fix: typo
* fix: add EOF && trigger CD
Co-authored-by: nic-chen <jo...@163.com>
Co-authored-by: kv <gx...@163.com>
* fix: invalid values from the manager-api (#736)
* feat: return None when timestamp is invalid
* chore: added TODO
* docs: add makefile && modify develop and deploy docs (#729)
* docs: add makefile && modify develop and deploy docs
* docs: Make the makefile clearer
* docs: modify frontend to web
* doc: two blankline between commands
* doc: remove blanklien EOF
* docs: remove make run/stop in makefile
* docs: make readme readable
* docs: declear in readme
* docs: make readme readable
* docs: remove dependencies in readme
* docs: check english desc
* docs: style adjust
* docs: sync makefile desc
* docs: remove blank
* docs: style adjust
* docs: remove ENV=local in deploy
* fix: modify lint ci
* docs: unify go-lint
* docs: check all text
* docs: makefile Aligned
* docs: update style
* docs: add markdown code style
* docs: fix syntax
* docs: remove Self-referencing
* docs: user guide
* docs: use header
* docs: style fix
* docs: add desc
* docs: modify 'pack' to 'package'
* docs: unify manager-api
* docs: mv Install to Installation
* docs: node to Node.js
* docs: source codes to Source Codes
* docs: Source Codes
* fix: mkdir -p ./output/logs in makefile build
* feat: support specifying APISIX path to generate json schema (#765)
* feat: support specifying APISIX path to generate json schema
* doc: update doc about schema sync
* fix: doc
* fix: errors
* fix: error according to test
* test
* no message
* test
* fix: remove debug
* test: add consumer e2e test (#735)
* add consumer e2e test
add public method "PartialBody"
* test: add end with EOL
* add test data plane to case 2
delete some useless code
* modify code style
* fix: makefile build error (#767)
* fix: used dashboard add consumer of jwt, would have an error when get the jwt token (#768)
* feat: update changelog (#771)
* Update CHANGELOG.md
* Update CHANGELOG.zh-CN.md
* docs: update change log
Co-authored-by: nic-chen <jo...@163.com>
* fix: consumer schema for auth plugin (#770)
* fix: consumer schema for auth plugin
* fix: update by jsonschema
* fix: json schema
* fix: doc (#772)
* fix: doc (#774)
* feat: remove CD for PR
* fix: closed WatchResponse channel when cancel function is called (#779) (#795)
* ci: fix CI naming (#799)
* fix: make cli test more compatible (#798)
* test: fix e2e test unstable (#800)
* fix: double scroll bar in plugin page (#801)
* feat(docs): improve README & Deploy (#785)
* feat(doc): update README & deploy
* feat(docs): added FAQ
* fix: linkx
* feat(docs): update deploy with docker
* feat(docs): update FAQ
* feat: update README
* feat: update README
* feta: update README
* fix: link
* feat: update deploy with docker
* feat(docs): added tip for some users
* feat(doc): improve deploy with docker
* feat(docs): improve deploy with docker
* feat(doc): update run with docker
* feat(doc): improve deploy
* feat(doc): added more info
* feat(doc): added more info
* feat(doc): remove extra info
* feat: added more detailed
* fix: CI fail according `api/conf/conf.yaml ` is changed.
* fix: revert changed
* feat(docs): improve English version
* feat(docs): use frontend instead, just like backend
* feat(docs): remove extra statements
* feat(docs): update typo
* feat(docs): remove startup with message
* feat: update CI's name
Co-authored-by: nic-chen <jo...@163.com>
* feat: skip puppeteer chromium download when build (#808)
* feat(Makefile): update release-src (#816)
* ci: fix CI fail (#818)
* ci: fix CI fail
* ci: fix CI fail
* ci: fix CI fail
* test: add e2e test for config route with service_id or upstream_id (#810)
* test: add e2e test for config route with service_id or upstream_id
* test: fix route test
* test: fix route test
* test: fix route test
* test: fix route test format
* test: fix route test format
* test: fix test format
* test: add test on data plane
* test: fix test conflict
* feat: install signal handler for graceful shutdown (#737) (#796)
* Revert "test: add consumer e2e test (#735)" (#829)
This reverts commit c140f41acdc90b53db3b349f63a43503666a76fe.
* feat: add a hanlder unit test for upstream and remove init
* append license
* revert unreviewed pr (#841)
Co-authored-by: nic-chen <33...@users.noreply.github.com>
Co-authored-by: 琚致远 <ju...@apache.org>
Co-authored-by: jiayx <ji...@users.noreply.github.com>
Co-authored-by: nic-chen <jo...@163.com>
Co-authored-by: liuxiran <be...@126.com>
Co-authored-by: YuanSheng Wang <me...@gmail.com>
Co-authored-by: kv <gx...@163.com>
Co-authored-by: idbeta <id...@gmail.com>
Co-authored-by: Peter Zhu <st...@gmail.com>
Co-authored-by: EnableAsync <43...@users.noreply.github.com>
Co-authored-by: ShiningRush <27...@qq.com>
---
.actions/ASF-Release.cfg | 20 +-
.asf.yaml | 1 -
.dockerignore | 2 +-
.github/ISSUE_TEMPLATE | 23 -
.github/ISSUE_TEMPLATE/bug-report.md | 36 +
.github/ISSUE_TEMPLATE/config.yml | 5 +
.github/ISSUE_TEMPLATE/feature-request.md | 23 +
.github/workflows/backend-cli-test.yml | 31 +
.github/workflows/backend-e2e-test.yml | 33 +
.github/workflows/backend-unit-test.yml | 74 +
.github/workflows/deploy-api.yml | 70 -
.github/workflows/deploy-frontend.yml | 22 -
.github/workflows/deploy-with-docker.yml | 44 +
.github/workflows/frontend-e2e-test.yml | 40 +
.../workflows/{license-checker.yml => go-lint.yml} | 12 +-
.github/workflows/license-checker.yml | 1 +
.github/workflows/test-api.yml | 61 -
.github/workflows/test-deploy-with-go.yml | 73 -
.../test-frontend-multiple-node-build.yml | 12 +-
.gitignore | 11 +-
.vscode/settings.json | 8 +
CHANGELOG.md | 24 +
CHANGELOG.zh-CN.md | 26 +
Dockerfile | 75 +-
Makefile | 98 +-
README.md | 59 +-
README.zh-CN.md | 66 +-
api/build-tools/schema-sync.lua | 15 +-
api/{entry.sh => build-tools/schema-sync.sh} | 39 +-
compose/manager_conf/entry.sh => api/build.sh | 31 +-
api/conf/conf.go | 171 +-
api/conf/conf.json | 23 -
api/conf/conf.yaml | 41 +
api/conf/conf_preview.json | 23 -
api/conf/schema.json | 3500 +++++++++++++++++++-
api/docker-compose.yml | 25 -
api/entry.sh | 18 +-
api/filter/authentication.go | 2 +-
api/filter/logging.go | 70 +-
api/filter/recover.go | 15 +-
api/go.mod | 4 +
api/go.sum | 234 +-
api/internal/core/entity/entity.go | 45 +-
api/internal/core/entity/format.go | 19 +-
api/internal/core/entity/format_test.go | 4 +-
api/internal/core/storage/etcd.go | 5 +-
api/internal/core/store/query.go | 4 +-
api/internal/core/store/store.go | 17 +-
api/internal/core/store/store_test.go | 6 +-
api/internal/core/store/storehub.go | 3 +
api/internal/core/store/validate.go | 79 +-
api/internal/core/store/validate_test.go | 175 +-
.../handler/authentication/authentication.go | 4 +-
.../handler/authentication/authentication_test.go | 17 +-
api/internal/handler/consumer/consumer.go | 14 +
api/internal/handler/consumer/consumer_test.go | 90 +-
api/internal/handler/plugin/plugin.go | 16 +-
api/internal/handler/plugin/plugin_test.go | 54 +-
api/internal/handler/route/route.go | 24 +-
api/internal/handler/route/route_test.go | 1652 ++++-----
api/internal/handler/service/service_test.go | 66 +-
api/internal/handler/ssl/ssl.go | 6 +
api/internal/handler/ssl/ssl_test.go | 18 +-
api/internal/handler/upstream/upstream_test.go | 250 +-
api/internal/route.go | 2 +-
api/log/log.go | 207 +-
api/log/zap.go | 89 +
api/{dist/.gitkeep => logs/placeholder.txt} | 0
api/main.go | 41 +-
api/run.sh | 41 +-
api/test/certs/apisix.crt | 27 +
api/test/certs/apisix.key | 39 +
api/test/certs/test2.crt | 28 +
api/test/certs/test2.key | 39 +
api/test/docker-deploy/docker-compose.yaml | 66 +
api/{ => test/docker}/Dockerfile | 22 +-
.../test/docker/apisix_config.yaml | 31 +-
api/test/docker/docker-compose.yaml | 183 +
api/test/docker/manager-api-conf.yaml | 43 +
api/test/docker/upstream.conf | 72 +
api/test/e2e/base.go | 170 +
api/test/e2e/go.mod | 10 +
api/test/e2e/go.sum | 126 +
api/test/e2e/route_service_upstream_test.go | 304 ++
api/test/e2e/route_test.go | 249 ++
api/test/e2e/ssl_test.go | 146 +
api/test/e2e/upstream_test.go | 243 ++
api/test/shell/cli_test.sh | 95 +
api/test/shell/docker_deploy_test.sh | 43 +
compose/dashboard_conf/nginx.conf | 39 -
compose/docker-compose.yml | 134 -
compose/grafana_conf/config/grafana.ini | 756 -----
.../dashboards/apisix_http_prometheus.json | 933 ------
.../grafana_conf/provisioning/dashboards/all.yaml | 27 -
.../grafana_conf/provisioning/datasources/all.yaml | 25 -
compose/prometheus_conf/prometheus.yml | 39 -
docker/nginx.conf | 38 -
docs/FAQ.md | 56 +
docs/FAQ.zh-CN.md | 56 +
docs/USER_GUIDE.md | 2 -
docs/USER_GUIDE.zh-CN.md | 2 +-
docs/deploy-with-docker.md | 81 +
docs/deploy-with-docker.zh-CN.md | 81 +
docs/deploy.md | 79 +-
docs/deploy.zh-CN.md | 73 +-
docs/develop.md | 57 +-
docs/develop.zh-CN.md | 54 +-
docs/images/architecture.png | Bin 0 -> 162681 bytes
src/pages/Consumer/index.ts | 16 -
.editorconfig => web/.editorconfig | 0
.eslintignore => web/.eslintignore | 0
.eslintrc.js => web/.eslintrc.js | 0
.prettierignore => web/.prettierignore | 0
.prettierrc.js => web/.prettierrc.js | 0
.stylelintrc.js => web/.stylelintrc.js | 0
{config => web/config}/config.ts | 1 +
{config => web/config}/defaultSettings.ts | 0
{config => web/config}/proxy.ts | 0
{config => web/config}/routes.ts | 2 +-
jest.config.js => web/jest.config.js | 0
jsconfig.json => web/jsconfig.json | 0
{mock => web/mock}/notices.ts | 0
{mock => web/mock}/route.ts | 0
{mock => web/mock}/user.ts | 0
package.json => web/package.json | 5 +-
{public => web/public}/empty.svg | 0
{public => web/public}/favicon.png | Bin
{scripts => web/scripts}/verifyCommit.js | 0
{src => web/src}/access.ts | 0
{src => web/src}/app.tsx | 0
{src => web/src}/assets/logo.svg | 0
.../src}/components/ActionBar/ActionBar.tsx | 0
{src => web/src}/components/ActionBar/index.ts | 0
.../src}/components/ActionBar/locales/en-US.ts | 0
.../src}/components/ActionBar/locales/zh-CN.ts | 0
{src => web/src}/components/Footer/index.tsx | 0
.../src}/components/HeaderDropdown/index.less | 0
.../src}/components/HeaderDropdown/index.tsx | 0
.../src}/components/NoticeIcon/NoticeList.less | 0
.../src}/components/NoticeIcon/NoticeList.tsx | 0
{src => web/src}/components/NoticeIcon/index.less | 0
{src => web/src}/components/NoticeIcon/index.tsx | 0
{src => web/src}/components/PageLoading/index.tsx | 0
.../components/RightContent/AvatarDropdown.tsx | 0
.../src}/components/RightContent/index.less | 0
{src => web/src}/components/RightContent/index.tsx | 0
.../src}/components/Upstream/UpstreamForm.tsx | 47 +-
{src => web/src}/components/Upstream/constant.ts | 0
{src => web/src}/components/Upstream/index.ts | 0
{src => web/src}/constants.ts | 0
web/src/e2e/Login.e2e.js | 75 +
web/src/e2e/Logout.e2e.js | 56 +
docs/develop.md => web/src/e2e/README.md | 24 +-
compose/README.md => web/src/e2e/README.zh-CN.md | 22 +-
.../src}/e2e/__mocks__/antd-pro-merge-less.js | 0
{src => web/src}/e2e/baseLayout.e2e.js | 0
.../Preview.tsx => web/src/e2e/service.js | 32 +-
{src => web/src}/global.less | 5 +
{src => web/src}/global.tsx | 0
{src => web/src}/helpers.tsx | 10 +
{src => web/src}/iconfont.ts | 0
{src => web/src}/locales/en-US.ts | 0
{src => web/src}/locales/en-US/component.ts | 0
{src => web/src}/locales/en-US/globalHeader.ts | 0
{src => web/src}/locales/en-US/menu.ts | 0
{src => web/src}/locales/en-US/pwa.ts | 0
.../zh-CN => web/src/locales/en-US}/setting.ts | 0
{src => web/src}/locales/en-US/settingDrawer.ts | 0
{src => web/src}/locales/zh-CN.ts | 0
{src => web/src}/locales/zh-CN/component.ts | 0
{src => web/src}/locales/zh-CN/globalHeader.ts | 0
{src => web/src}/locales/zh-CN/menu.ts | 0
{src => web/src}/locales/zh-CN/pwa.ts | 0
.../en-US => web/src/locales/zh-CN}/setting.ts | 0
{src => web/src}/locales/zh-CN/settingDrawer.ts | 0
{src => web/src}/manifest.json | 0
{src => web/src}/pages/404.tsx | 0
{src => web/src}/pages/Consumer/Create.tsx | 18 +-
{src => web/src}/pages/Consumer/List.tsx | 8 +-
.../src}/pages/Consumer/components/Preview.tsx | 0
.../src}/pages/Consumer/components/Step1.tsx | 0
{src => web/src}/pages/Consumer/locales/en-US.ts | 0
{src => web/src}/pages/Consumer/locales/zh-CN.ts | 0
{src => web/src}/pages/Consumer/service.ts | 10 +-
{src => web/src}/pages/Consumer/typing.d.ts | 0
{src => web/src}/pages/Metrics/Metrics.tsx | 0
{src => web/src}/pages/Metrics/index.ts | 0
{src => web/src}/pages/Metrics/locales/en-US.ts | 0
{src => web/src}/pages/Metrics/locales/zh-CN.ts | 0
{src => web/src}/pages/Metrics/service.ts | 0
{src => web/src}/pages/Route/Create.less | 0
{src => web/src}/pages/Route/Create.tsx | 20 +-
{src => web/src}/pages/Route/List.tsx | 32 +-
.../Route/components/CreateStep4/CreateStep4.tsx | 0
.../pages/Route/components/CreateStep4/index.ts | 0
.../Route/components/ResultView/ResultView.tsx | 0
.../pages/Route/components/ResultView/index.ts | 0
.../Route/components/Step1/MatchingRulesView.tsx | 2 +-
.../src}/pages/Route/components/Step1/MetaView.tsx | 0
.../Route/components/Step1/RequestConfigView.tsx | 0
.../src}/pages/Route/components/Step1/index.tsx | 0
.../Route/components/Step2/RequestRewriteView.tsx | 0
.../src}/pages/Route/components/Step2/index.tsx | 0
.../src}/pages/Route/components/Step3/index.tsx | 57 +-
{src => web/src}/pages/Route/constants.ts | 0
{src => web/src}/pages/Route/index.ts | 0
{src => web/src}/pages/Route/locales/en-US.ts | 0
{src => web/src}/pages/Route/locales/zh-CN.ts | 0
{src => web/src}/pages/Route/service.ts | 0
{src => web/src}/pages/Route/transform.ts | 53 +-
{src => web/src}/pages/Route/typing.d.ts | 4 +
{src => web/src}/pages/SSL/Create.less | 0
{src => web/src}/pages/SSL/Create.tsx | 0
{src => web/src}/pages/SSL/List.tsx | 6 +-
.../pages/SSL/components/CertificateForm/index.tsx | 0
.../SSL/components/CertificateUploader/index.tsx | 0
.../src}/pages/SSL/components/Step1/index.tsx | 0
.../src}/pages/SSL/components/Step2/index.tsx | 0
{src => web/src}/pages/SSL/locales/en-US.ts | 0
{src => web/src}/pages/SSL/locales/zh-CN.ts | 0
{src => web/src}/pages/SSL/service.ts | 0
{src => web/src}/pages/SSL/style.less | 0
{src => web/src}/pages/SSL/typing.d.ts | 0
{src => web/src}/pages/Setting/Setting.tsx | 0
{src => web/src}/pages/Setting/index.ts | 0
{src => web/src}/pages/Setting/locales/en-US.ts | 0
{src => web/src}/pages/Setting/locales/zh-CN.ts | 0
{src => web/src}/pages/Setting/service.ts | 0
{src => web/src}/pages/Setting/style.less | 0
{src => web/src}/pages/Setting/typingd.d.ts | 0
{src => web/src}/pages/Upstream/Create.tsx | 0
{src => web/src}/pages/Upstream/List.tsx | 4 +-
.../src}/pages/Upstream/components/Step1.tsx | 0
{src => web/src}/pages/Upstream/constants.ts | 0
{src => web/src}/pages/Upstream/index.ts | 0
{src => web/src}/pages/Upstream/locales/en-US.ts | 0
{src => web/src}/pages/Upstream/locales/zh-CN.ts | 0
{src => web/src}/pages/Upstream/service.ts | 0
{src => web/src}/pages/Upstream/transform.ts | 6 +-
{src => web/src}/pages/Upstream/typing.d.ts | 4 +-
{src => web/src}/pages/User/Login.less | 0
{src => web/src}/pages/User/Login.tsx | 0
{src => web/src}/pages/User/Logout.tsx | 0
.../pages/User/components/LoginMethodExample.tsx | 0
.../pages/User/components/LoginMethodPassword.tsx | 0
{src => web/src}/pages/User/index.ts | 0
{src => web/src}/pages/User/locales/en-US.ts | 0
{src => web/src}/pages/User/locales/zh-CN.ts | 0
{src => web/src}/pages/User/typing.d.ts | 0
{src => web/src}/pages/document.ejs | 0
{src => web/src}/service-worker.js | 0
{src => web/src}/services/API.d.ts | 0
{src => web/src}/services/user.ts | 0
{src => web/src}/typings.d.ts | 0
{tests => web/tests}/PuppeteerEnvironment.js | 0
{tests => web/tests}/beforeTest.js | 0
{tests => web/tests}/getBrowser.js | 0
{tests => web/tests}/run-tests.js | 0
tsconfig.json => web/tsconfig.json | 0
yarn.lock => web/yarn.lock | 227 +-
260 files changed, 8904 insertions(+), 4419 deletions(-)
diff --git a/.actions/ASF-Release.cfg b/.actions/ASF-Release.cfg
index 1ac4118..bed65bf 100644
--- a/.actions/ASF-Release.cfg
+++ b/.actions/ASF-Release.cfg
@@ -68,16 +68,16 @@ ASFLicenseHeaderLua.txt
.tox
# Skip files containing MIT License
-scripts/verifyCommit.js
-src/components/HeaderDropdown/index.less
-src/components/HeaderDropdown/index.tsx
-src/components/NoticeIcon
-src/components/PageLoading/index.tsx
-src/components/RightContent
-src/e2e/__mocks__/antd-pro-merge-less.js
-src/e2e/baseLayout.e2e.js
-src/pages/404.tsx
-src/service-worker.js
+web/scripts/verifyCommit.js
+web/src/components/HeaderDropdown/index.less
+web/src/components/HeaderDropdown/index.tsx
+web/src/components/NoticeIcon
+web/src/components/PageLoading/index.tsx
+web/src/components/RightContent
+web/src/e2e/__mocks__/antd-pro-merge-less.js
+web/src/e2e/baseLayout.e2e.js
+web/src/pages/404.tsx
+web/src/service-worker.js
api/build-tools/json.lua
# Skip files containing Apache 2.0 License
diff --git a/.asf.yaml b/.asf.yaml
index b2617d9..59b805a 100644
--- a/.asf.yaml
+++ b/.asf.yaml
@@ -24,7 +24,6 @@ github:
- api-management
- apisix
- devops
- - docker
enabled_merge_buttons:
squash: true
diff --git a/.dockerignore b/.dockerignore
index 3c3629e..cf70988 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1 +1 @@
-node_modules
+**/node_modules
diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE
deleted file mode 100644
index b3c0269..0000000
--- a/.github/ISSUE_TEMPLATE
+++ /dev/null
@@ -1,23 +0,0 @@
-Please answer these questions before submitting your issue.
-
-- Why do you submit this issue?
-- [ ] Question or discussion
-- [ ] Bug
-- [ ] Requirements
-- [ ] Feature or performance improvement
-- [ ] Other
-
-___
-### Question
-- What do you want to know?
-
-___
-### Bug
-- Which version of Apache APISIX Dashboard, OS, and Browser?
-
-- What happened?
-If possible, provide a way to reproduce the error.
-
-___
-### Requirements or improvement
-- Please describe your requirements or improvement suggestions.
diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md
new file mode 100644
index 0000000..cf887b7
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug-report.md
@@ -0,0 +1,36 @@
+---
+name: Bug report
+about: Create a bug report for the Apache APISIX Dashboard
+labels: "bug"
+---
+
+# Bug report
+
+## Describe the bug
+
+A clear and concise description of what the bug is.
+
+## How to Reproduce
+
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+## Expected behavior
+
+A clear and concise description of what you expected to happen.
+
+## Screenshots
+
+Add screenshots to help explain your problem if applicable.
+
+## System information
+
+- OS: [e.g. macOS, Windows]
+- Browser (if applies) [e.g. Chrome, Safari, Edge]
+- Version: [e.g. 2.0-rc3]
+
+## Additional context
+
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..216f73c
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,5 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Visit Apache APISIX
+ url: https://github.com/apache/apisix
+ about: Ask questions or discuss with other community members about Apache APISIX
diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md
new file mode 100644
index 0000000..aa019dc
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature-request.md
@@ -0,0 +1,23 @@
+---
+name: Feature request
+about: Create a feature request for the Apache APISIX Dashboard
+labels: 'feature'
+---
+
+# Feature request
+
+## Please describe your feature
+
+A clear and concise description of what you want and what your use case is.
+
+## Describe the solution you'd like
+
+A clear and concise description of what you want to happen.
+
+## Describe alternatives you've considered
+
+A clear and concise description of any alternative solutions or features you've considered.
+
+## Additional context
+
+Add any other context or screenshots about the feature request here.
diff --git a/.github/workflows/backend-cli-test.yml b/.github/workflows/backend-cli-test.yml
new file mode 100644
index 0000000..db7fc15
--- /dev/null
+++ b/.github/workflows/backend-cli-test.yml
@@ -0,0 +1,31 @@
+name: Backend CLI Test
+
+on:
+ push:
+ branches:
+ - master
+ - v2.0
+ pull_request:
+ branches:
+ - master
+ - v2.0
+
+jobs:
+ run-test:
+ runs-on: ubuntu-latest
+
+ services:
+ etcd:
+ image: bitnami/etcd:3.4.13
+ ports:
+ - 2379:2379
+ - 2380:2380
+ env:
+ ALLOW_NONE_AUTHENTICATION: yes
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: run test
+ working-directory: ./api
+ run: sudo ./test/shell/cli_test.sh
diff --git a/.github/workflows/backend-e2e-test.yml b/.github/workflows/backend-e2e-test.yml
new file mode 100644
index 0000000..1bfe4ec
--- /dev/null
+++ b/.github/workflows/backend-e2e-test.yml
@@ -0,0 +1,33 @@
+name: Backend E2E Test
+
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ branches:
+ - master
+ - v2.0
+
+jobs:
+ run-test:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: setup go
+ uses: actions/setup-go@v1
+ with:
+ go-version: '1.13'
+
+ - name: run docker compose
+ working-directory: ./api/test/docker
+ run: |
+ docker-compose up -d
+ sleep 5
+ docker logs docker_managerapi_1
+
+ - name: run test
+ working-directory: ./api/test/e2e
+ run: go test
diff --git a/.github/workflows/backend-unit-test.yml b/.github/workflows/backend-unit-test.yml
new file mode 100644
index 0000000..2a8dd83
--- /dev/null
+++ b/.github/workflows/backend-unit-test.yml
@@ -0,0 +1,74 @@
+name: Backend Unit Test
+
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ branches:
+ - master
+ - v2.0
+
+jobs:
+ run-test:
+ runs-on: ubuntu-latest
+
+ services:
+ etcd:
+ image: bitnami/etcd:3.4.13
+ ports:
+ - 2379:2379
+ - 2380:2380
+ env:
+ ALLOW_NONE_AUTHENTICATION: yes
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: get lua lib
+ run: |
+ wget https://github.com/api7/dag-to-lua/archive/v1.1.tar.gz
+ sudo mkdir -p ./api/dag-to-lua
+ tar -zxvf v1.1.tar.gz
+ sudo mv ./dag-to-lua-1.1/lib/* ./api/dag-to-lua/
+
+ - name: setup go
+ uses: actions/setup-go@v1
+ with:
+ go-version: '1.13'
+
+ - name: setup lua
+ run: |
+ sudo apt-get update
+ sudo apt-get install lua5.1
+
+ - name: run test
+ run: |
+ make api-test
+
+ - name: upload coverage profile
+ working-directory: ./api
+ run: |
+ bash <(curl -s https://codecov.io/bash)
+
+ - name: run with custom port
+ working-directory: ./api
+ run: |
+ export GO111MOUDULE=on
+ export APISIX_CONF_PATH=$PWD/conf
+ sed -i 's/8080/8088/' conf/conf.yaml
+ go build -o ./manager-api
+ ./manager-api > ./api.log 2>&1 &
+ sleep 2
+ cat ./api.log
+ cat conf/conf.yaml
+
+ - name: run with custom port
+ working-directory: ./api
+ run: |
+ curl http://127.0.0.1:8088/apisix/admin/user/login -X POST -i -d '{"username":"admin", "password": "admin"}'
+ code=$(curl -k -i -m 20 -o /dev/null -s -w %{http_code} http://127.0.0.1:8088/apisix/admin/user/login -X POST -i -d '{"username":"admin", "password": "admin"}')
+ if [ ! $code -eq 200 ]; then
+ echo "failed: failed to custom port"
+ exit 1
+ fi
diff --git a/.github/workflows/deploy-api.yml b/.github/workflows/deploy-api.yml
deleted file mode 100644
index d996e52..0000000
--- a/.github/workflows/deploy-api.yml
+++ /dev/null
@@ -1,70 +0,0 @@
-name: Deploy API to Azure
-
-on:
- push:
- branches:
- - master
-
-jobs:
- build:
- runs-on: ubuntu-latest
-
- services:
- etcd:
- image: bitnami/etcd:3.3.13-r80
- ports:
- - 2379:2379
- - 2380:2380
- env:
- ALLOW_NONE_AUTHENTICATION: yes
-
- steps:
- - uses: actions/checkout@v2
-
- - name: license check
- run: |
- make license-check
-
- - name: get lua lib
- run: |
- wget https://github.com/api7/dag-to-lua/archive/v1.1.tar.gz
- sudo mkdir -p /go/manager-api/dag-to-lua/
- tar -zxvf v1.1.tar.gz
- sudo mv ./dag-to-lua-1.1/lib/* /go/manager-api/dag-to-lua/
-
- - name: install runtime
- run: |
- sudo apt-get update
- sudo apt-get install lua5.1
- sudo add-apt-repository ppa:longsleep/golang-backports
- sudo apt update
- export GO111MOUDULE=on
- sudo apt install golang-1.14-go
-
- - name: generate json schema
- working-directory: ./api
- run: |
- wget https://github.com/apache/apisix/archive/master.zip
- mkdir -p ./build-tools/apisix/
- unzip master.zip
- sudo mv ./apisix-master/apisix/* ./build-tools/apisix/
- rm -rf ./apisix-master
- cd ./build-tools/ && lua schema-sync.lua > ../conf/schema.json
-
- - name: run test
- working-directory: ./api
- run: |
- export APIX_ETCD_ENDPOINTS=127.0.0.1:2379
- go test ./...
-
- - uses: Azure/docker-login@v1
- with:
- login-server: apisixacr.azurecr.cn
- username: ${{ secrets.REGISTRY_USERNAME }}
- password: ${{ secrets.REGISTRY_PASSWORD }}
-
- - name: build and push docker image
- working-directory: ./api
- run: |
- docker build . -t apisixacr.azurecr.cn/managerapi:${{ github.sha }}
- docker push apisixacr.azurecr.cn/managerapi:${{ github.sha }}
diff --git a/.github/workflows/deploy-frontend.yml b/.github/workflows/deploy-frontend.yml
deleted file mode 100644
index 9998d50..0000000
--- a/.github/workflows/deploy-frontend.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-name: Deploy frontend to Azure
-
-on:
- push:
- branches: [master]
-
-jobs:
- build:
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v2
-
- - uses: Azure/docker-login@v1
- with:
- login-server: apisixacr.azurecr.cn
- username: ${{ secrets.REGISTRY_USERNAME }}
- password: ${{ secrets.REGISTRY_PASSWORD }}
-
- - run: |
- docker build . -t apisixacr.azurecr.cn/dashboard:${{ github.sha }}
- docker push apisixacr.azurecr.cn/dashboard:${{ github.sha }}
diff --git a/.github/workflows/deploy-with-docker.yml b/.github/workflows/deploy-with-docker.yml
new file mode 100644
index 0000000..2dfa41d
--- /dev/null
+++ b/.github/workflows/deploy-with-docker.yml
@@ -0,0 +1,44 @@
+name: Test and Deploy with Docker
+
+on:
+ push:
+ branches:
+ - master
+ - v2.0
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - uses: Azure/docker-login@v1
+ with:
+ login-server: apisixacr.azurecr.cn
+ username: ${{ secrets.REGISTRY_USERNAME }}
+ password: ${{ secrets.REGISTRY_PASSWORD }}
+
+ - name: Build Docker Image
+ run: |
+ docker build -t dashboard:ci .
+
+ - name: Modify ETCD IP
+ run: |
+ sed -i 's/127.0.0.1:2379/172.16.238.10:2379/' api/conf/conf.yaml
+ sed -i 's/host: 127.0.0.1/host: 0.0.0.0/' api/conf/conf.yaml
+
+ - name: Run Docker Compose
+ working-directory: ./api/test/docker-deploy
+ run: |
+ docker-compose up -d
+ sleep 5
+ docker logs docker-deploy_managerapi_1
+
+ - name: Run Test
+ run: api/test/shell/docker_deploy_test.sh
+
+ - name: Deploy
+ run: |
+ docker tag dashboard:ci apisixacr.azurecr.cn/dashboard:${{ github.sha }}
+ docker push apisixacr.azurecr.cn/dashboard:${{ github.sha }}
diff --git a/.github/workflows/frontend-e2e-test.yml b/.github/workflows/frontend-e2e-test.yml
new file mode 100644
index 0000000..1753ac2
--- /dev/null
+++ b/.github/workflows/frontend-e2e-test.yml
@@ -0,0 +1,40 @@
+name: Frontend e2e test
+
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ branches:
+ - master
+ - v2.0
+defaults:
+ run:
+ working-directory: web
+
+jobs:
+ web-e2e:
+ name: Frontend e2e test
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ - name: Cache or restore node_modules
+ id: node_modules_cache_id
+ uses: actions/cache@v2
+ with:
+ path: "**/node_modules"
+ key: ${{ runner.os }}-node_modules-${{ hashFiles('**/yarn.lock') }}
+
+ - name: Setup Node.js environment
+ uses: actions/setup-node@v1
+ with:
+ node-version: 14.x
+
+ - name: Install dependencies
+ if: steps.node_modules_cache_id.outputs.cache-hit != 'true'
+ run: yarn install
+
+ - name: Start frontend then test
+ run: yarn test:e2e
diff --git a/.github/workflows/license-checker.yml b/.github/workflows/go-lint.yml
similarity index 59%
copy from .github/workflows/license-checker.yml
copy to .github/workflows/go-lint.yml
index 09b2cba..0de9fe3 100644
--- a/.github/workflows/license-checker.yml
+++ b/.github/workflows/go-lint.yml
@@ -1,20 +1,20 @@
-name: License checker
-
+name: go-lint
on:
push:
branches:
- master
+ - v2.0
pull_request:
branches:
- master
+ - v2.0
jobs:
- check-license:
+ golangci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- - name: run license check
- run: |
- make license-check
+ - name: run lint
+ run: make go-lint
diff --git a/.github/workflows/license-checker.yml b/.github/workflows/license-checker.yml
index 09b2cba..b6e6c75 100644
--- a/.github/workflows/license-checker.yml
+++ b/.github/workflows/license-checker.yml
@@ -7,6 +7,7 @@ on:
pull_request:
branches:
- master
+ - v2.0
jobs:
check-license:
diff --git a/.github/workflows/test-api.yml b/.github/workflows/test-api.yml
deleted file mode 100644
index 386c52d..0000000
--- a/.github/workflows/test-api.yml
+++ /dev/null
@@ -1,61 +0,0 @@
-name: Test API
-
-on:
- push:
- branches:
- - master
- pull_request:
- branches:
- - master
-
-jobs:
- run-test:
- runs-on: ubuntu-latest
-
- services:
- etcd:
- image: bitnami/etcd:3.4.13
- ports:
- - 2379:2379
- - 2380:2380
- env:
- ALLOW_NONE_AUTHENTICATION: yes
-
- steps:
- - uses: actions/checkout@v2
-
- - name: run Makefile
- run: |
- make license-check
-
- - name: get lua lib
- run: |
- wget https://github.com/api7/dag-to-lua/archive/v1.1.tar.gz
- sudo mkdir -p /go/manager-api/dag-to-lua/
- tar -zxvf v1.1.tar.gz
- sudo mv ./dag-to-lua-1.1/lib/* /go/manager-api/dag-to-lua/
-
- - name: install runtime
- run: |
- sudo apt-get update
- sudo apt-get install lua5.1
- sudo add-apt-repository ppa:longsleep/golang-backports
- sudo apt update
- export GO111MOUDULE=on
- sudo apt install golang-1.14-go
-
- - name: generate json schema
- working-directory: ./api
- run: |
- wget https://github.com/apache/apisix/archive/master.zip
- mkdir -p ./build-tools/apisix/
- unzip master.zip
- sudo mv ./apisix-master/apisix/* ./build-tools/apisix/
- rm -rf ./apisix-master
- cd ./build-tools/ && lua schema-sync.lua > ../conf/schema.json
-
- - name: run test
- working-directory: ./api
- run: |
- export APIX_ETCD_ENDPOINTS=127.0.0.1:2379
- go test ./...
diff --git a/.github/workflows/test-deploy-with-go.yml b/.github/workflows/test-deploy-with-go.yml
deleted file mode 100644
index 59fefbb..0000000
--- a/.github/workflows/test-deploy-with-go.yml
+++ /dev/null
@@ -1,73 +0,0 @@
-name: Test deploy frontend and API using Go
-
-on:
- push:
- branches:
- - master
- pull_request:
- branches:
- - master
-
-jobs:
- frontend:
- name: Front-End compile
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
-
- - name: Setup Node.JS environment for Front-End
- uses: actions/setup-node@v1
- with:
- node-version: 14.x
-
- - name: Install Front-End dependencies
- run: yarn install
-
- - name: Build Front-End
- run: yarn build
-
- - name: Store Compiled Front-End files
- uses: actions/upload-artifact@v2
- with:
- name: dist
- path: ./dist/
-
- backend:
- name: Back-End compile
- needs: frontend
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v2
-
- - name: Copy file to Back-End compile environment
- uses: actions/download-artifact@v2
- with:
- name: dist
- path: ./api/dashboard/
-
- - name: Setup Golang environment for Back-End
- uses: actions/setup-go@v2
- with:
- go-version: 1.14
-
- - name: Setup Build Environment
- run: |
- cd ./api/
- sudo go get github.com/rakyll/statik
-
- - name: Generate Built-in Code
- run: |
- cd ./api/
- $(go env GOPATH)/bin/statik -src=./dashboard/
-
- - name: Build Back-End Binary
- run: |
- cd ./api/
- sudo go build -o /go/manager-api/manager-api
-
- - name: Store Compiled Back-End files
- uses: actions/upload-artifact@v2
- with:
- name: output
- path: /go/manager-api/manager-api
diff --git a/.github/workflows/test-frontend-multiple-node-build.yml b/.github/workflows/test-frontend-multiple-node-build.yml
index b631398..1c6aa38 100644
--- a/.github/workflows/test-frontend-multiple-node-build.yml
+++ b/.github/workflows/test-frontend-multiple-node-build.yml
@@ -1,6 +1,6 @@
# This is a basic test to build the dashboard
-name: Test building frontend in multiple node version
+name: Test building web in multiple node version
# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
@@ -11,6 +11,7 @@ on:
pull_request:
branches:
- master
+ - v2.0
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
@@ -34,10 +35,13 @@ jobs:
# Install dependencies
- name: Install dependencies
+ working-directory: web
run: yarn
- - name: Build the Dashboard
- run: yarn build
-
- name: Lint
+ working-directory: web
run: yarn run lint:js && yarn run lint:style
+
+ - name: Build the Dashboard
+ working-directory: web
+ run: yarn build
diff --git a/.gitignore b/.gitignore
index 571eb5b..06ac7fe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,8 +7,7 @@
_roadhog-api-doc
# production
-/dist
-/.vscode
+dist
# misc
.DS_Store
@@ -19,7 +18,6 @@ yarn-error.log
.idea
package-lock.json
*bak
-.vscode
# visual studio code
.history
@@ -42,5 +40,8 @@ build
/compose/**/nginx.pid
/compose/etcd_data
manager-api
-conf.json
-conf.json-e
+
+output
+default.etcd
+api/build-tools/apisix
+/*.zip
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..e521849
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,8 @@
+{
+ "eslint.validate": [
+ "javascript",
+ "javascriptreact",
+ { "language": "typescript", "autoFix": true },
+ { "language": "typescriptreact", "autoFix": true }
+ ]
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4553526..a6a0fa2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,9 +19,33 @@
# Table of Contents
+- [2.0.0](#200)
- [1.5.0](#150)
- [1.0.0](#100)
+# 2.0.0
+
+This is a release candidate.
+
+# Core
+
+- Refactor frontend with Admin-API.
+- Manager-API removes dependency on MySQL.
+- Support plugin orchestration.
+- Setting standards for frontend internationalization.
+- New deployment pattern.
+- Add more test cases.
+- Document Enhancement.
+- Add back-end E2E test examples.
+- Improve CI testing.
+- Support log save to local file.
+- Optimize the deployment process.
+- Add E2E test examples to the frontend. [#619](https://github.com/apache/apisix-dashboard/pull/619)
+- Fix the Promethues plugin updating incorrect values when updating routes. [#666](https://github.com/apache/apisix-dashboard/pull/666)
+- Fix page display exceptions when the Redirect option is selected as Enable HTTPS in the Route page. [#692](https://github.com/apache/apisix-dashboard/pull/692)
+
+For more changes, please refer to [Milestone](https://github.com/apache/apisix-dashboard/milestone/4)
+
# 1.5.0
This release mainly refactors the dashboard.
diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md
index 774e199..378f9df 100644
--- a/CHANGELOG.zh-CN.md
+++ b/CHANGELOG.zh-CN.md
@@ -19,9 +19,35 @@
# 目录
+- [2.0.0](#200)
- [1.5.0](#150)
- [1.0.0](#100)
+
+# 2.0.0
+
+这是一个候选版本。
+
+### 核心
+
+- 前端根据新的 admin-api 进行重构。
+- 后端移除对 mysql 的依赖。
+- 支持插件编排模式。
+- 制定前端国际化标准。
+- Dashboard 新的部署方式。
+- 增加更多测试用例。
+- 文档增强。
+- 添加后端 E2E 测试例子。
+- 完善 CI 测试。
+- 支持日志保存到本地文件。
+- 优化部署流程。
+- 前端增加 E2E 测试例子。[#619](https://github.com/apache/apisix-dashboard/pull/619)
+- 修复 Promethues 插件在更新路由时更新错误值的问题。[#666](https://github.com/apache/apisix-dashboard/pull/666)
+- 修复在路由页面中重定向选项选择为 启用HTTPS 时页面显示异常的问题。[#692](https://github.com/apache/apisix-dashboard/pull/692)
+
+
+更多的变动可以参考[里程碑](https://github.com/apache/apisix-dashboard/milestone/4)
+
# 1.5.0
该版本主要完成 Dashboard 的重构工作。
diff --git a/Dockerfile b/Dockerfile
index 90d4fde..a1e219f 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -14,24 +14,71 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+FROM alpine:latest as pre-build
-# phase-build
-FROM node:12 as builder
+ARG APISIX_DASHBOARD_VERSION=v2.0
-WORKDIR /usr/src/app/
-USER root
+RUN set -x \
+ && wget https://github.com/apache/apisix-dashboard/archive/${APISIX_DASHBOARD_VERSION}.tar.gz -O /tmp/apisix-dashboard.tar.gz \
+ && mkdir /usr/local/apisix-dashboard \
+ && tar -xvf /tmp/apisix-dashboard.tar.gz -C /usr/local/apisix-dashboard --strip 1
-COPY package.json ./
-COPY yarn.lock ./
-RUN yarn
+FROM golang:1.14 as api-builder
-COPY ./ ./
-RUN yarn build && rm -rf /usr/src/app/node_modules
+ARG ENABLE_PROXY=false
-# phase-run
-FROM nginx:1.16-alpine
+WORKDIR /usr/local/apisix-dashboard
-COPY ./docker/nginx.conf /etc/nginx/conf.d/default.conf
-COPY --from=builder /usr/src/app/dist /usr/share/nginx/html
+COPY --from=pre-build /usr/local/apisix-dashboard .
-EXPOSE 80
+WORKDIR /usr/local/apisix-dashboard/api
+
+RUN mkdir -p ../output/conf \
+ && cp ./conf/*.json ../output/conf
+
+RUN wget https://github.com/api7/dag-to-lua/archive/v1.1.tar.gz -O /tmp/v1.1.tar.gz \
+ && mkdir /tmp/dag-to-lua \
+ && tar -xvf /tmp/v1.1.tar.gz -C /tmp/dag-to-lua --strip 1 \
+ && mkdir -p ../output/dag-to-lua \
+ && mv /tmp/dag-to-lua/lib/* ../output/dag-to-lua/
+
+RUN if [ "$ENABLE_PROXY" = "true" ] ; then go env -w GOPROXY=https://goproxy.io,direct ; fi
+
+RUN go env -w GO111MODULE=on \
+ && CGO_ENABLED=0 go build -o ../output/manager-api .
+
+FROM node:14-alpine as fe-builder
+
+ARG ENABLE_PROXY=false
+
+WORKDIR /usr/local/apisix-dashboard
+
+COPY --from=pre-build /usr/local/apisix-dashboard .
+
+WORKDIR /usr/local/apisix-dashboard/web
+
+RUN if [ "$ENABLE_PROXY" = "true" ] ; then yarn config set registry https://registry.npm.taobao.org/ ; fi
+
+RUN yarn install
+
+RUN yarn build
+
+FROM alpine:latest as prod
+
+ARG ENABLE_PROXY=false
+
+RUN if [ "$ENABLE_PROXY" = "true" ] ; then sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories ; fi
+
+RUN apk add lua5.1
+
+WORKDIR /usr/local/apisix-dashboard
+
+COPY --from=api-builder /usr/local/apisix-dashboard/output/ ./
+
+COPY --from=fe-builder /usr/local/apisix-dashboard/output/ ./
+
+RUN mkdir logs
+
+EXPOSE 8080
+
+CMD [ "/usr/local/apisix-dashboard/manager-api" ]
diff --git a/Makefile b/Makefile
index c55fedb..7eee57c 100644
--- a/Makefile
+++ b/Makefile
@@ -15,11 +15,105 @@
# limitations under the License.
#
-### license-check: Check apisix-dashboard source codes for Apache License
+SHELL := /bin/bash -o pipefail
+UNAME ?= $(shell uname)
+YARN_EXEC ?= $(shell which yarn)
+GO_EXEC ?= $(shell which go)
+
+VERSION ?= latest
+RELEASE_SRC = apache-apisix-dashboard-${VERSION}-src
+
+export GO111MODULE=on
+
+### help: Show Makefile rules
+.PHONY: help
+help:
+ @echo Makefile rules:
+ @echo
+ @grep -E '^### [-A-Za-z0-9_]+:' Makefile | sed 's/###/ /'
+
+
+### build: Build Apache APISIX Dashboard, it contains web and manager-api
+.PHONY: build
+build: web-default api-default
+ api/build.sh && cd ./web && export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true && yarn install && yarn build && mkdir -p ../output/logs
+
+
+.PHONY: web-default
+web-default:
+ifeq ("$(wildcard $(YARN_EXEC))", "")
+ @echo "ERROR: Need to install yarn first"
+ exit 1
+endif
+
+
+.PHONY: api-default
+api-default:
+ifeq ("$(wildcard $(GO_EXEC))", "")
+ @echo "ERROR: Need to install golang 1.13+ first"
+ exit 1
+endif
+
+
+### api-test: Run the tests of manager-api
+.PHONY: api-test
+api-test: api-default
+ cd api/ && APISIX_API_WORKDIR=$$PWD go test -v -race -cover -coverprofile=coverage.txt -covermode=atomic ./...
+
+
+### api-run: Run the manager-api
+.PHONY: api-run
+api-run: api-default
+ cd api/ && go run .
+
+### api-stop: Stop the manager-api
+api-stop:
+ kill $(ps aux | grep 'manager-api' | awk '{print $2}')
+
+
+### go-lint: Lint Go source code
+.PHONY: go-lint
+go-lint: ## Run the golangci-lint application (install if not found)
+ @#Brew - MacOS
+ @if [ "$(shell command -v golangci-lint)" = "" ] && [ "$(shell command -v brew)" != "" ] && [ "$(UNAME)" = "Darwin" ]; then brew install golangci-lint; fi;
+ @#has sudo
+ @if [ "$(shell command -v golangci-lint)" = "" ]; then curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.32.0 && sudo cp ./bin/golangci-lint $(go env GOPATH)/bin/; fi;
+ @echo "running golangci-lint..."
+ @cd api && golangci-lint run --tests=false ./...
+
+
+### license-check: Check Apache APISIX Dashboard Source Codes for Apache License
.PHONY: license-check
license-check:
ifeq ("$(wildcard .actions/openwhisk-utilities/scancode/scanCode.py)", "")
git clone https://github.com/apache/openwhisk-utilities.git .actions/openwhisk-utilities
cp .actions/ASF* .actions/openwhisk-utilities/scancode/
endif
- .actions/openwhisk-utilities/scancode/scanCode.py --config .actions/ASF-Release.cfg ./
\ No newline at end of file
+ .actions/openwhisk-utilities/scancode/scanCode.py --config .actions/ASF-Release.cfg ./
+
+
+.PHONY: release-src
+release-src:
+ git clean -Xdf
+ tar -zcvf $(RELEASE_SRC).tgz \
+ --exclude .github \
+ --exclude .git \
+ --exclude .gitattributes \
+ --exclude .idea \
+ --exclude .vscode \
+ --exclude .gitignore \
+ --exclude .DS_Store \
+ --exclude docs \
+ --exclude release \
+ --exclude api/internal/core/store/validate_mock.go \
+ --exclude api/internal/core/storage/storage_mock.go \
+ .
+
+ gpg --batch --yes --armor --detach-sig $(RELEASE_SRC).tgz
+ shasum -a 512 $(RELEASE_SRC).tgz > $(RELEASE_SRC).tgz.sha512
+
+ mkdir -p release
+ mv $(RELEASE_SRC).tgz release/$(RELEASE_SRC).tgz
+ mv $(RELEASE_SRC).tgz.asc release/$(RELEASE_SRC).tgz.asc
+ mv $(RELEASE_SRC).tgz.sha512 release/$(RELEASE_SRC).tgz.sha512
+
diff --git a/README.md b/README.md
index ff68f39..ac4e185 100644
--- a/README.md
+++ b/README.md
@@ -21,35 +21,64 @@ English | [简体中文](./README.zh-CN.md)
# Apache APISIX Dashboard
-Dashboard for [Apache APISIX](https://github.com/apache/apisix)
+## What's Apache APISIX Dashboard
-[Online Demo](http://139.217.190.60/), Username/Password: `admin`.
+The Apache APISIX Dashboard is designed to make it as easy as possible for users to operate [Apache APISIX](https://github.com/apache/apisix) through a frontend interface.
-## User Guide
+The Dashboard is the control plane and performs all parameter checks; Apache APISIX mixes data and control planes and will evolve to a pure data plane.
+
+This project includes `manager-api`, which will gradually replace `admin-api` in Apache APISIX.
+
+Note: Currently the Dashboard does not have complete coverage of Apache APISIX features, [visit here](https://github.com/apache/apisix-dashboard/milestones) to view the milestones.
+
+![architecture](./docs/images/architecture.png)
+
+## Project structure
-Please refer to [User Guide](./docs/USER_GUIDE.md)
+```
+.
+├── CHANGELOG.md
+├── CHANGELOG.zh-CN.md
+├── CODE_OF_CONDUCT.md
+├── CONTRIBUTING.md
+├── Dockerfile
+├── LICENSE
+├── Makefile
+├── NOTICE
+├── README.md
+├── README.zh-CN.md
+├── api
+├── docs
+├── licenses
+└── web
+```
-## Deployment
+1. The `api` directory is used to store the `manager-api` source codes, which is used to manage `etcd` and provide APIs to the frontend interface.
+2. The `web` directory is used to store the frontend source codes.
-- [Deploy Manually](./docs/deploy.md)
-- [Deploy with Docker](./compose/README.md)
+## Build then launch
+
+Support the following ways currently.
+
+- [Source Codes](./docs/deploy.md)
+- [Docker](./docs/deploy-with-docker.md)
## Development
-- [Apache APISIX](https://github.com/apache/apisix)
-- [Dashboard](./docs/develop.md)
+Please refer to the [Development Guide](./docs/develop.md).
-## Milestones
+## User Guide
-- [2.0](https://github.com/apache/apisix-dashboard/milestone/4)
-- [2.1](https://github.com/apache/apisix-dashboard/milestone/5)
+Please refer to the [User Guide](./docs/USER_GUIDE.md).
## Contributing
-See [CONTRIBUTING](./CONTRIBUTING.md) for details on submitting patches and the contribution workflow.
+Please refer to the [Contribution Guide](./CONTRIBUTING.md) for a more detailed infomation.
## FAQ
-1. If you need the dashboard-1.0 which is built with Vue.js, please refer to [master-vue](https://github.com/apache/apisix-dashboard/tree/master-vue).
+Please refer to the [FAQ](./docs/FAQ.md) for more known issues.
+
+## License
-2. The dashboard 2.0 removes MySQL which [dashboard 1.5](https://github.com/apache/apisix-dashboard/tree/backup-1.5-latest) is relied on.
+[Apache License 2.0](./LICENSE)
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 9b24761..1d08b84 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -19,38 +19,66 @@
[English](./README.md) | 简体中文
-# [Apache APISIX](https://github.com/apache/apisix) 控制台
+# Apache APISIX Dashboard
-访问 [http://139.217.190.60/](http://139.217.190.60/) 查看在线预览,账户与密码:`admin`。
+## 介绍
-## 用户指南
+Apache APISIX Dashboard 旨在通过前端界面,让用户尽可能更方便地操作 [Apache APISIX](https://github.com/apache/apisix)。
-请参考 [用户指南](./docs/USER_GUIDE.zh-CN.md)
+Dashboard 为控制平面,完成所有参数的校验;Apache APISIX 混合了数据平面与控制平面,会逐渐演进为纯粹的数据平面。
-## 部署
+本项目包含了 `manager-api` 与前端界面,前者将逐渐替代 Apache APISIX 中的 `admin-api`,我们正在积极地迁移相关逻辑。
-当前支持如下方式部署:
+注意:目前 Dashboard 尚未完整覆盖 Apache APISIX 的功能,[访问此处](https://github.com/apache/apisix-dashboard/milestones)以查看里程碑。
-- [手动部署](./docs/deploy.zh-CN.md)
-- [使用 Docker 部署](./compose/README.md)
+![architecture](./docs/images/architecture.png)
-## 开发
+## 目录结构
-开发分为 Apache APISIX 开发、Dashboard 开发
+```
+.
+├── CHANGELOG.md
+├── CHANGELOG.zh-CN.md
+├── CODE_OF_CONDUCT.md
+├── CONTRIBUTING.md
+├── Dockerfile
+├── LICENSE
+├── Makefile
+├── NOTICE
+├── README.md
+├── README.zh-CN.md
+├── api
+├── docs
+├── licenses
+└── web
+```
-- [Apache APISIX](https://github.com/apache/apisix)
-- [Dashboard](./docs/develop.zh-CN.md)
+1. `api` 目录用于存放 `manager-api` 源码,它用于管理 `etcd` 并为前端界面提供接口。
+2. `web` 目录用于存放前端源码。
-## 里程碑
+## 构建并启动
-- [2.0](https://github.com/apache/apisix-dashboard/milestone/4)
-- [2.1](https://github.com/apache/apisix-dashboard/milestone/5)
+支持以下方式:
-## 贡献
+- [源码](./docs/deploy.zh-CN.md)
+- [Docker](./docs/deploy-with-docker.zh-CN.md)
-请参考[贡献指南](./CONTRIBUTING.md)以获取更详细的流程。
+## 本地开发
+
+请参考[开发指南](./docs/develop.zh-CN.md)
+
+## 使用指南
+
+请参考[用户指南](./docs/USER_GUIDE.zh-CN.md)
+
+## 参与贡献
+
+请参考[贡献指南](./CONTRIBUTING.md)以获取更详细的流程
## FAQ
-1. 如果你需要 Vue.js 构建的 dashboard-1.0,请使用 [master-vue 分支](https://github.com/apache/apisix-dashboard/tree/master-vue)。
-2. 2.0 版本的控制台移除了[1.5 版本](https://github.com/apache/apisix-dashboard/tree/backup-1.5-latest)中的 MySQL,将直接操作 etcd。
+请参考 [FAQ 汇总](./docs/FAQ.zh-CN.md)以查看更多已知问题
+
+## License
+
+[Apache License 2.0](./LICENSE)
diff --git a/api/build-tools/schema-sync.lua b/api/build-tools/schema-sync.lua
index 257d220..aa65c2b 100644
--- a/api/build-tools/schema-sync.lua
+++ b/api/build-tools/schema-sync.lua
@@ -29,6 +29,7 @@ local fake_module_list = {
'pb',
'prometheus',
'protoc',
+ 'skywalking.tracer',
'resty.cookie',
'resty.core.regex',
@@ -61,7 +62,8 @@ local fake_module_list = {
'apisix.plugins.skywalking.tracer',
'apisix.plugins.zipkin.codec',
'apisix.plugins.zipkin.random_sampler',
- 'apisix.plugins.zipkin.reporter'
+ 'apisix.plugins.zipkin.reporter',
+ 'apisix.timers'
}
for _, name in ipairs(fake_module_list) do
package.loaded[name] = {}
@@ -77,7 +79,11 @@ ngx.re = {}
ngx.timer = {}
ngx.location = {}
ngx.socket = {}
+ngx.thread = {}
ngx.re.gmatch = empty_function
+ngx.shared = {
+ ["plugin-api-breaker"] = {}
+}
-- additional define for management
local time_def = {
@@ -127,7 +133,12 @@ local plugins = get_plugin_list()
for idx, plugin_name in pairs(plugins) do
local plugin = require("apisix.plugins." .. plugin_name)
if plugin and type(plugin) == "table" and plugin.schema then
- schema_all.plugins[plugin_name] = plugin.schema
+ schema_all.plugins[plugin_name]= {
+ ['schema'] = plugin.schema
+ }
+ end
+ if plugin and type(plugin) == "table" and plugin.consumer_schema then
+ schema_all.plugins[plugin_name]['consumer_schema'] = plugin.consumer_schema
end
end
diff --git a/api/entry.sh b/api/build-tools/schema-sync.sh
similarity index 54%
copy from api/entry.sh
copy to api/build-tools/schema-sync.sh
index 8f7afbd..a9a856d 100755
--- a/api/entry.sh
+++ b/api/build-tools/schema-sync.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/usr/bin/env bash
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
@@ -16,22 +16,33 @@
# limitations under the License.
#
-pwd=`pwd`
-
-# config
-cp ${pwd}/api/conf/conf_preview.json ${pwd}/conf.json
-
-# export APIX_DAG_LIB_PATH="${pwd}/dag-to-lua-1.1/lib/"
-# export APIX_ETCD_ENDPOINTS="127.0.0.1:2379"
+set -ex
-export SYSLOG_HOST=127.0.0.1
+pwd=`pwd`
-if [[ "$unamestr" == 'Darwin' ]]; then
- sed -i '' -e "s%#syslogAddress#%`echo $SYSLOG_HOST`%g" ${pwd}/conf.json
+if [[ -n $1 && -d "$1" ]]; then
+ path=$1
+ if [[ -d "${path}/apisix" ]]; then
+ cp -R ${path}/apisix/ ./api/build-tools/apisix/
+ else
+ cp -R ${path}/ ./api/build-tools/apisix/
+ fi
else
- sed -i -e "s%#syslogAddress#%`echo $SYSLOG_HOST`%g" ${pwd}/conf.json
+ version="master"
+ if [[ -n $1 ]]; then
+ version=$1
+ fi
+ wget -O $version.zip https://github.com/apache/apisix/archive/$version.zip
+
+ unzip $version.zip
+ mkdir -p ./api/build-tools/apisix/
+ cp -R ./apisix-$version/apisix/ ./api/build-tools/
+ rm -rf ./apisix-$version
fi
-cp ${pwd}/conf.json ${pwd}/api/conf/conf.json
+cd ./api/build-tools/ && lua schema-sync.lua > ${pwd}/api/conf/schema.json && cd ../../
+
+rm -rf ./api/build-tools/apisix/
-exec ./manager-api
+echo "sync success:"
+echo "${pwd}/api/conf/schema.json"
diff --git a/compose/manager_conf/entry.sh b/api/build.sh
similarity index 58%
rename from compose/manager_conf/entry.sh
rename to api/build.sh
index 34ca263..811eb84 100755
--- a/compose/manager_conf/entry.sh
+++ b/api/build.sh
@@ -1,3 +1,4 @@
+#!/usr/bin/env bash
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
@@ -14,25 +15,23 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-
-#!/bin/sh
-
+set -ex
+export ENV=local
pwd=`pwd`
-# config
-cp ${pwd}/api/conf/conf_preview.json ${pwd}/conf.json
-
-export APIX_ETCD_ENDPOINTS="192.17.5.10:2379"
+rm -rf output && mkdir -p output/conf && mkdir -p output/dag-to-lua
-export SYSLOG_HOST=127.0.0.1
-
-if [[ "$unamestr" == 'Darwin' ]]; then
- sed -i '' -e "s%#syslogAddress#%`echo $SYSLOG_HOST`%g" ${pwd}/conf.json
-else
- sed -i -e "s%#syslogAddress#%`echo $SYSLOG_HOST`%g" ${pwd}/conf.json
+# get dag-to-lua lib
+if [[ ! -f "dag-to-lua-1.1/lib/dag-to-lua.lua" ]]; then
+ wget https://github.com/api7/dag-to-lua/archive/v1.1.tar.gz -P /tmp
+ tar -zxvf /tmp/v1.1.tar.gz -C /tmp
+ cp -r /tmp/dag-to-lua-1.1/lib/* ./output/dag-to-lua
fi
-cp ${pwd}/conf.json ${pwd}/api/conf/conf.json
+# build
+cd ./api && go build -o ../output/manager-api . && cd ..
+
+cp ./api/conf/schema.json ./output/conf/schema.json
+cp ./api/conf/conf.yaml ./output/conf/conf.yaml
-cd /go/manager-api
-exec ./manager-api
+echo "Build the Manager API successfully"
diff --git a/api/conf/conf.go b/api/conf/conf.go
index 84c509f..91eb89b 100644
--- a/api/conf/conf.go
+++ b/api/conf/conf.go
@@ -17,114 +17,163 @@
package conf
import (
+ "flag"
"fmt"
"io/ioutil"
+ "log"
"os"
"path/filepath"
- "runtime"
"github.com/tidwall/gjson"
+ "gopkg.in/yaml.v2"
"github.com/apisix/manager-api/internal/utils"
)
const (
- ServerPort = 8080
- WebDir = "./dist"
-
EnvPROD = "prod"
EnvBETA = "beta"
EnvDEV = "dev"
EnvLOCAL = "local"
- confPath = "/go/manager-api/conf.json"
- schemaPath = "/go/manager-api/schema.json"
+ WebDir = "./html"
)
var (
- ENV string
- basePath string
- Schema gjson.Result
- DagLibPath = "/go/manager-api/dag-to-lua/"
+ ENV string
+ Schema gjson.Result
+ WorkDir = "."
+ ServerHost = "127.0.0.1"
+ ServerPort = 80
+ ETCDEndpoints = []string{"127.0.0.1:2379"}
+ ErrorLogLevel = "warn"
+ ErrorLogPath = "logs/error.log"
+ UserList = make(map[string]User, 2)
+ AuthConf Authentication
+ SSLDefaultStatus = 1 //enable ssl by default
)
-func init() {
- setEnvironment()
- initAuthentication()
- initSchema()
+type Etcd struct {
+ Endpoints []string
}
-func setEnvironment() {
- if env := os.Getenv("ENV"); env == "" {
- ENV = EnvLOCAL
- } else {
- ENV = env
- }
-
- if env := os.Getenv("APIX_DAG_LIB_PATH"); env != "" {
- DagLibPath = env
- }
+type Listen struct {
+ Host string
+ Port int
+}
- _, basePath, _, _ = runtime.Caller(1)
+type ErrorLog struct {
+ Level string
+ FilePath string `yaml:"file_path"`
}
-func configurationPath() string {
- if ENV == EnvLOCAL {
- return filepath.Join(filepath.Dir(basePath), "conf.json")
- } else {
- return confPath
- }
+type Log struct {
+ ErrorLog ErrorLog `yaml:"error_log"`
}
-func getSchemaPath() string {
- if ENV == EnvLOCAL {
- return filepath.Join(filepath.Dir(basePath), "schema.json")
- } else {
- return schemaPath
- }
+type Conf struct {
+ Etcd Etcd
+ Listen Listen
+ Log Log
}
-type user struct {
+type User struct {
Username string
Password string
}
-type authenticationConfig struct {
- Session struct {
- Secret string
- ExpireTime uint64
- }
+type Authentication struct {
+ Secret string
+ ExpireTime int `yaml:"expire_time"`
+ Users []User
}
-var UserList = make(map[string]user, 1)
+type Config struct {
+ Conf Conf
+ Authentication Authentication
+}
-var AuthenticationConfig authenticationConfig
+func init() {
+ //go test
+ if workDir := os.Getenv("APISIX_API_WORKDIR"); workDir != "" {
+ WorkDir = workDir
+ } else {
+ flag.StringVar(&WorkDir, "p", ".", "current work dir")
+ flag.Parse()
+ }
-func initAuthentication() {
- filePath := configurationPath()
- configurationContent, err := ioutil.ReadFile(filePath)
- if err != nil {
+ setConf()
+ setEnvironment()
+ initSchema()
+}
+
+func setConf() {
+ filePath := WorkDir + "/conf/conf.yaml"
+ if configurationContent, err := ioutil.ReadFile(filePath); err != nil {
panic(fmt.Sprintf("fail to read configuration: %s", filePath))
+ } else {
+ //configuration := gjson.ParseBytes(configurationContent)
+ config := Config{}
+ err := yaml.Unmarshal(configurationContent, &config)
+ if err != nil {
+ log.Printf("conf: %s, error: %v", configurationContent, err)
+ }
+
+ //listen
+ if config.Conf.Listen.Port != 0 {
+ ServerPort = config.Conf.Listen.Port
+ }
+
+ if config.Conf.Listen.Host != "" {
+ ServerHost = config.Conf.Listen.Host
+ }
+
+ //etcd
+ if len(config.Conf.Etcd.Endpoints) > 0 {
+ ETCDEndpoints = config.Conf.Etcd.Endpoints
+ }
+
+ //error log
+ if config.Conf.Log.ErrorLog.Level != "" {
+ ErrorLogLevel = config.Conf.Log.ErrorLog.Level
+ }
+ if config.Conf.Log.ErrorLog.FilePath != "" {
+ ErrorLogPath = config.Conf.Log.ErrorLog.FilePath
+ }
+ if !filepath.IsAbs(ErrorLogPath) {
+ ErrorLogPath, err = filepath.Abs(WorkDir + "/" + ErrorLogPath)
+ if err != nil {
+ panic(err)
+ }
+ }
+
+ //auth
+ initAuthentication(config.Authentication)
}
+}
- configuration := gjson.ParseBytes(configurationContent)
- userList := configuration.Get("authentication.user").Array()
- // create user list
- for _, item := range userList {
- username := item.Map()["username"].String()
- password := item.Map()["password"].String()
- UserList[item.Map()["username"].String()] = user{Username: username, Password: password}
+func setEnvironment() {
+ ENV = EnvPROD
+ if env := os.Getenv("ENV"); env != "" {
+ ENV = env
}
- AuthenticationConfig.Session.Secret = configuration.Get("authentication.session.secret").String()
- if "secret" == AuthenticationConfig.Session.Secret {
- AuthenticationConfig.Session.Secret = utils.GetFlakeUidStr()
+}
+
+func initAuthentication(conf Authentication) {
+ AuthConf = conf
+ if AuthConf.Secret == "secret" {
+ AuthConf.Secret = utils.GetFlakeUidStr()
}
- AuthenticationConfig.Session.ExpireTime = configuration.Get("authentication.session.expireTime").Uint()
+ userList := conf.Users
+ // create user list
+ for _, item := range userList {
+ UserList[item.Username] = item
+ }
}
func initSchema() {
- filePath := getSchemaPath()
+ filePath := WorkDir + "/conf/schema.json"
if schemaContent, err := ioutil.ReadFile(filePath); err != nil {
panic(fmt.Sprintf("fail to read configuration: %s", filePath))
} else {
diff --git a/api/conf/conf.json b/api/conf/conf.json
deleted file mode 100644
index d00c492..0000000
--- a/api/conf/conf.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "conf": {
- "syslog": {
- "host": "127.0.0.1"
- }
- },
- "authentication": {
- "session": {
- "secret": "secret",
- "expireTime": 3600
- },
- "user": [
- {
- "username": "admin",
- "password": "admin"
- },
- {
- "username": "user",
- "password": "user"
- }
- ]
- }
-}
diff --git a/api/conf/conf.yaml b/api/conf/conf.yaml
new file mode 100644
index 0000000..2270e72
--- /dev/null
+++ b/api/conf/conf.yaml
@@ -0,0 +1,41 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+conf:
+ listen:
+ host: 127.0.0.1 # `manager api` listening ip or host name
+ port: 8080 # `manager api` listening port
+ etcd:
+ endpoints: # supports defining multiple etcd host addresses for an etcd cluster
+ - 127.0.0.1:2379
+ log:
+ error_log:
+ level: warn # supports levels, lower to higher: debug, info, warn, error, panic, fatal
+ file_path:
+ logs/error.log # supports relative path, absolute path, standard output
+ # such as: logs/error.log, /tmp/logs/error.log, /dev/stdout, /dev/stderr
+authentication:
+ secret:
+ secret # secret for jwt token generation.
+ # NOTE: Highly recommended to modify this value to protect `manager api`.
+ # if it's default value, when `manager api` start , it will generate a random string to replace it.
+ expire_time: 3600 # jwt token expire time, in second
+ users:
+ - username: admin # username and password for login `manager api`
+ password: admin
+ - username: user
+ password: user
diff --git a/api/conf/conf_preview.json b/api/conf/conf_preview.json
deleted file mode 100644
index eef8683..0000000
--- a/api/conf/conf_preview.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "conf": {
- "syslog": {
- "host": "#syslogAddress#"
- }
- },
- "authentication": {
- "session": {
- "secret": "secret",
- "expireTime": 3600
- },
- "user": [
- {
- "username": "admin",
- "password": "admin"
- },
- {
- "username": "user",
- "password": "user"
- }
- ]
- }
-}
diff --git a/api/conf/schema.json b/api/conf/schema.json
index 087cf4c..a684d3c 100644
--- a/api/conf/schema.json
+++ b/api/conf/schema.json
@@ -1 +1,3499 @@
-{"main":{"upstream_hash_header_schema":{"type":"string","pattern":"^[a-zA-Z0-9-_]+$"},"stream_route":{"type":"object","properties":{"plugins":{"type":"object"},"id":{"anyOf":[{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-zA-Z0-9-_]+$"},{"type":"integer","minimum":1}]},"remote_addr":{"type":"string","anyOf":[{"title":"IPv4","type":"string","pattern":"^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$"},{"title":"IPv4/CIDR","type":"string","pattern":"^[0-9]{1,3}.[0-9]{1,3}.[0-9]{ [...]
+{
+ "main": {
+ "global_rule": {
+ "additionalProperties": false,
+ "type": "object",
+ "required": ["plugins"],
+ "properties": {
+ "id": {
+ "anyOf": [{
+ "maxLength": 64,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9-_]+$",
+ "minLength": 1
+ }, {
+ "minimum": 1,
+ "type": "integer"
+ }]
+ },
+ "plugins": {
+ "type": "object"
+ }
+ }
+ },
+ "upstream": {
+ "properties": {
+ "update_time": {
+ "type": "integer"
+ },
+ "retries": {
+ "minimum": 0,
+ "type": "integer"
+ },
+ "k8s_deployment_info": {
+ "type": "object",
+ "properties": {
+ "port": {
+ "minimum": 0,
+ "type": "number"
+ },
+ "deploy_name": {
+ "description": "k8s deployment name",
+ "type": "string"
+ },
+ "service_name": {
+ "description": "k8s service name",
+ "type": "string"
+ },
+ "namespace": {
+ "description": "k8s namespace",
+ "type": "string"
+ },
+ "backend_type": {
+ "enum": ["svc", "pod"],
+ "type": "string",
+ "default": "pod",
+ "description": "k8s service name"
+ }
+ },
+ "anyOf": [{
+ "required": ["namespace", "deploy_name", "port"]
+ }, {
+ "required": ["namespace", "service_name", "port"]
+ }]
+ },
+ "key": {
+ "description": "the key of chash for dynamic load balancing",
+ "type": "string"
+ },
+ "pass_host": {
+ "default": "pass",
+ "type": "string",
+ "description": "mod of host passing",
+ "enum": ["pass", "node", "rewrite"]
+ },
+ "type": {
+ "type": "string",
+ "description": "algorithms of load balancing",
+ "enum": ["chash", "roundrobin", "ewma"]
+ },
+ "timeout": {
+ "type": "object",
+ "required": ["connect", "send", "read"],
+ "properties": {
+ "send": {
+ "minimum": 0,
+ "type": "number"
+ },
+ "read": {
+ "minimum": 0,
+ "type": "number"
+ },
+ "connect": {
+ "minimum": 0,
+ "type": "number"
+ }
+ }
+ },
+ "checks": {
+ "properties": {
+ "passive": {
+ "properties": {
+ "unhealthy": {
+ "properties": {
+ "http_failures": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 5,
+ "maximum": 254
+ },
+ "timeouts": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 7,
+ "maximum": 254
+ },
+ "http_statuses": {
+ "items": {
+ "minimum": 200,
+ "type": "integer",
+ "maximum": 599
+ },
+ "type": "array",
+ "default": [429, 500, 503],
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "tcp_failures": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 2,
+ "maximum": 254
+ }
+ },
+ "type": "object"
+ },
+ "type": {
+ "type": "string",
+ "default": "http",
+ "enum": ["http", "https", "tcp"]
+ },
+ "healthy": {
+ "properties": {
+ "http_statuses": {
+ "items": {
+ "minimum": 200,
+ "type": "integer",
+ "maximum": 599
+ },
+ "type": "array",
+ "default": [200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 304, 305, 306, 307, 308],
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "successes": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 5,
+ "maximum": 254
+ }
+ },
+ "type": "object"
+ }
+ },
+ "type": "object"
+ },
+ "active": {
+ "properties": {
+ "type": {
+ "type": "string",
+ "default": "http",
+ "enum": ["http", "https", "tcp"]
+ },
+ "timeout": {
+ "default": 1,
+ "type": "number"
+ },
+ "req_headers": {
+ "items": {
+ "uniqueItems": true,
+ "type": "string"
+ },
+ "type": "array",
+ "minItems": 1
+ },
+ "http_path": {
+ "default": "/",
+ "type": "string"
+ },
+ "concurrency": {
+ "default": 10,
+ "type": "integer"
+ },
+ "host": {
+ "pattern": "^\\*?[0-9a-zA-Z-.]+$",
+ "type": "string"
+ },
+ "port": {
+ "minimum": 1,
+ "type": "integer",
+ "maximum": 65535
+ },
+ "unhealthy": {
+ "properties": {
+ "timeouts": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 3,
+ "maximum": 254
+ },
+ "http_failures": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 5,
+ "maximum": 254
+ },
+ "interval": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 0
+ },
+ "http_statuses": {
+ "items": {
+ "minimum": 200,
+ "type": "integer",
+ "maximum": 599
+ },
+ "type": "array",
+ "default": [429, 404, 500, 501, 502, 503, 504, 505],
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "tcp_failures": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 2,
+ "maximum": 254
+ }
+ },
+ "type": "object"
+ },
+ "healthy": {
+ "properties": {
+ "interval": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 0
+ },
+ "http_statuses": {
+ "items": {
+ "minimum": 200,
+ "type": "integer",
+ "maximum": 599
+ },
+ "type": "array",
+ "default": [200, 302],
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "successes": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 2,
+ "maximum": 254
+ }
+ },
+ "type": "object"
+ },
+ "https_verify_certificate": {
+ "default": true,
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+ }
+ },
+ "type": "object",
+ "additionalProperties": false,
+ "anyOf": [{
+ "required": ["active"]
+ }, {
+ "required": ["active", "passive"]
+ }]
+ },
+ "hash_on": {
+ "type": "string",
+ "default": "vars",
+ "enum": ["vars", "header", "cookie", "consumer"]
+ },
+ "upstream_host": {
+ "pattern": "^\\*?[0-9a-zA-Z-.]+$",
+ "type": "string"
+ },
+ "discovery_type": {
+ "description": "discovery type",
+ "type": "string"
+ },
+ "create_time": {
+ "type": "integer"
+ },
+ "name": {
+ "maxLength": 50,
+ "type": "string"
+ },
+ "id": {
+ "anyOf": [{
+ "maxLength": 64,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9-_]+$",
+ "minLength": 1
+ }, {
+ "minimum": 1,
+ "type": "integer"
+ }]
+ },
+ "nodes": {
+ "anyOf": [{
+ "minProperties": 1,
+ "type": "object",
+ "patternProperties": {
+ ".*": {
+ "minimum": 0,
+ "type": "integer",
+ "description": "weight of node"
+ }
+ }
+ }, {
+ "items": {
+ "type": "object",
+ "required": ["host", "port", "weight"],
+ "properties": {
+ "host": {
+ "pattern": "^\\*?[0-9a-zA-Z-.]+$",
+ "type": "string"
+ },
+ "port": {
+ "minimum": 1,
+ "type": "integer",
+ "description": "port of node"
+ },
+ "metadata": {
+ "description": "metadata of node",
+ "type": "object"
+ },
+ "weight": {
+ "minimum": 0,
+ "type": "integer",
+ "description": "weight of node"
+ }
+ }
+ },
+ "type": "array",
+ "minItems": 1
+ }]
+ },
+ "service_name": {
+ "maxLength": 50,
+ "type": "string"
+ },
+ "desc": {
+ "maxLength": 256,
+ "type": "string"
+ },
+ "labels": {
+ "maxProperties": 16,
+ "type": "object",
+ "description": "key/value pairs to specify attributes",
+ "patternProperties": {
+ ".*": {
+ "type": "string",
+ "description": "value of label",
+ "minLength": 1,
+ "pattern": "^[a-zA-Z0-9-_.]+$",
+ "maxLength": 64
+ }
+ }
+ }
+ },
+ "type": "object",
+ "additionalProperties": false,
+ "anyOf": [{
+ "required": ["type", "nodes"]
+ }, {
+ "required": ["type", "k8s_deployment_info"]
+ }, {
+ "required": ["type", "service_name"]
+ }]
+ },
+ "id_schema": {
+ "anyOf": [{
+ "maxLength": 64,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9-_]+$",
+ "minLength": 1
+ }, {
+ "minimum": 1,
+ "type": "integer"
+ }]
+ },
+ "service": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "script": {
+ "type": "string",
+ "maxLength": 102400,
+ "minLength": 10
+ },
+ "upstream": {
+ "properties": {
+ "update_time": {
+ "type": "integer"
+ },
+ "retries": {
+ "minimum": 0,
+ "type": "integer"
+ },
+ "k8s_deployment_info": {
+ "type": "object",
+ "properties": {
+ "port": {
+ "minimum": 0,
+ "type": "number"
+ },
+ "deploy_name": {
+ "description": "k8s deployment name",
+ "type": "string"
+ },
+ "service_name": {
+ "description": "k8s service name",
+ "type": "string"
+ },
+ "namespace": {
+ "description": "k8s namespace",
+ "type": "string"
+ },
+ "backend_type": {
+ "enum": ["svc", "pod"],
+ "type": "string",
+ "default": "pod",
+ "description": "k8s service name"
+ }
+ },
+ "anyOf": [{
+ "required": ["namespace", "deploy_name", "port"]
+ }, {
+ "required": ["namespace", "service_name", "port"]
+ }]
+ },
+ "key": {
+ "description": "the key of chash for dynamic load balancing",
+ "type": "string"
+ },
+ "pass_host": {
+ "default": "pass",
+ "type": "string",
+ "description": "mod of host passing",
+ "enum": ["pass", "node", "rewrite"]
+ },
+ "type": {
+ "type": "string",
+ "description": "algorithms of load balancing",
+ "enum": ["chash", "roundrobin", "ewma"]
+ },
+ "timeout": {
+ "type": "object",
+ "required": ["connect", "send", "read"],
+ "properties": {
+ "send": {
+ "minimum": 0,
+ "type": "number"
+ },
+ "read": {
+ "minimum": 0,
+ "type": "number"
+ },
+ "connect": {
+ "minimum": 0,
+ "type": "number"
+ }
+ }
+ },
+ "checks": {
+ "properties": {
+ "passive": {
+ "properties": {
+ "unhealthy": {
+ "properties": {
+ "http_failures": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 5,
+ "maximum": 254
+ },
+ "timeouts": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 7,
+ "maximum": 254
+ },
+ "http_statuses": {
+ "items": {
+ "minimum": 200,
+ "type": "integer",
+ "maximum": 599
+ },
+ "type": "array",
+ "default": [429, 500, 503],
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "tcp_failures": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 2,
+ "maximum": 254
+ }
+ },
+ "type": "object"
+ },
+ "type": {
+ "type": "string",
+ "default": "http",
+ "enum": ["http", "https", "tcp"]
+ },
+ "healthy": {
+ "properties": {
+ "http_statuses": {
+ "items": {
+ "minimum": 200,
+ "type": "integer",
+ "maximum": 599
+ },
+ "type": "array",
+ "default": [200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 304, 305, 306, 307, 308],
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "successes": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 5,
+ "maximum": 254
+ }
+ },
+ "type": "object"
+ }
+ },
+ "type": "object"
+ },
+ "active": {
+ "properties": {
+ "type": {
+ "type": "string",
+ "default": "http",
+ "enum": ["http", "https", "tcp"]
+ },
+ "timeout": {
+ "default": 1,
+ "type": "number"
+ },
+ "req_headers": {
+ "items": {
+ "uniqueItems": true,
+ "type": "string"
+ },
+ "type": "array",
+ "minItems": 1
+ },
+ "http_path": {
+ "default": "/",
+ "type": "string"
+ },
+ "concurrency": {
+ "default": 10,
+ "type": "integer"
+ },
+ "host": {
+ "pattern": "^\\*?[0-9a-zA-Z-.]+$",
+ "type": "string"
+ },
+ "port": {
+ "minimum": 1,
+ "type": "integer",
+ "maximum": 65535
+ },
+ "unhealthy": {
+ "properties": {
+ "timeouts": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 3,
+ "maximum": 254
+ },
+ "http_failures": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 5,
+ "maximum": 254
+ },
+ "interval": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 0
+ },
+ "http_statuses": {
+ "items": {
+ "minimum": 200,
+ "type": "integer",
+ "maximum": 599
+ },
+ "type": "array",
+ "default": [429, 404, 500, 501, 502, 503, 504, 505],
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "tcp_failures": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 2,
+ "maximum": 254
+ }
+ },
+ "type": "object"
+ },
+ "healthy": {
+ "properties": {
+ "interval": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 0
+ },
+ "http_statuses": {
+ "items": {
+ "minimum": 200,
+ "type": "integer",
+ "maximum": 599
+ },
+ "type": "array",
+ "default": [200, 302],
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "successes": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 2,
+ "maximum": 254
+ }
+ },
+ "type": "object"
+ },
+ "https_verify_certificate": {
+ "default": true,
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+ }
+ },
+ "type": "object",
+ "additionalProperties": false,
+ "anyOf": [{
+ "required": ["active"]
+ }, {
+ "required": ["active", "passive"]
+ }]
+ },
+ "hash_on": {
+ "type": "string",
+ "default": "vars",
+ "enum": ["vars", "header", "cookie", "consumer"]
+ },
+ "upstream_host": {
+ "pattern": "^\\*?[0-9a-zA-Z-.]+$",
+ "type": "string"
+ },
+ "discovery_type": {
+ "description": "discovery type",
+ "type": "string"
+ },
+ "create_time": {
+ "type": "integer"
+ },
+ "name": {
+ "maxLength": 50,
+ "type": "string"
+ },
+ "id": {
+ "anyOf": [{
+ "maxLength": 64,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9-_]+$",
+ "minLength": 1
+ }, {
+ "minimum": 1,
+ "type": "integer"
+ }]
+ },
+ "nodes": {
+ "anyOf": [{
+ "minProperties": 1,
+ "type": "object",
+ "patternProperties": {
+ ".*": {
+ "minimum": 0,
+ "type": "integer",
+ "description": "weight of node"
+ }
+ }
+ }, {
+ "items": {
+ "type": "object",
+ "required": ["host", "port", "weight"],
+ "properties": {
+ "host": {
+ "pattern": "^\\*?[0-9a-zA-Z-.]+$",
+ "type": "string"
+ },
+ "port": {
+ "minimum": 1,
+ "type": "integer",
+ "description": "port of node"
+ },
+ "metadata": {
+ "description": "metadata of node",
+ "type": "object"
+ },
+ "weight": {
+ "minimum": 0,
+ "type": "integer",
+ "description": "weight of node"
+ }
+ }
+ },
+ "type": "array",
+ "minItems": 1
+ }]
+ },
+ "service_name": {
+ "maxLength": 50,
+ "type": "string"
+ },
+ "desc": {
+ "maxLength": 256,
+ "type": "string"
+ },
+ "labels": {
+ "maxProperties": 16,
+ "type": "object",
+ "description": "key/value pairs to specify attributes",
+ "patternProperties": {
+ ".*": {
+ "type": "string",
+ "description": "value of label",
+ "minLength": 1,
+ "pattern": "^[a-zA-Z0-9-_.]+$",
+ "maxLength": 64
+ }
+ }
+ }
+ },
+ "type": "object",
+ "additionalProperties": false,
+ "anyOf": [{
+ "required": ["type", "nodes"]
+ }, {
+ "required": ["type", "k8s_deployment_info"]
+ }, {
+ "required": ["type", "service_name"]
+ }]
+ },
+ "id": {
+ "anyOf": [{
+ "maxLength": 64,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9-_]+$",
+ "minLength": 1
+ }, {
+ "minimum": 1,
+ "type": "integer"
+ }]
+ },
+ "desc": {
+ "maxLength": 256,
+ "type": "string"
+ },
+ "create_time": {
+ "type": "integer"
+ },
+ "name": {
+ "maxLength": 50,
+ "type": "string"
+ },
+ "upstream_id": {
+ "anyOf": [{
+ "maxLength": 64,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9-_]+$",
+ "minLength": 1
+ }, {
+ "minimum": 1,
+ "type": "integer"
+ }]
+ },
+ "plugins": {
+ "type": "object"
+ },
+ "enable_websocket": {
+ "description": "enable websocket for request",
+ "type": "boolean"
+ },
+ "update_time": {
+ "type": "integer"
+ },
+ "labels": {
+ "maxProperties": 16,
+ "type": "object",
+ "description": "key/value pairs to specify attributes",
+ "patternProperties": {
+ ".*": {
+ "type": "string",
+ "description": "value of label",
+ "minLength": 1,
+ "pattern": "^[a-zA-Z0-9-_.]+$",
+ "maxLength": 64
+ }
+ }
+ }
+ }
+ },
+ "ip_def": [{
+ "type": "string",
+ "title": "IPv4",
+ "pattern": "^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$"
+ }, {
+ "type": "string",
+ "title": "IPv4/CIDR",
+ "pattern": "^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}/[0-9]{1,2}$"
+ }, {
+ "type": "string",
+ "title": "IPv6",
+ "pattern": "^([a-fA-F0-9]{0,4}:){0,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?$"
+ }, {
+ "type": "string",
+ "title": "IPv6/CIDR",
+ "pattern": "^([a-fA-F0-9]{0,4}:){0,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?/[0-9]{1,3}$"
+ }],
+ "host_def": {
+ "pattern": "^\\*?[0-9a-zA-Z-.]+$",
+ "type": "string"
+ },
+ "ssl": {
+ "oneOf": [{
+ "required": ["sni", "key", "cert"]
+ }, {
+ "required": ["snis", "key", "cert"]
+ }],
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "update_time": {
+ "type": "integer"
+ },
+ "create_time": {
+ "type": "integer"
+ },
+ "id": {
+ "anyOf": [{
+ "maxLength": 64,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9-_]+$",
+ "minLength": 1
+ }, {
+ "minimum": 1,
+ "type": "integer"
+ }]
+ },
+ "status": {
+ "default": 1,
+ "type": "integer",
+ "description": "ssl status, 1 to enable, 0 to disable",
+ "enum": [1, 0]
+ },
+ "cert": {
+ "type": "string",
+ "maxLength": 65536,
+ "minLength": 128
+ },
+ "sni": {
+ "pattern": "^\\*?[0-9a-zA-Z-.]+$",
+ "type": "string"
+ },
+ "validity_end": {
+ "type": "integer"
+ },
+ "validity_start": {
+ "type": "integer"
+ },
+ "key": {
+ "type": "string",
+ "maxLength": 65536,
+ "minLength": 128
+ },
+ "exptime": {
+ "minimum": 1588262400,
+ "type": "integer"
+ },
+ "keys": {
+ "items": {
+ "type": "string",
+ "maxLength": 65536,
+ "minLength": 128
+ },
+ "type": "array"
+ },
+ "certs": {
+ "items": {
+ "type": "string",
+ "maxLength": 65536,
+ "minLength": 128
+ },
+ "type": "array"
+ },
+ "snis": {
+ "items": {
+ "pattern": "^\\*?[0-9a-zA-Z-.]+$",
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "labels": {
+ "maxProperties": 16,
+ "type": "object",
+ "description": "key/value pairs to specify attributes",
+ "patternProperties": {
+ ".*": {
+ "type": "string",
+ "description": "value of label",
+ "minLength": 1,
+ "pattern": "^[a-zA-Z0-9-_.]+$",
+ "maxLength": 64
+ }
+ }
+ }
+ }
+ },
+ "proto": {
+ "additionalProperties": false,
+ "type": "object",
+ "required": ["content"],
+ "properties": {
+ "content": {
+ "type": "string",
+ "maxLength": 1048576,
+ "minLength": 1
+ }
+ }
+ },
+ "route": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "service_id": {
+ "anyOf": [{
+ "maxLength": 64,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9-_]+$",
+ "minLength": 1
+ }, {
+ "minimum": 1,
+ "type": "integer"
+ }]
+ },
+ "update_time": {
+ "type": "integer"
+ },
+ "uris": {
+ "items": {
+ "description": "HTTP uri",
+ "type": "string"
+ },
+ "type": "array",
+ "uniqueItems": true
+ },
+ "hosts": {
+ "items": {
+ "pattern": "^\\*?[0-9a-zA-Z-.]+$",
+ "type": "string"
+ },
+ "type": "array",
+ "uniqueItems": true
+ },
+ "remote_addrs": {
+ "items": {
+ "type": "string",
+ "description": "client IP",
+ "anyOf": [{
+ "type": "string",
+ "title": "IPv4",
+ "pattern": "^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$"
+ }, {
+ "type": "string",
+ "title": "IPv4/CIDR",
+ "pattern": "^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}/[0-9]{1,2}$"
+ }, {
+ "type": "string",
+ "title": "IPv6",
+ "pattern": "^([a-fA-F0-9]{0,4}:){0,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?$"
+ }, {
+ "type": "string",
+ "title": "IPv6/CIDR",
+ "pattern": "^([a-fA-F0-9]{0,4}:){0,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?/[0-9]{1,3}$"
+ }]
+ },
+ "type": "array",
+ "uniqueItems": true
+ },
+ "host": {
+ "pattern": "^\\*?[0-9a-zA-Z-.]+$",
+ "type": "string"
+ },
+ "remote_addr": {
+ "type": "string",
+ "description": "client IP",
+ "anyOf": [{
+ "type": "string",
+ "title": "IPv4",
+ "pattern": "^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$"
+ }, {
+ "type": "string",
+ "title": "IPv4/CIDR",
+ "pattern": "^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}/[0-9]{1,2}$"
+ }, {
+ "type": "string",
+ "title": "IPv6",
+ "pattern": "^([a-fA-F0-9]{0,4}:){0,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?$"
+ }, {
+ "type": "string",
+ "title": "IPv6/CIDR",
+ "pattern": "^([a-fA-F0-9]{0,4}:){0,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?/[0-9]{1,3}$"
+ }]
+ },
+ "upstream_id": {
+ "anyOf": [{
+ "maxLength": 64,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9-_]+$",
+ "minLength": 1
+ }, {
+ "minimum": 1,
+ "type": "integer"
+ }]
+ },
+ "plugins": {
+ "type": "object"
+ },
+ "priority": {
+ "default": 0,
+ "type": "integer"
+ },
+ "uri": {
+ "type": "string",
+ "maxLength": 4096,
+ "minLength": 1
+ },
+ "methods": {
+ "items": {
+ "type": "string",
+ "description": "HTTP method",
+ "enum": ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "CONNECT", "TRACE"]
+ },
+ "type": "array",
+ "uniqueItems": true
+ },
+ "script": {
+ "type": "string",
+ "maxLength": 102400,
+ "minLength": 10
+ },
+ "id": {
+ "anyOf": [{
+ "maxLength": 64,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9-_]+$",
+ "minLength": 1
+ }, {
+ "minimum": 1,
+ "type": "integer"
+ }]
+ },
+ "desc": {
+ "maxLength": 256,
+ "type": "string"
+ },
+ "enable_websocket": {
+ "description": "enable websocket for request",
+ "type": "boolean"
+ },
+ "create_time": {
+ "type": "integer"
+ },
+ "name": {
+ "maxLength": 50,
+ "type": "string"
+ },
+ "service_protocol": {
+ "enum": ["grpc", "http"]
+ },
+ "vars": {
+ "items": {
+ "items": {
+ "maxItems": 3,
+ "minItems": 2,
+ "anyOf": [{
+ "type": "string"
+ }, {
+ "type": "number"
+ }]
+ },
+ "type": "array",
+ "description": "Nginx builtin variable name and value"
+ },
+ "type": "array"
+ },
+ "upstream": {
+ "properties": {
+ "update_time": {
+ "type": "integer"
+ },
+ "retries": {
+ "minimum": 0,
+ "type": "integer"
+ },
+ "k8s_deployment_info": {
+ "type": "object",
+ "properties": {
+ "port": {
+ "minimum": 0,
+ "type": "number"
+ },
+ "deploy_name": {
+ "description": "k8s deployment name",
+ "type": "string"
+ },
+ "service_name": {
+ "description": "k8s service name",
+ "type": "string"
+ },
+ "namespace": {
+ "description": "k8s namespace",
+ "type": "string"
+ },
+ "backend_type": {
+ "enum": ["svc", "pod"],
+ "type": "string",
+ "default": "pod",
+ "description": "k8s service name"
+ }
+ },
+ "anyOf": [{
+ "required": ["namespace", "deploy_name", "port"]
+ }, {
+ "required": ["namespace", "service_name", "port"]
+ }]
+ },
+ "key": {
+ "description": "the key of chash for dynamic load balancing",
+ "type": "string"
+ },
+ "pass_host": {
+ "default": "pass",
+ "type": "string",
+ "description": "mod of host passing",
+ "enum": ["pass", "node", "rewrite"]
+ },
+ "type": {
+ "type": "string",
+ "description": "algorithms of load balancing",
+ "enum": ["chash", "roundrobin", "ewma"]
+ },
+ "timeout": {
+ "type": "object",
+ "required": ["connect", "send", "read"],
+ "properties": {
+ "send": {
+ "minimum": 0,
+ "type": "number"
+ },
+ "read": {
+ "minimum": 0,
+ "type": "number"
+ },
+ "connect": {
+ "minimum": 0,
+ "type": "number"
+ }
+ }
+ },
+ "checks": {
+ "properties": {
+ "passive": {
+ "properties": {
+ "unhealthy": {
+ "properties": {
+ "http_failures": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 5,
+ "maximum": 254
+ },
+ "timeouts": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 7,
+ "maximum": 254
+ },
+ "http_statuses": {
+ "items": {
+ "minimum": 200,
+ "type": "integer",
+ "maximum": 599
+ },
+ "type": "array",
+ "default": [429, 500, 503],
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "tcp_failures": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 2,
+ "maximum": 254
+ }
+ },
+ "type": "object"
+ },
+ "type": {
+ "type": "string",
+ "default": "http",
+ "enum": ["http", "https", "tcp"]
+ },
+ "healthy": {
+ "properties": {
+ "http_statuses": {
+ "items": {
+ "minimum": 200,
+ "type": "integer",
+ "maximum": 599
+ },
+ "type": "array",
+ "default": [200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 304, 305, 306, 307, 308],
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "successes": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 5,
+ "maximum": 254
+ }
+ },
+ "type": "object"
+ }
+ },
+ "type": "object"
+ },
+ "active": {
+ "properties": {
+ "type": {
+ "type": "string",
+ "default": "http",
+ "enum": ["http", "https", "tcp"]
+ },
+ "timeout": {
+ "default": 1,
+ "type": "number"
+ },
+ "req_headers": {
+ "items": {
+ "uniqueItems": true,
+ "type": "string"
+ },
+ "type": "array",
+ "minItems": 1
+ },
+ "http_path": {
+ "default": "/",
+ "type": "string"
+ },
+ "concurrency": {
+ "default": 10,
+ "type": "integer"
+ },
+ "host": {
+ "pattern": "^\\*?[0-9a-zA-Z-.]+$",
+ "type": "string"
+ },
+ "port": {
+ "minimum": 1,
+ "type": "integer",
+ "maximum": 65535
+ },
+ "unhealthy": {
+ "properties": {
+ "timeouts": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 3,
+ "maximum": 254
+ },
+ "http_failures": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 5,
+ "maximum": 254
+ },
+ "interval": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 0
+ },
+ "http_statuses": {
+ "items": {
+ "minimum": 200,
+ "type": "integer",
+ "maximum": 599
+ },
+ "type": "array",
+ "default": [429, 404, 500, 501, 502, 503, 504, 505],
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "tcp_failures": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 2,
+ "maximum": 254
+ }
+ },
+ "type": "object"
+ },
+ "healthy": {
+ "properties": {
+ "interval": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 0
+ },
+ "http_statuses": {
+ "items": {
+ "minimum": 200,
+ "type": "integer",
+ "maximum": 599
+ },
+ "type": "array",
+ "default": [200, 302],
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "successes": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 2,
+ "maximum": 254
+ }
+ },
+ "type": "object"
+ },
+ "https_verify_certificate": {
+ "default": true,
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+ }
+ },
+ "type": "object",
+ "additionalProperties": false,
+ "anyOf": [{
+ "required": ["active"]
+ }, {
+ "required": ["active", "passive"]
+ }]
+ },
+ "hash_on": {
+ "type": "string",
+ "default": "vars",
+ "enum": ["vars", "header", "cookie", "consumer"]
+ },
+ "upstream_host": {
+ "pattern": "^\\*?[0-9a-zA-Z-.]+$",
+ "type": "string"
+ },
+ "discovery_type": {
+ "description": "discovery type",
+ "type": "string"
+ },
+ "create_time": {
+ "type": "integer"
+ },
+ "name": {
+ "maxLength": 50,
+ "type": "string"
+ },
+ "id": {
+ "anyOf": [{
+ "maxLength": 64,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9-_]+$",
+ "minLength": 1
+ }, {
+ "minimum": 1,
+ "type": "integer"
+ }]
+ },
+ "nodes": {
+ "anyOf": [{
+ "minProperties": 1,
+ "type": "object",
+ "patternProperties": {
+ ".*": {
+ "minimum": 0,
+ "type": "integer",
+ "description": "weight of node"
+ }
+ }
+ }, {
+ "items": {
+ "type": "object",
+ "required": ["host", "port", "weight"],
+ "properties": {
+ "host": {
+ "pattern": "^\\*?[0-9a-zA-Z-.]+$",
+ "type": "string"
+ },
+ "port": {
+ "minimum": 1,
+ "type": "integer",
+ "description": "port of node"
+ },
+ "metadata": {
+ "description": "metadata of node",
+ "type": "object"
+ },
+ "weight": {
+ "minimum": 0,
+ "type": "integer",
+ "description": "weight of node"
+ }
+ }
+ },
+ "type": "array",
+ "minItems": 1
+ }]
+ },
+ "service_name": {
+ "maxLength": 50,
+ "type": "string"
+ },
+ "desc": {
+ "maxLength": 256,
+ "type": "string"
+ },
+ "labels": {
+ "maxProperties": 16,
+ "type": "object",
+ "description": "key/value pairs to specify attributes",
+ "patternProperties": {
+ ".*": {
+ "type": "string",
+ "description": "value of label",
+ "minLength": 1,
+ "pattern": "^[a-zA-Z0-9-_.]+$",
+ "maxLength": 64
+ }
+ }
+ }
+ },
+ "type": "object",
+ "additionalProperties": false,
+ "anyOf": [{
+ "required": ["type", "nodes"]
+ }, {
+ "required": ["type", "k8s_deployment_info"]
+ }, {
+ "required": ["type", "service_name"]
+ }]
+ },
+ "filter_func": {
+ "type": "string",
+ "pattern": "^function",
+ "minLength": 10
+ },
+ "labels": {
+ "maxProperties": 16,
+ "type": "object",
+ "description": "key/value pairs to specify attributes",
+ "patternProperties": {
+ ".*": {
+ "type": "string",
+ "description": "value of label",
+ "minLength": 1,
+ "pattern": "^[a-zA-Z0-9-_.]+$",
+ "maxLength": 64
+ }
+ }
+ }
+ },
+ "not": {
+ "anyOf": [{
+ "required": ["script", "plugins"]
+ }]
+ },
+ "anyOf": [{
+ "required": ["plugins", "uri"]
+ }, {
+ "required": ["upstream", "uri"]
+ }, {
+ "required": ["upstream_id", "uri"]
+ }, {
+ "required": ["service_id", "uri"]
+ }, {
+ "required": ["plugins", "uris"]
+ }, {
+ "required": ["upstream", "uris"]
+ }, {
+ "required": ["upstream_id", "uris"]
+ }, {
+ "required": ["service_id", "uris"]
+ }, {
+ "required": ["script", "uri"]
+ }, {
+ "required": ["script", "uris"]
+ }]
+ },
+ "upstream_hash_header_schema": {
+ "pattern": "^[a-zA-Z0-9-_]+$",
+ "type": "string"
+ },
+ "upstream_hash_vars_schema": {
+ "pattern": "^((uri|server_name|server_addr|request_uri|remote_port|remote_addr|query_string|host|hostname)|arg_[0-9a-zA-z_-]+)$",
+ "type": "string"
+ },
+ "version": 0.5,
+ "stream_route": {
+ "properties": {
+ "remote_addr": {
+ "type": "string",
+ "description": "client IP",
+ "anyOf": [{
+ "type": "string",
+ "title": "IPv4",
+ "pattern": "^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$"
+ }, {
+ "type": "string",
+ "title": "IPv4/CIDR",
+ "pattern": "^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}/[0-9]{1,2}$"
+ }, {
+ "type": "string",
+ "title": "IPv6",
+ "pattern": "^([a-fA-F0-9]{0,4}:){0,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?$"
+ }, {
+ "type": "string",
+ "title": "IPv6/CIDR",
+ "pattern": "^([a-fA-F0-9]{0,4}:){0,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?/[0-9]{1,3}$"
+ }]
+ },
+ "plugins": {
+ "type": "object"
+ },
+ "server_addr": {
+ "type": "string",
+ "description": "server IP",
+ "anyOf": [{
+ "type": "string",
+ "title": "IPv4",
+ "pattern": "^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$"
+ }, {
+ "type": "string",
+ "title": "IPv4/CIDR",
+ "pattern": "^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}/[0-9]{1,2}$"
+ }, {
+ "type": "string",
+ "title": "IPv6",
+ "pattern": "^([a-fA-F0-9]{0,4}:){0,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?$"
+ }, {
+ "type": "string",
+ "title": "IPv6/CIDR",
+ "pattern": "^([a-fA-F0-9]{0,4}:){0,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?/[0-9]{1,3}$"
+ }]
+ },
+ "id": {
+ "anyOf": [{
+ "maxLength": 64,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9-_]+$",
+ "minLength": 1
+ }, {
+ "minimum": 1,
+ "type": "integer"
+ }]
+ },
+ "upstream_id": {
+ "anyOf": [{
+ "maxLength": 64,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9-_]+$",
+ "minLength": 1
+ }, {
+ "minimum": 1,
+ "type": "integer"
+ }]
+ },
+ "server_port": {
+ "description": "server port",
+ "type": "integer"
+ },
+ "upstream": {
+ "properties": {
+ "update_time": {
+ "type": "integer"
+ },
+ "retries": {
+ "minimum": 0,
+ "type": "integer"
+ },
+ "k8s_deployment_info": {
+ "type": "object",
+ "properties": {
+ "port": {
+ "minimum": 0,
+ "type": "number"
+ },
+ "deploy_name": {
+ "description": "k8s deployment name",
+ "type": "string"
+ },
+ "service_name": {
+ "description": "k8s service name",
+ "type": "string"
+ },
+ "namespace": {
+ "description": "k8s namespace",
+ "type": "string"
+ },
+ "backend_type": {
+ "enum": ["svc", "pod"],
+ "type": "string",
+ "default": "pod",
+ "description": "k8s service name"
+ }
+ },
+ "anyOf": [{
+ "required": ["namespace", "deploy_name", "port"]
+ }, {
+ "required": ["namespace", "service_name", "port"]
+ }]
+ },
+ "key": {
+ "description": "the key of chash for dynamic load balancing",
+ "type": "string"
+ },
+ "pass_host": {
+ "default": "pass",
+ "type": "string",
+ "description": "mod of host passing",
+ "enum": ["pass", "node", "rewrite"]
+ },
+ "type": {
+ "type": "string",
+ "description": "algorithms of load balancing",
+ "enum": ["chash", "roundrobin", "ewma"]
+ },
+ "timeout": {
+ "type": "object",
+ "required": ["connect", "send", "read"],
+ "properties": {
+ "send": {
+ "minimum": 0,
+ "type": "number"
+ },
+ "read": {
+ "minimum": 0,
+ "type": "number"
+ },
+ "connect": {
+ "minimum": 0,
+ "type": "number"
+ }
+ }
+ },
+ "checks": {
+ "properties": {
+ "passive": {
+ "properties": {
+ "unhealthy": {
+ "properties": {
+ "http_failures": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 5,
+ "maximum": 254
+ },
+ "timeouts": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 7,
+ "maximum": 254
+ },
+ "http_statuses": {
+ "items": {
+ "minimum": 200,
+ "type": "integer",
+ "maximum": 599
+ },
+ "type": "array",
+ "default": [429, 500, 503],
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "tcp_failures": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 2,
+ "maximum": 254
+ }
+ },
+ "type": "object"
+ },
+ "type": {
+ "type": "string",
+ "default": "http",
+ "enum": ["http", "https", "tcp"]
+ },
+ "healthy": {
+ "properties": {
+ "http_statuses": {
+ "items": {
+ "minimum": 200,
+ "type": "integer",
+ "maximum": 599
+ },
+ "type": "array",
+ "default": [200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 304, 305, 306, 307, 308],
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "successes": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 5,
+ "maximum": 254
+ }
+ },
+ "type": "object"
+ }
+ },
+ "type": "object"
+ },
+ "active": {
+ "properties": {
+ "type": {
+ "type": "string",
+ "default": "http",
+ "enum": ["http", "https", "tcp"]
+ },
+ "timeout": {
+ "default": 1,
+ "type": "number"
+ },
+ "req_headers": {
+ "items": {
+ "uniqueItems": true,
+ "type": "string"
+ },
+ "type": "array",
+ "minItems": 1
+ },
+ "http_path": {
+ "default": "/",
+ "type": "string"
+ },
+ "concurrency": {
+ "default": 10,
+ "type": "integer"
+ },
+ "host": {
+ "pattern": "^\\*?[0-9a-zA-Z-.]+$",
+ "type": "string"
+ },
+ "port": {
+ "minimum": 1,
+ "type": "integer",
+ "maximum": 65535
+ },
+ "unhealthy": {
+ "properties": {
+ "timeouts": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 3,
+ "maximum": 254
+ },
+ "http_failures": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 5,
+ "maximum": 254
+ },
+ "interval": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 0
+ },
+ "http_statuses": {
+ "items": {
+ "minimum": 200,
+ "type": "integer",
+ "maximum": 599
+ },
+ "type": "array",
+ "default": [429, 404, 500, 501, 502, 503, 504, 505],
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "tcp_failures": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 2,
+ "maximum": 254
+ }
+ },
+ "type": "object"
+ },
+ "healthy": {
+ "properties": {
+ "interval": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 0
+ },
+ "http_statuses": {
+ "items": {
+ "minimum": 200,
+ "type": "integer",
+ "maximum": 599
+ },
+ "type": "array",
+ "default": [200, 302],
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "successes": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 2,
+ "maximum": 254
+ }
+ },
+ "type": "object"
+ },
+ "https_verify_certificate": {
+ "default": true,
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+ }
+ },
+ "type": "object",
+ "additionalProperties": false,
+ "anyOf": [{
+ "required": ["active"]
+ }, {
+ "required": ["active", "passive"]
+ }]
+ },
+ "hash_on": {
+ "type": "string",
+ "default": "vars",
+ "enum": ["vars", "header", "cookie", "consumer"]
+ },
+ "upstream_host": {
+ "pattern": "^\\*?[0-9a-zA-Z-.]+$",
+ "type": "string"
+ },
+ "discovery_type": {
+ "description": "discovery type",
+ "type": "string"
+ },
+ "create_time": {
+ "type": "integer"
+ },
+ "name": {
+ "maxLength": 50,
+ "type": "string"
+ },
+ "id": {
+ "anyOf": [{
+ "maxLength": 64,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9-_]+$",
+ "minLength": 1
+ }, {
+ "minimum": 1,
+ "type": "integer"
+ }]
+ },
+ "nodes": {
+ "anyOf": [{
+ "minProperties": 1,
+ "type": "object",
+ "patternProperties": {
+ ".*": {
+ "minimum": 0,
+ "type": "integer",
+ "description": "weight of node"
+ }
+ }
+ }, {
+ "items": {
+ "type": "object",
+ "required": ["host", "port", "weight"],
+ "properties": {
+ "host": {
+ "pattern": "^\\*?[0-9a-zA-Z-.]+$",
+ "type": "string"
+ },
+ "port": {
+ "minimum": 1,
+ "type": "integer",
+ "description": "port of node"
+ },
+ "metadata": {
+ "description": "metadata of node",
+ "type": "object"
+ },
+ "weight": {
+ "minimum": 0,
+ "type": "integer",
+ "description": "weight of node"
+ }
+ }
+ },
+ "type": "array",
+ "minItems": 1
+ }]
+ },
+ "service_name": {
+ "maxLength": 50,
+ "type": "string"
+ },
+ "desc": {
+ "maxLength": 256,
+ "type": "string"
+ },
+ "labels": {
+ "maxProperties": 16,
+ "type": "object",
+ "description": "key/value pairs to specify attributes",
+ "patternProperties": {
+ ".*": {
+ "type": "string",
+ "description": "value of label",
+ "minLength": 1,
+ "pattern": "^[a-zA-Z0-9-_.]+$",
+ "maxLength": 64
+ }
+ }
+ }
+ },
+ "type": "object",
+ "additionalProperties": false,
+ "anyOf": [{
+ "required": ["type", "nodes"]
+ }, {
+ "required": ["type", "k8s_deployment_info"]
+ }, {
+ "required": ["type", "service_name"]
+ }]
+ }
+ },
+ "type": "object"
+ },
+ "plugin_disable_schema": {
+ "disable": {
+ "type": "boolean"
+ }
+ },
+ "plugins": {
+ "items": {
+ "type": "object",
+ "required": ["name"],
+ "properties": {
+ "stream": {
+ "type": "boolean"
+ },
+ "name": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "additionalProperties": false
+ }
+ },
+ "type": "array"
+ },
+ "label_value_def": {
+ "type": "string",
+ "description": "value of label",
+ "minLength": 1,
+ "pattern": "^[a-zA-Z0-9-_.]+$",
+ "maxLength": 64
+ },
+ "consumer": {
+ "additionalProperties": false,
+ "type": "object",
+ "required": ["username"],
+ "properties": {
+ "username": {
+ "maxLength": 32,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9_]+$",
+ "minLength": 1
+ },
+ "create_time": {
+ "type": "integer"
+ },
+ "update_time": {
+ "type": "integer"
+ },
+ "id": {
+ "anyOf": [{
+ "maxLength": 64,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9-_]+$",
+ "minLength": 1
+ }, {
+ "minimum": 1,
+ "type": "integer"
+ }]
+ },
+ "desc": {
+ "maxLength": 256,
+ "type": "string"
+ },
+ "plugins": {
+ "type": "object"
+ },
+ "labels": {
+ "maxProperties": 16,
+ "type": "object",
+ "description": "key/value pairs to specify attributes",
+ "patternProperties": {
+ ".*": {
+ "type": "string",
+ "description": "value of label",
+ "minLength": 1,
+ "pattern": "^[a-zA-Z0-9-_.]+$",
+ "maxLength": 64
+ }
+ }
+ }
+ }
+ }
+ },
+ "plugins": {
+ "limit-req": {
+ "schema": {
+ "type": "object",
+ "required": ["rate", "burst", "key"],
+ "properties": {
+ "rejected_code": {
+ "minimum": 200,
+ "type": "integer",
+ "default": 503
+ },
+ "key": {
+ "enum": ["remote_addr", "server_addr", "http_x_real_ip", "http_x_forwarded_for", "consumer_name"],
+ "type": "string"
+ },
+ "rate": {
+ "minimum": 0,
+ "type": "number"
+ },
+ "burst": {
+ "minimum": 0,
+ "type": "number"
+ }
+ }
+ }
+ },
+ "zipkin": {
+ "schema": {
+ "type": "object",
+ "required": ["endpoint", "sample_ratio"],
+ "properties": {
+ "endpoint": {
+ "type": "string"
+ },
+ "service_name": {
+ "type": "string",
+ "description": "service name for zipkin reporter",
+ "default": "APISIX"
+ },
+ "sample_ratio": {
+ "minimum": 1e-05,
+ "type": "number",
+ "maximum": 1
+ },
+ "server_addr": {
+ "type": "string",
+ "description": "default is $server_addr, you can speific your external ip address",
+ "pattern": "^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$"
+ }
+ }
+ }
+ },
+ "jwt-auth": {
+ "schema": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {}
+ },
+ "consumer_schema": {
+ "required": ["key"],
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "public_key": {
+ "type": "string"
+ },
+ "key": {
+ "type": "string"
+ },
+ "exp": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 86400
+ },
+ "base64_secret": {
+ "default": false,
+ "type": "boolean"
+ },
+ "private_key": {
+ "type": "string"
+ },
+ "algorithm": {
+ "type": "string",
+ "default": "HS256",
+ "enum": ["HS256", "HS512", "RS256"]
+ },
+ "secret": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "request-id": {
+ "schema": {
+ "properties": {
+ "header_name": {
+ "default": "X-Request-Id",
+ "type": "string"
+ },
+ "include_in_response": {
+ "default": true,
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+ }
+ },
+ "proxy-rewrite": {
+ "schema": {
+ "minProperties": 1,
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "host": {
+ "type": "string",
+ "description": "new host for upstream",
+ "pattern": "^[0-9a-zA-Z-.]+$"
+ },
+ "regex_uri": {
+ "items": {
+ "description": "regex uri",
+ "type": "string"
+ },
+ "type": "array",
+ "description": "new uri that substitute from client uri for upstream, lower priority than uri property",
+ "maxItems": 2,
+ "minItems": 2
+ },
+ "scheme": {
+ "type": "string",
+ "description": "new scheme for upstream",
+ "enum": ["http", "https"]
+ },
+ "uri": {
+ "type": "string",
+ "description": "new uri for upstream",
+ "pattern": "^\\/.*",
+ "maxLength": 4096,
+ "minLength": 1
+ },
+ "headers": {
+ "minProperties": 1,
+ "type": "object",
+ "description": "new headers for request"
+ }
+ }
+ }
+ },
+ "serverless-post-function": {
+ "schema": {
+ "type": "object",
+ "required": ["functions"],
+ "properties": {
+ "phase": {
+ "enum": ["rewrite", "access", "header_filter", "body_filter", "log", "balancer"],
+ "type": "string"
+ },
+ "functions": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "minItems": 1
+ }
+ }
+ }
+ },
+ "ip-restriction": {
+ "schema": {
+ "oneOf": [{
+ "additionalProperties": false,
+ "properties": {
+ "whitelist": {
+ "items": {
+ "anyOf": [{
+ "type": "string",
+ "title": "IPv4",
+ "pattern": "^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$"
+ }, {
+ "type": "string",
+ "title": "IPv4/CIDR",
+ "pattern": "^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}/[0-9]{1,2}$"
+ }, {
+ "type": "string",
+ "title": "IPv6",
+ "pattern": "^([a-fA-F0-9]{0,4}:){0,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?$"
+ }, {
+ "type": "string",
+ "title": "IPv6/CIDR",
+ "pattern": "^([a-fA-F0-9]{0,4}:){0,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?/[0-9]{1,3}$"
+ }]
+ },
+ "type": "array",
+ "minItems": 1
+ }
+ },
+ "title": "whitelist",
+ "required": ["whitelist"]
+ }, {
+ "additionalProperties": false,
+ "properties": {
+ "blacklist": {
+ "items": {
+ "anyOf": [{
+ "type": "string",
+ "title": "IPv4",
+ "pattern": "^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$"
+ }, {
+ "type": "string",
+ "title": "IPv4/CIDR",
+ "pattern": "^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}/[0-9]{1,2}$"
+ }, {
+ "type": "string",
+ "title": "IPv6",
+ "pattern": "^([a-fA-F0-9]{0,4}:){0,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?$"
+ }, {
+ "type": "string",
+ "title": "IPv6/CIDR",
+ "pattern": "^([a-fA-F0-9]{0,4}:){0,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?/[0-9]{1,3}$"
+ }]
+ },
+ "type": "array",
+ "minItems": 1
+ }
+ },
+ "title": "blacklist",
+ "required": ["blacklist"]
+ }],
+ "type": "object"
+ }
+ },
+ "tcp-logger": {
+ "schema": {
+ "type": "object",
+ "required": ["host", "port"],
+ "properties": {
+ "tls": {
+ "default": false,
+ "type": "boolean"
+ },
+ "timeout": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 1000
+ },
+ "max_retry_count": {
+ "minimum": 0,
+ "type": "integer",
+ "default": 0
+ },
+ "include_req_body": {
+ "default": false,
+ "type": "boolean"
+ },
+ "host": {
+ "type": "string"
+ },
+ "port": {
+ "minimum": 0,
+ "type": "integer"
+ },
+ "name": {
+ "default": "tcp logger",
+ "type": "string"
+ },
+ "batch_max_size": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 1000
+ },
+ "buffer_duration": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 60
+ },
+ "retry_delay": {
+ "minimum": 0,
+ "type": "integer",
+ "default": 1
+ },
+ "inactive_timeout": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 5
+ },
+ "tls_options": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "cors": {
+ "schema": {
+ "properties": {
+ "allow_credential": {
+ "type": "boolean",
+ "description": "allow client append crendential. according to CORS specification,if you set this option to 'true', you can not use '*' for other options.",
+ "default": false
+ },
+ "allow_headers": {
+ "type": "string",
+ "description": "you can use '*' to allow all header when no credentials,'**' to allow forcefully(it will bring some security risks, be carefully),multiple header use ',' to split. default: *.",
+ "default": "*"
+ },
+ "allow_origins": {
+ "type": "string",
+ "description": "you can use '*' to allow all origins when no credentials,'**' to allow forcefully(it will bring some security risks, be carefully),multiple origin use ',' to split. default: *.",
+ "default": "*"
+ },
+ "allow_methods": {
+ "type": "string",
+ "description": "you can use '*' to allow all methods when no credentials and '**','**' to allow forcefully(it will bring some security risks, be carefully),multiple method use ',' to split. default: *.",
+ "default": "*"
+ },
+ "expose_headers": {
+ "type": "string",
+ "description": "you can use '*' to expose all header when no credentials,multiple header use ',' to split. default: *.",
+ "default": "*"
+ },
+ "max_age": {
+ "type": "integer",
+ "description": "maximum number of seconds the results can be cached.-1 mean no cached,the max value is depend on browser,more detail plz check MDN. default: 5.",
+ "default": 5
+ }
+ },
+ "type": "object"
+ }
+ },
+ "hmac-auth": {
+ "schema": {
+ "additionalProperties": false,
+ "type": "object",
+ "title": "work with route or service object",
+ "properties": {}
+ },
+ "consumer_schema": {
+ "type": "object",
+ "title": "work with consumer object",
+ "properties": {
+ "signed_headers": {
+ "items": {
+ "type": "string",
+ "maxLength": 50,
+ "minLength": 1
+ },
+ "type": "array"
+ },
+ "access_key": {
+ "type": "string",
+ "maxLength": 256,
+ "minLength": 1
+ },
+ "clock_skew": {
+ "default": 0,
+ "type": "integer"
+ },
+ "algorithm": {
+ "type": "string",
+ "default": "hmac-sha256",
+ "enum": ["hmac-sha1", "hmac-sha256", "hmac-sha512"]
+ },
+ "secret_key": {
+ "type": "string",
+ "maxLength": 256,
+ "minLength": 1
+ },
+ "keep_headers": {
+ "type": "boolean",
+ "title": "whether to keep the http request header",
+ "default": false
+ }
+ },
+ "additionalProperties": false,
+ "required": ["access_key", "secret_key"]
+ }
+ },
+ "grpc-transcode": {
+ "schema": {
+ "required": ["proto_id", "service", "method"],
+ "type": "object",
+ "additionalProperties": true,
+ "properties": {
+ "method": {
+ "description": "the method name in the grpc service.",
+ "type": "string"
+ },
+ "proto_id": {
+ "anyOf": [{
+ "maxLength": 64,
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9-_]+$",
+ "minLength": 1
+ }, {
+ "minimum": 1,
+ "type": "integer"
+ }]
+ },
+ "pb_option": {
+ "items": {
+ "anyOf": [{
+ "type": "string",
+ "description": "enum as result",
+ "enum": ["int64_as_number", "int64_as_string", "int64_as_hexstring"]
+ }, {
+ "type": "string",
+ "description": "int64 as result",
+ "enum": ["ienum_as_name", "enum_as_value"]
+ }, {
+ "type": "string",
+ "description": "default values option",
+ "enum": ["auto_default_values", "no_default_values", "use_default_values", "use_default_metatable"]
+ }, {
+ "type": "string",
+ "description": "hooks option",
+ "enum": ["enable_hooks", "disable_hooks"]
+ }],
+ "type": "string"
+ },
+ "type": "array",
+ "minItems": 1
+ },
+ "service": {
+ "description": "the grpc service name",
+ "type": "string"
+ },
+ "deadline": {
+ "type": "number",
+ "description": "deadline for grpc, millisecond",
+ "default": 0
+ }
+ }
+ }
+ },
+ "limit-count": {
+ "schema": {
+ "dependencies": {
+ "policy": {
+ "oneOf": [{
+ "properties": {
+ "policy": {
+ "enum": ["local"]
+ }
+ }
+ }, {
+ "required": ["redis_host"],
+ "properties": {
+ "redis_timeout": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 1000
+ },
+ "redis_host": {
+ "minLength": 2,
+ "type": "string"
+ },
+ "policy": {
+ "enum": ["redis"]
+ },
+ "redis_password": {
+ "minLength": 0,
+ "type": "string"
+ },
+ "redis_port": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 6379
+ }
+ }
+ }, {
+ "required": ["redis_cluster_nodes"],
+ "properties": {
+ "redis_cluster_nodes": {
+ "items": {
+ "type": "string",
+ "maxLength": 100,
+ "minLength": 2
+ },
+ "type": "array",
+ "minItems": 2
+ },
+ "policy": {
+ "enum": ["redis-cluster"]
+ },
+ "redis_password": {
+ "minLength": 0,
+ "type": "string"
+ },
+ "redis_timeout": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 1000
+ }
+ }
+ }]
+ }
+ },
+ "type": "object",
+ "required": ["count", "time_window", "key"],
+ "properties": {
+ "count": {
+ "minimum": 0,
+ "type": "integer"
+ },
+ "rejected_code": {
+ "minimum": 200,
+ "type": "integer",
+ "default": 503,
+ "maximum": 600
+ },
+ "policy": {
+ "type": "string",
+ "default": "local",
+ "enum": ["local", "redis", "redis-cluster"]
+ },
+ "time_window": {
+ "minimum": 0,
+ "type": "integer"
+ },
+ "key": {
+ "enum": ["remote_addr", "server_addr", "http_x_real_ip", "http_x_forwarded_for", "consumer_name", "service_id"],
+ "type": "string"
+ }
+ }
+ }
+ },
+ "key-auth": {
+ "schema": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {}
+ },
+ "consumer_schema": {
+ "required": ["key"],
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "key": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "authz-keycloak": {
+ "schema": {
+ "type": "object",
+ "required": ["token_endpoint"],
+ "properties": {
+ "keepalive": {
+ "default": true,
+ "type": "boolean"
+ },
+ "grant_type": {
+ "type": "string",
+ "default": "urn:ietf:params:oauth:grant-type:uma-ticket",
+ "enum": ["urn:ietf:params:oauth:grant-type:uma-ticket"],
+ "maxLength": 100,
+ "minLength": 1
+ },
+ "timeout": {
+ "minimum": 1000,
+ "type": "integer",
+ "default": 3000
+ },
+ "policy_enforcement_mode": {
+ "type": "string",
+ "default": "ENFORCING",
+ "enum": ["ENFORCING", "PERMISSIVE"]
+ },
+ "audience": {
+ "type": "string",
+ "maxLength": 100,
+ "minLength": 1
+ },
+ "permissions": {
+ "items": {
+ "type": "string",
+ "maxLength": 100,
+ "minLength": 1
+ },
+ "type": "array",
+ "uniqueItems": true
+ },
+ "keepalive_timeout": {
+ "minimum": 1000,
+ "type": "integer",
+ "default": 60000
+ },
+ "ssl_verify": {
+ "default": true,
+ "type": "boolean"
+ },
+ "keepalive_pool": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 5
+ },
+ "token_endpoint": {
+ "type": "string",
+ "maxLength": 4096,
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "wolf-rbac": {
+ "schema": {
+ "properties": {
+ "appid": {
+ "default": "unset",
+ "type": "string"
+ },
+ "header_prefix": {
+ "default": "X-",
+ "type": "string"
+ },
+ "server": {
+ "default": "http://127.0.0.1:10080",
+ "type": "string"
+ }
+ },
+ "type": "object"
+ }
+ },
+ "kafka-logger": {
+ "schema": {
+ "type": "object",
+ "required": ["broker_list", "kafka_topic", "key"],
+ "properties": {
+ "meta_format": {
+ "type": "string",
+ "default": "default",
+ "enum": ["default", "origin"]
+ },
+ "timeout": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 3
+ },
+ "max_retry_count": {
+ "minimum": 0,
+ "type": "integer",
+ "default": 0
+ },
+ "include_req_body": {
+ "default": false,
+ "type": "boolean"
+ },
+ "batch_max_size": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 1000
+ },
+ "inactive_timeout": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 5
+ },
+ "key": {
+ "type": "string"
+ },
+ "buffer_duration": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 60
+ },
+ "kafka_topic": {
+ "type": "string"
+ },
+ "retry_delay": {
+ "minimum": 0,
+ "type": "integer",
+ "default": 1
+ },
+ "broker_list": {
+ "type": "object"
+ },
+ "name": {
+ "default": "kafka logger",
+ "type": "string"
+ }
+ }
+ }
+ },
+ "openid-connect": {
+ "schema": {
+ "type": "object",
+ "required": ["client_id", "client_secret", "discovery"],
+ "properties": {
+ "logout_path": {
+ "type": "string"
+ },
+ "introspection_endpoint_auth_method": {
+ "type": "string"
+ },
+ "client_secret": {
+ "type": "string"
+ },
+ "scope": {
+ "type": "string"
+ },
+ "introspection_endpoint": {
+ "type": "string"
+ },
+ "discovery": {
+ "type": "string"
+ },
+ "public_key": {
+ "type": "string"
+ },
+ "ssl_verify": {
+ "type": "boolean"
+ },
+ "redirect_uri": {
+ "type": "string"
+ },
+ "realm": {
+ "type": "string"
+ },
+ "bearer_only": {
+ "type": "boolean"
+ },
+ "timeout": {
+ "minimum": 1,
+ "type": "integer"
+ },
+ "token_signing_alg_values_expected": {
+ "type": "string"
+ },
+ "client_id": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "limit-conn": {
+ "schema": {
+ "type": "object",
+ "required": ["conn", "burst", "default_conn_delay", "key"],
+ "properties": {
+ "conn": {
+ "exclusiveMinimum": 0,
+ "type": "integer"
+ },
+ "burst": {
+ "minimum": 0,
+ "type": "integer"
+ },
+ "rejected_code": {
+ "minimum": 200,
+ "type": "integer",
+ "default": 503
+ },
+ "key": {
+ "enum": ["remote_addr", "server_addr", "http_x_real_ip", "http_x_forwarded_for", "consumer_name"],
+ "type": "string"
+ },
+ "default_conn_delay": {
+ "exclusiveMinimum": 0,
+ "type": "number"
+ }
+ }
+ }
+ },
+ "redirect": {
+ "schema": {
+ "oneOf": [{
+ "required": ["uri"]
+ }, {
+ "required": ["http_to_https"]
+ }],
+ "type": "object",
+ "properties": {
+ "ret_code": {
+ "minimum": 200,
+ "type": "integer",
+ "default": 302
+ },
+ "uri": {
+ "minLength": 2,
+ "type": "string"
+ },
+ "http_to_https": {
+ "type": "boolean"
+ }
+ }
+ }
+ },
+ "echo": {
+ "schema": {
+ "minProperties": 1,
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "before_body": {
+ "description": "body before the filter phase.",
+ "type": "string"
+ },
+ "auth_value": {
+ "description": "auth value",
+ "type": "string"
+ },
+ "headers": {
+ "minProperties": 1,
+ "type": "object",
+ "description": "new headers for response"
+ },
+ "after_body": {
+ "description": "body after the modification of filter phase.",
+ "type": "string"
+ },
+ "body": {
+ "description": "body to replace upstream response.",
+ "type": "string"
+ }
+ },
+ "anyOf": [{
+ "required": ["before_body"]
+ }, {
+ "required": ["body"]
+ }, {
+ "required": ["after_body"]
+ }]
+ }
+ },
+ "proxy-cache": {
+ "schema": {
+ "type": "object",
+ "required": ["cache_zone"],
+ "properties": {
+ "no_cache": {
+ "items": {
+ "pattern": "(^[^\\$].+$|^\\$[0-9a-zA-Z_]+$)",
+ "type": "string"
+ },
+ "type": "array",
+ "minItems": 1
+ },
+ "cache_bypass": {
+ "items": {
+ "pattern": "(^[^\\$].+$|^\\$[0-9a-zA-Z_]+$)",
+ "type": "string"
+ },
+ "type": "array",
+ "minItems": 1
+ },
+ "cache_method": {
+ "items": {
+ "type": "string",
+ "description": "http method",
+ "enum": ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "CONNECT", "TRACE"]
+ },
+ "type": "array",
+ "default": ["GET", "HEAD"],
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "cache_zone": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "hide_cache_headers": {
+ "default": false,
+ "type": "boolean"
+ },
+ "cache_key": {
+ "items": {
+ "type": "string",
+ "description": "a key for caching",
+ "pattern": "(^[^\\$].+$|^\\$[0-9a-zA-Z_]+$)"
+ },
+ "type": "array",
+ "minItems": 1,
+ "default": ["$host", "$request_uri"]
+ },
+ "cache_http_status": {
+ "items": {
+ "minimum": 200,
+ "type": "integer",
+ "description": "http response status",
+ "maximum": 599
+ },
+ "type": "array",
+ "default": [200, 301, 404],
+ "minItems": 1,
+ "uniqueItems": true
+ }
+ }
+ }
+ },
+ "udp-logger": {
+ "schema": {
+ "type": "object",
+ "required": ["host", "port"],
+ "properties": {
+ "host": {
+ "type": "string"
+ },
+ "port": {
+ "minimum": 0,
+ "type": "integer"
+ },
+ "timeout": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 3
+ },
+ "include_req_body": {
+ "default": false,
+ "type": "boolean"
+ },
+ "batch_max_size": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 1000
+ },
+ "buffer_duration": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 60
+ },
+ "inactive_timeout": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 5
+ },
+ "name": {
+ "default": "udp logger",
+ "type": "string"
+ }
+ }
+ }
+ },
+ "request-validation": {
+ "schema": {
+ "anyOf": [{
+ "properties": {
+ "body_schema": {
+ "type": "object"
+ }
+ },
+ "title": "Body schema",
+ "required": ["body_schema"]
+ }, {
+ "properties": {
+ "header_schema": {
+ "type": "object"
+ }
+ },
+ "title": "Header schema",
+ "required": ["header_schema"]
+ }],
+ "type": "object"
+ }
+ },
+ "consumer-restriction": {
+ "schema": {
+ "oneOf": [{
+ "properties": {
+ "type": {
+ "type": "string",
+ "default": "consumer_name",
+ "enum": ["consumer_name", "service_id"]
+ },
+ "rejected_code": {
+ "minimum": 200,
+ "type": "integer",
+ "default": 403
+ },
+ "blacklist": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "minItems": 1
+ }
+ },
+ "title": "blacklist",
+ "required": ["blacklist"]
+ }, {
+ "properties": {
+ "type": {
+ "type": "string",
+ "default": "consumer_name",
+ "enum": ["consumer_name", "service_id"]
+ },
+ "whitelist": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "minItems": 1
+ },
+ "rejected_code": {
+ "minimum": 200,
+ "type": "integer",
+ "default": 403
+ }
+ },
+ "title": "whitelist",
+ "required": ["whitelist"]
+ }],
+ "type": "object"
+ }
+ },
+ "response-rewrite": {
+ "schema": {
+ "minProperties": 1,
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "status_code": {
+ "minimum": 200,
+ "type": "integer",
+ "description": "new status code for repsonse",
+ "maximum": 598
+ },
+ "body": {
+ "description": "new body for repsonse",
+ "type": "string"
+ },
+ "body_base64": {
+ "type": "boolean",
+ "description": "whether new body for repsonse need base64 decode before return",
+ "default": false
+ },
+ "headers": {
+ "minProperties": 1,
+ "type": "object",
+ "description": "new headers for repsonse"
+ }
+ }
+ }
+ },
+ "syslog": {
+ "schema": {
+ "type": "object",
+ "required": ["host", "port"],
+ "properties": {
+ "tls": {
+ "default": false,
+ "type": "boolean"
+ },
+ "drop_limit": {
+ "default": 1048576,
+ "type": "integer"
+ },
+ "timeout": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 3
+ },
+ "pool_size": {
+ "minimum": 5,
+ "type": "integer",
+ "default": 5
+ },
+ "sock_type": {
+ "type": "string",
+ "default": "tcp",
+ "enum": ["tcp", "udp"]
+ },
+ "include_req_body": {
+ "default": false,
+ "type": "boolean"
+ },
+ "host": {
+ "type": "string"
+ },
+ "port": {
+ "type": "integer"
+ },
+ "name": {
+ "default": "sys logger",
+ "type": "string"
+ },
+ "buffer_duration": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 60
+ },
+ "batch_max_size": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 1000
+ },
+ "retry_interval": {
+ "minimum": 0,
+ "type": "integer",
+ "default": 1
+ },
+ "max_retry_times": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 1
+ },
+ "flush_limit": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 4096
+ }
+ }
+ }
+ },
+ "skywalking": {
+ "schema": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "sample_ratio": {
+ "minimum": 1e-05,
+ "type": "number",
+ "default": 1,
+ "maximum": 1
+ }
+ }
+ }
+ },
+ "node-status": {
+ "schema": {
+ "additionalProperties": false,
+ "type": "object"
+ }
+ },
+ "http-logger": {
+ "schema": {
+ "type": "object",
+ "required": ["uri"],
+ "properties": {
+ "timeout": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 3
+ },
+ "max_retry_count": {
+ "minimum": 0,
+ "type": "integer",
+ "default": 0
+ },
+ "inactive_timeout": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 5
+ },
+ "include_req_body": {
+ "default": false,
+ "type": "boolean"
+ },
+ "batch_max_size": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 1000
+ },
+ "name": {
+ "default": "http logger",
+ "type": "string"
+ },
+ "concat_method": {
+ "type": "string",
+ "default": "json",
+ "enum": ["json", "new_line"]
+ },
+ "auth_header": {
+ "default": "",
+ "type": "string"
+ },
+ "retry_delay": {
+ "minimum": 0,
+ "type": "integer",
+ "default": 1
+ },
+ "uri": {
+ "type": "string"
+ },
+ "buffer_duration": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 60
+ }
+ }
+ }
+ },
+ "fault-injection": {
+ "schema": {
+ "minProperties": 1,
+ "type": "object",
+ "properties": {
+ "delay": {
+ "minProperties": 1,
+ "type": "object",
+ "properties": {
+ "percentage": {
+ "minimum": 0,
+ "type": "integer",
+ "maximum": 100
+ },
+ "duration": {
+ "minimum": 0,
+ "type": "number"
+ }
+ }
+ },
+ "abort": {
+ "minProperties": 1,
+ "type": "object",
+ "properties": {
+ "percentage": {
+ "minimum": 0,
+ "type": "integer",
+ "maximum": 100
+ },
+ "http_status": {
+ "minimum": 200,
+ "type": "integer"
+ },
+ "body": {
+ "minLength": 0,
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ },
+ "referer-restriction": {
+ "schema": {
+ "additionalProperties": false,
+ "type": "object",
+ "required": ["whitelist"],
+ "properties": {
+ "bypass_missing": {
+ "default": false,
+ "type": "boolean"
+ },
+ "whitelist": {
+ "items": {
+ "pattern": "^\\*?[0-9a-zA-Z-.]+$",
+ "type": "string"
+ },
+ "type": "array",
+ "minItems": 1
+ }
+ }
+ }
+ },
+ "uri-blocker": {
+ "schema": {
+ "type": "object",
+ "required": ["block_rules"],
+ "properties": {
+ "rejected_code": {
+ "minimum": 200,
+ "type": "integer",
+ "default": 403
+ },
+ "block_rules": {
+ "items": {
+ "type": "string",
+ "maxLength": 4096,
+ "minLength": 1
+ },
+ "type": "array",
+ "uniqueItems": true
+ }
+ }
+ }
+ },
+ "serverless-pre-function": {
+ "schema": {
+ "type": "object",
+ "required": ["functions"],
+ "properties": {
+ "phase": {
+ "enum": ["rewrite", "access", "header_filter", "body_filter", "log", "balancer"],
+ "type": "string"
+ },
+ "functions": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "minItems": 1
+ }
+ }
+ }
+ },
+ "proxy-mirror": {
+ "schema": {
+ "minProperties": 1,
+ "type": "object",
+ "required": ["host"],
+ "properties": {
+ "host": {
+ "pattern": "^http(s)?:\\/\\/[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(:[0-9]{1,5})?$",
+ "type": "string"
+ }
+ }
+ }
+ },
+ "basic-auth": {
+ "schema": {
+ "additionalProperties": false,
+ "type": "object",
+ "title": "work with route or service object",
+ "properties": {}
+ },
+ "consumer_schema": {
+ "type": "object",
+ "title": "work with consumer object",
+ "properties": {
+ "username": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": ["username", "password"]
+ }
+ },
+ "prometheus": {
+ "schema": {
+ "additionalProperties": false,
+ "type": "object"
+ }
+ },
+ "example-plugin": {
+ "schema": {
+ "type": "object",
+ "required": ["i"],
+ "properties": {
+ "i": {
+ "minimum": 0,
+ "type": "number"
+ },
+ "port": {
+ "type": "integer"
+ },
+ "s": {
+ "type": "string"
+ },
+ "t": {
+ "minItems": 1,
+ "type": "array"
+ },
+ "ip": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "log-rotate": {
+ "schema": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {}
+ }
+ },
+ "api-breaker": {
+ "schema": {
+ "type": "object",
+ "required": ["break_response_code"],
+ "properties": {
+ "max_breaker_sec": {
+ "minimum": 3,
+ "type": "integer",
+ "default": 300
+ },
+ "healthy": {
+ "type": "object",
+ "default": {
+ "http_statuses": [200],
+ "successes": 3
+ },
+ "properties": {
+ "http_statuses": {
+ "items": {
+ "minimum": 200,
+ "type": "integer",
+ "maximum": 499
+ },
+ "type": "array",
+ "default": [200],
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "successes": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 3
+ }
+ }
+ },
+ "break_response_code": {
+ "minimum": 200,
+ "type": "integer",
+ "maximum": 599
+ },
+ "unhealthy": {
+ "type": "object",
+ "default": {
+ "http_statuses": [500],
+ "failures": 3
+ },
+ "properties": {
+ "http_statuses": {
+ "items": {
+ "minimum": 500,
+ "type": "integer",
+ "maximum": 599
+ },
+ "type": "array",
+ "default": [500],
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "failures": {
+ "minimum": 1,
+ "type": "integer",
+ "default": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "batch-requests": {
+ "schema": {
+ "additionalProperties": false,
+ "type": "object"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/api/docker-compose.yml b/api/docker-compose.yml
deleted file mode 100644
index 5e91b30..0000000
--- a/api/docker-compose.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-version: '3'
-
-services:
- manager:
- image: golang:1.13.8
- volumes:
- - .:/go/src/github.com/apisix/manager-api
- working_dir: /go/src/github.com/apisix/manager-api
- command: go test -v github.com/apisix/manager-api/service
diff --git a/api/entry.sh b/api/entry.sh
index 8f7afbd..886e47c 100755
--- a/api/entry.sh
+++ b/api/entry.sh
@@ -16,22 +16,6 @@
# limitations under the License.
#
-pwd=`pwd`
-
-# config
-cp ${pwd}/api/conf/conf_preview.json ${pwd}/conf.json
-
-# export APIX_DAG_LIB_PATH="${pwd}/dag-to-lua-1.1/lib/"
-# export APIX_ETCD_ENDPOINTS="127.0.0.1:2379"
-
-export SYSLOG_HOST=127.0.0.1
-
-if [[ "$unamestr" == 'Darwin' ]]; then
- sed -i '' -e "s%#syslogAddress#%`echo $SYSLOG_HOST`%g" ${pwd}/conf.json
-else
- sed -i -e "s%#syslogAddress#%`echo $SYSLOG_HOST`%g" ${pwd}/conf.json
-fi
-
-cp ${pwd}/conf.json ${pwd}/api/conf/conf.json
+export ENV=prod
exec ./manager-api
diff --git a/api/filter/authentication.go b/api/filter/authentication.go
index 9928d2a..ba6c17c 100644
--- a/api/filter/authentication.go
+++ b/api/filter/authentication.go
@@ -33,7 +33,7 @@ func Authentication() gin.HandlerFunc {
// verify token
token, err := jwt.ParseWithClaims(tokenStr, &jwt.StandardClaims{}, func(token *jwt.Token) (interface{}, error) {
- return []byte(conf.AuthenticationConfig.Session.Secret), nil
+ return []byte(conf.AuthConf.Secret), nil
})
errResp := gin.H{
diff --git a/api/filter/logging.go b/api/filter/logging.go
index badf234..328ac4d 100644
--- a/api/filter/logging.go
+++ b/api/filter/logging.go
@@ -16,72 +16,4 @@
*/
package filter
-import (
- "bytes"
- "io/ioutil"
- "time"
-
- "github.com/gin-gonic/gin"
- "github.com/sirupsen/logrus"
-)
-
-func RequestLogHandler() gin.HandlerFunc {
- return func(c *gin.Context) {
- start, host, remoteIP, path, method := time.Now(), c.Request.Host, c.ClientIP(), c.Request.URL.Path, c.Request.Method
- var val interface{}
- if method == "GET" {
- val = c.Request.URL.Query()
- } else {
- val, _ = c.GetRawData()
-
- // set RequestBody back
- c.Request.Body = ioutil.NopCloser(bytes.NewReader(val.([]byte)))
- }
- c.Set("requestBody", val)
- uuid, _ := c.Get("X-Request-Id")
-
- param, _ := c.Get("requestBody")
-
- switch param.(type) {
- case []byte:
- param = string(param.([]byte))
- default:
- }
-
- blw := &bodyLogWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
- c.Writer = blw
- c.Next()
- latency := time.Now().Sub(start) / 1000000
- statusCode := c.Writer.Status()
- respBody := blw.body.String()
- if uuid == "" {
- uuid = c.Writer.Header().Get("X-Request-Id")
- }
- var errs []string
- for _, err := range c.Errors {
- errs = append(errs, err.Error())
- }
- logger.WithFields(logrus.Fields{
- "requestId": uuid,
- "latency": latency,
- "remoteIp": remoteIP,
- "method": method,
- "path": path,
- "statusCode": statusCode,
- "host": host,
- "params": param,
- "respBody": respBody,
- "errMsg": errs,
- }).Info("")
- }
-}
-
-type bodyLogWriter struct {
- gin.ResponseWriter
- body *bytes.Buffer
-}
-
-func (w bodyLogWriter) Write(b []byte) (int, error) {
- w.body.Write(b)
- return w.ResponseWriter.Write(b)
-}
+//for logging access log, will refactor it in a new pr.
diff --git a/api/filter/recover.go b/api/filter/recover.go
index a47e270..77e44a3 100644
--- a/api/filter/recover.go
+++ b/api/filter/recover.go
@@ -26,11 +26,9 @@ import (
"github.com/apisix/manager-api/log"
"github.com/gin-gonic/gin"
- "github.com/sirupsen/logrus"
)
var (
- logger = log.GetLogger()
dunno = []byte("???")
centerDot = []byte("·")
dot = []byte(".")
@@ -41,12 +39,13 @@ func RecoverHandler() gin.HandlerFunc {
return func(c *gin.Context) {
defer func() {
if err := recover(); err != nil {
- uuid := c.Writer.Header().Get("X-Request-Id")
- logger.WithFields(logrus.Fields{
- "uuid": uuid,
- })
+ fmt.Println("err;", err)
+ //uuid := c.Writer.Header().Get("X-Request-Id")
stack := stack(3)
- logger.Errorf("[Recovery] %s panic recovered:\n\n%s\n%s", timeFormat(time.Now()), err, stack)
+ fmt.Printf("[Recovery] %s panic recovered:\n\n%s\n%s", timeFormat(time.Now()), err, stack)
+
+ //log.With(zap.String("uuid", uuid))
+ log.Errorf("[Recovery] %s panic recovered:\n\n%s\n%s", timeFormat(time.Now()), err, stack)
c.AbortWithStatus(http.StatusInternalServerError)
}
}()
@@ -58,7 +57,7 @@ func WrapGo(f func(...interface{}), args ...interface{}) {
defer func() {
if err := recover(); err != nil {
stack := stack(3)
- logger.Errorf("[Recovery] %s panic recovered:\n\n%s\n%s", timeFormat(time.Now()), err, stack)
+ log.Errorf("[Recovery] %s panic recovered:\n\n%s\n%s", timeFormat(time.Now()), err, stack)
}
}()
f(args...)
diff --git a/api/go.mod b/api/go.mod
index 3f41ce6..d054357 100644
--- a/api/go.mod
+++ b/api/go.mod
@@ -17,6 +17,9 @@ require (
github.com/gin-gonic/gin v1.6.3
github.com/gogo/protobuf v1.3.1 // indirect
github.com/google/uuid v1.1.2 // indirect
+ github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
+ github.com/lestrrat-go/strftime v1.0.3 // indirect
+ github.com/natefinch/lumberjack v2.0.0+incompatible
github.com/satori/go.uuid v1.2.0
github.com/shiningrush/droplet v0.2.1
github.com/shiningrush/droplet/wrapper/gin v0.2.0
@@ -27,4 +30,5 @@ require (
github.com/xeipuuv/gojsonschema v1.2.0
go.etcd.io/etcd v3.3.25+incompatible
go.uber.org/zap v1.16.0
+ gopkg.in/yaml.v2 v2.3.0
)
diff --git a/api/go.sum b/api/go.sum
index 37089e0..c1e2010 100644
--- a/api/go.sum
+++ b/api/go.sum
@@ -1,43 +1,14 @@
-cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
-cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
-cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
-cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
-cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
-cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
-cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
-cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
-cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
-cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
-dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/api7/go-jsonpatch v0.0.0-20180223123257-a8710867776e h1:TX/8xM53DHaIIBr4wU+ifYI8IkUzS8+HrX8kzIzaaG0=
github.com/api7/go-jsonpatch v0.0.0-20180223123257-a8710867776e/go.mod h1:yc49guNPyTy2deyszk3erQN+2vO2NwLKPNicXurj7Hs=
-github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
-github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
-github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
-github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
-github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
-github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw=
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1/go.mod h1:dkChI7Tbtx7H1Tj7TqGSZMOeGpMP5gLHtjroHd4agiI=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
-github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
-github.com/coreos/etcd v3.3.13+incompatible h1:8F3hqu9fGYLBifCmRCJsicFqDx/D68Rt3q1JMazcgBQ=
-github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.25+incompatible h1:0GQEw6h3YnuOVdtwygkIfJ+Omx0tZ8/QkVyXI4LkbeY=
github.com/coreos/etcd v3.3.25+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
-github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
@@ -46,18 +17,11 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
-github.com/dgrijalva/jwt-go v1.0.2 h1:KPldsxuKGsS2FPWsNeg9ZO18aCrGKujPoWXn2yo+KQM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
-github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
-github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/pprof v1.3.0 h1:G9eK6HnbkSqDZBYbzG4wrjCsA4e+cvYAHUZw6W+W9K0=
github.com/gin-contrib/pprof v1.3.0/go.mod h1:waMjT1H9b179t3CxuG1cV3DHpga6ybizwfBaM5OXaB0=
github.com/gin-contrib/sessions v0.0.3 h1:PoBXki+44XdJdlgDqDrY5nDVe3Wk7wDV/UCOuLP6fBI=
@@ -71,10 +35,6 @@ github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwv
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
-github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
-github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
-github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
@@ -85,19 +45,11 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-playground/validator/v10 v10.3.0 h1:nZU+7q+yJoFmwvNgv/LnPUkwPal62+b2xXj0AU1Es7o=
github.com/go-playground/validator/v10 v10.3.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
-github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
-github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
@@ -109,23 +61,15 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
-github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
-github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
-github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
@@ -133,131 +77,64 @@ github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+
github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
github.com/gorilla/sessions v1.1.3 h1:uXoZdcdA5XdXF3QzuSlheVRUvjl+1rKY7zBXL68L9RU=
github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
-github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
-github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
-github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
-github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
-github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
-github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
-github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b/go.mod h1:g2nVr8KZVXJSS97Jo8pJ0jgq29P6H7dG0oplUA86MQw=
-github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
-github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
-github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
-github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is=
+github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4=
+github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA=
+github.com/lestrrat-go/strftime v1.0.3 h1:qqOPU7y+TM8Y803I8fG9c/DyKG3xH/xkng6keC1015Q=
+github.com/lestrrat-go/strftime v1.0.3/go.mod h1:E1nN3pCbtMSu1yjSVeyuRFVm/U0xoR76fd03sz+Qz4g=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
-github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/memcachier/mc v2.0.1+incompatible/go.mod h1:7bkvFE61leUBvXz+yxsOnGBQSZpBSPIMUQSmmSHvuXc=
-github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
-github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
-github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
-github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
-github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
-github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
-github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
-github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
-github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
-github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=
+github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=
+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
-github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
-github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/quasoft/memstore v0.0.0-20180925164028-84a050167438/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg=
-github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
-github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shiningrush/droplet v0.0.0-20191118073048-00b06fe19ce4/go.mod h1:E/th13n/wtPi+Cj2f0hAAEFeT3gb5xsS6Ob4WRrdxdM=
github.com/shiningrush/droplet v0.2.1 h1:p2utttTbCfgiL+x0Zrb2jFeWspB7/o+v3e+R94G6nm4=
github.com/shiningrush/droplet v0.2.1/go.mod h1:akW2vIeamvMD6zj6wIBfzYn6StGXBxwlW3gA+hcHu5M=
github.com/shiningrush/droplet/wrapper/gin v0.2.0 h1:LHkU+TbSkpePgXrTg3hJoSZlCMS03GeWMl0t+oLkd44=
github.com/shiningrush/droplet/wrapper/gin v0.2.0/go.mod h1:ZJu+sCRrVXn5Pg618c1KK3Ob2UiXGuPM1ROx5uMM9YQ=
-github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
-github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
-github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sony/sonyflake v1.0.0 h1:MpU6Ro7tfXwgn2l5eluf9xQvQJDROTBImNCfRXn/YeM=
github.com/sony/sonyflake v1.0.0/go.mod h1:Jv3cfhf/UFtolOTTRd3q4Nl6ENqM+KfyZ5PseKfZGF4=
-github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
-github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
-github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
-github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
-github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
-github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
-github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
-github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
-github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
-github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
-github.com/tidwall/gjson v1.6.0 h1:9VEQWz6LLMUsUl6PueE49ir4Ka6CzLymOAZDxpFsTDc=
-github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
github.com/tidwall/gjson v1.6.1 h1:LRbvNuNuvAiISWg6gxLEFuCe72UKy5hDqhxW/8183ws=
github.com/tidwall/gjson v1.6.1/go.mod h1:BaHyNc5bjzYkPqgLq7mdVzeiRtULKULXLgZFKsxEHI0=
github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
-github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
-github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
-github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
@@ -268,137 +145,53 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
-github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
-go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/etcd v0.5.0-alpha.5 h1:VOolFSo3XgsmnYDLozjvZ6JL6AAwIDu1Yx1y+4EYLDo=
go.etcd.io/etcd v3.3.25+incompatible h1:V1RzkZJj9LqsJRy+TUBgpWSbZXITLB819lstuTFoZOY=
go.etcd.io/etcd v3.3.25+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI=
-go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
-go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
-go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
-go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
-go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
-golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
-golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
-golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
-golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
-golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
-golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
-golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
-golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA=
-golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 h1:W0lCpv29Hv0UaM1LXb9QlBHLNP8UFfcKjblhVCWftOM=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200915084602-288bc346aa39 h1:356XA7ITklAU2//sYkjFeco+dH1bCRD8XCJ9FIEsvo4=
-golang.org/x/sys v0.0.0-20200915084602-288bc346aa39/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
-golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
-google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
-google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
-google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg=
@@ -413,28 +206,17 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
-gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
-gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
-gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
-gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
-gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
-rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
-sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
diff --git a/api/internal/core/entity/entity.go b/api/internal/core/entity/entity.go
index c15a5d5..93ae456 100644
--- a/api/internal/core/entity/entity.go
+++ b/api/internal/core/entity/entity.go
@@ -75,6 +75,7 @@ type Route struct {
UpstreamID string `json:"upstream_id,omitempty"`
ServiceProtocol string `json:"service_protocol,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
+ EnableWebsocket bool `json:"enable_websocket,omitempty"`
}
// --- structures for upstream start ---
@@ -138,21 +139,20 @@ type HealthChecker struct {
}
type UpstreamDef struct {
- Nodes interface{} `json:"nodes,omitempty"`
- Retries int `json:"retries,omitempty"`
- Timeout interface{} `json:"timeout,omitempty"`
- K8sInfo interface{} `json:"k8s_deployment_info,omitempty"`
- Type string `json:"type,omitempty"`
- Checks interface{} `json:"checks,omitempty"`
- HashOn string `json:"hash_on,omitempty"`
- Key string `json:"key,omitempty"`
- EnableWebsocket bool `json:"enable_websocket,omitempty"`
- PassHost string `json:"pass_host,omitempty"`
- UpstreamHost string `json:"upstream_host,omitempty"`
- Name string `json:"name,omitempty"`
- Desc string `json:"desc,omitempty"`
- ServiceName string `json:"service_name,omitempty"`
- Labels map[string]string `json:"labels,omitempty"`
+ Nodes interface{} `json:"nodes,omitempty"`
+ Retries int `json:"retries,omitempty"`
+ Timeout interface{} `json:"timeout,omitempty"`
+ K8sInfo interface{} `json:"k8s_deployment_info,omitempty"`
+ Type string `json:"type,omitempty"`
+ Checks interface{} `json:"checks,omitempty"`
+ HashOn string `json:"hash_on,omitempty"`
+ Key string `json:"key,omitempty"`
+ PassHost string `json:"pass_host,omitempty"`
+ UpstreamHost string `json:"upstream_host,omitempty"`
+ Name string `json:"name,omitempty"`
+ Desc string `json:"desc,omitempty"`
+ ServiceName string `json:"service_name,omitempty"`
+ Labels map[string]string `json:"labels,omitempty"`
}
type Upstream struct {
@@ -200,13 +200,14 @@ type SSL struct {
type Service struct {
BaseInfo
- Name string `json:"name,omitempty"`
- Desc string `json:"desc,omitempty"`
- Upstream *UpstreamDef `json:"upstream,omitempty"`
- UpstreamID string `json:"upstream_id,omitempty"`
- Plugins map[string]interface{} `json:"plugins,omitempty"`
- Script string `json:"script,omitempty"`
- Labels map[string]string `json:"labels,omitempty"`
+ Name string `json:"name,omitempty"`
+ Desc string `json:"desc,omitempty"`
+ Upstream *UpstreamDef `json:"upstream,omitempty"`
+ UpstreamID string `json:"upstream_id,omitempty"`
+ Plugins map[string]interface{} `json:"plugins,omitempty"`
+ Script string `json:"script,omitempty"`
+ Labels map[string]string `json:"labels,omitempty"`
+ EnableWebsocket bool `json:"enable_websocket,omitempty"`
}
type Script struct {
diff --git a/api/internal/core/entity/format.go b/api/internal/core/entity/format.go
index 0c5d8d1..a409644 100644
--- a/api/internal/core/entity/format.go
+++ b/api/internal/core/entity/format.go
@@ -23,8 +23,8 @@ import (
)
func NodesFormat(obj interface{}) interface{} {
+ var nodes []*Node
if value, ok := obj.(map[string]float64); ok {
- var nodes []*Node
var strArr []string
for key, val := range value {
node := &Node{}
@@ -48,5 +48,22 @@ func NodesFormat(obj interface{}) interface{} {
return nodes
}
+ if nodes, ok := obj.([]*Node); ok {
+ return nodes
+ }
+
+ if list, ok := obj.([]interface{}); ok {
+ for _, v := range list {
+ val := v.(map[string]interface{})
+ node := &Node{}
+ node.Host = val["host"].(string)
+ node.Port = int(val["port"].(float64))
+ node.Weight = int(val["weight"].(float64))
+ nodes = append(nodes, node)
+ }
+
+ return nodes
+ }
+
return obj
}
diff --git a/api/internal/core/entity/format_test.go b/api/internal/core/entity/format_test.go
index cc51bf2..5ba5e13 100644
--- a/api/internal/core/entity/format_test.go
+++ b/api/internal/core/entity/format_test.go
@@ -28,7 +28,9 @@ func TestConsumer(t *testing.T) {
"127.0.0.1:8080": 1
}`
nodesMap := map[string]float64{}
- json.Unmarshal([]byte(nodesStr), &nodesMap)
+ err := json.Unmarshal([]byte(nodesStr), &nodesMap)
+ assert.Nil(t, err)
+
res := NodesFormat(nodesMap)
nodes := res.([]*Node)
diff --git a/api/internal/core/storage/etcd.go b/api/internal/core/storage/etcd.go
index aff2d4a..5a9c23e 100644
--- a/api/internal/core/storage/etcd.go
+++ b/api/internal/core/storage/etcd.go
@@ -19,9 +19,10 @@ package storage
import (
"context"
"fmt"
+ "time"
+
"github.com/apisix/manager-api/internal/utils"
"go.etcd.io/etcd/clientv3"
- "time"
)
var (
@@ -132,6 +133,8 @@ func (s *EtcdV3Storage) Watch(ctx context.Context, key string) <-chan WatchRespo
}
ch <- output
}
+
+ close(ch)
}()
return ch
diff --git a/api/internal/core/store/query.go b/api/internal/core/store/query.go
index 7f59594..20036d0 100644
--- a/api/internal/core/store/query.go
+++ b/api/internal/core/store/query.go
@@ -16,6 +16,7 @@ package store
import (
"github.com/apisix/manager-api/internal/core/entity"
+ "github.com/apisix/manager-api/log"
)
type Query struct {
@@ -88,7 +89,7 @@ func NewQuery(sort *Sort, filter *Filter, pagination *Pagination) *Query {
func NewSort(sortRaw []string) *Sort {
if sortRaw == nil || len(sortRaw)%2 == 1 {
- // Empty sort list or invalid (odd) length
+ log.Info("empty sort for query")
return NoSort
}
list := []SortBy{}
@@ -117,6 +118,7 @@ func NewSort(sortRaw []string) *Sort {
func NewFilter(filterRaw []string) *Filter {
if filterRaw == nil || len(filterRaw)%2 == 1 {
+ log.Info("empty filter for query")
return NoFilter
}
list := []FilterBy{}
diff --git a/api/internal/core/store/store.go b/api/internal/core/store/store.go
index b285183..1627e2e 100644
--- a/api/internal/core/store/store.go
+++ b/api/internal/core/store/store.go
@@ -21,7 +21,6 @@ import (
"context"
"encoding/json"
"fmt"
- "log"
"reflect"
"sort"
"sync"
@@ -31,6 +30,7 @@ import (
"github.com/apisix/manager-api/internal/core/entity"
"github.com/apisix/manager-api/internal/core/storage"
+ "github.com/apisix/manager-api/log"
)
type Interface interface {
@@ -60,12 +60,15 @@ type GenericStoreOption struct {
func NewGenericStore(opt GenericStoreOption) (*GenericStore, error) {
if opt.BasePath == "" {
+ log.Warn("base path empty")
return nil, fmt.Errorf("base path can not be empty")
}
if opt.ObjType == nil {
+ log.Warn("object type is nil")
return nil, fmt.Errorf("object type can not be nil")
}
if opt.KeyFunc == nil {
+ log.Warn("key func is nil")
return nil, fmt.Errorf("key func can not be nil")
}
@@ -73,6 +76,7 @@ func NewGenericStore(opt GenericStoreOption) (*GenericStore, error) {
opt.ObjType = opt.ObjType.Elem()
}
if opt.ObjType.Kind() != reflect.Struct {
+ log.Warn("obj type is invalid")
return nil, fmt.Errorf("obj type is invalid")
}
s := &GenericStore{
@@ -106,7 +110,7 @@ func (s *GenericStore) Init() error {
go func() {
for event := range ch {
if event.Canceled {
- log.Println("watch failed", event.Error)
+ log.Warnf("watch failed: %w", event.Error)
}
for i := range event.Events {
@@ -114,7 +118,7 @@ func (s *GenericStore) Init() error {
case storage.EventTypePut:
objPtr, err := s.StringToObjPtr(event.Events[i].Value)
if err != nil {
- log.Println("value convert to obj failed", err)
+ log.Warnf("value convert to obj failed: %w", err)
continue
}
s.cache.Store(event.Events[i].Key[len(s.opt.BasePath)+1:], objPtr)
@@ -131,6 +135,7 @@ func (s *GenericStore) Init() error {
func (s *GenericStore) Get(key string) (interface{}, error) {
ret, ok := s.cache.Load(key)
if !ok {
+ log.Warnf("data not found by key: %s", key)
return nil, data.ErrNotFound
}
return ret, nil
@@ -213,6 +218,7 @@ func (s *GenericStore) List(input ListInput) (*ListOutput, error) {
func (s *GenericStore) ingestValidate(obj interface{}) (err error) {
if s.opt.Validator != nil {
if err := s.opt.Validator.Validate(obj); err != nil {
+ log.Infof("data validate fail: %w", err)
return err
}
}
@@ -244,11 +250,13 @@ func (s *GenericStore) Create(ctx context.Context, obj interface{}) error {
}
_, ok := s.cache.Load(key)
if ok {
+ log.Warnf("key: %s is conflicted", key)
return fmt.Errorf("key: %s is conflicted", key)
}
bs, err := json.Marshal(obj)
if err != nil {
+ log.Warnf("json marshal failed: %s", err)
return fmt.Errorf("json marshal failed: %s", err)
}
if err := s.Stg.Create(ctx, s.GetObjStorageKey(obj), string(bs)); err != nil {
@@ -272,6 +280,7 @@ func (s *GenericStore) Update(ctx context.Context, obj interface{}, createIfNotE
if createIfNotExist {
return s.Create(ctx, obj)
}
+ log.Warnf("key: %s is not found", key)
return fmt.Errorf("key: %s is not found", key)
}
@@ -284,6 +293,7 @@ func (s *GenericStore) Update(ctx context.Context, obj interface{}, createIfNotE
bs, err := json.Marshal(obj)
if err != nil {
+ log.Warnf("json marshal failed: %s", err)
return fmt.Errorf("json marshal failed: %s", err)
}
if err := s.Stg.Update(ctx, s.GetObjStorageKey(obj), string(bs)); err != nil {
@@ -311,6 +321,7 @@ func (s *GenericStore) StringToObjPtr(str string) (interface{}, error) {
objPtr := reflect.New(s.opt.ObjType)
err := json.Unmarshal([]byte(str), objPtr.Interface())
if err != nil {
+ log.Warnf("json marshal failed: %s", err)
return nil, fmt.Errorf("json unmarshal failed: %w", err)
}
diff --git a/api/internal/core/store/store_test.go b/api/internal/core/store/store_test.go
index 53f6a85..17a1e83 100644
--- a/api/internal/core/store/store_test.go
+++ b/api/internal/core/store/store_test.go
@@ -580,7 +580,8 @@ func TestGenericStore_Create(t *testing.T) {
createCalled = true
assert.Equal(t, tc.wantKey, args[1], tc.caseDesc)
input := TestStruct{}
- _ = json.Unmarshal([]byte(args[2].(string)), &input)
+ err := json.Unmarshal([]byte(args[2].(string)), &input)
+ assert.Nil(t, err)
assert.Equal(t, tc.giveObj.Field1, input.Field1, tc.caseDesc)
assert.Equal(t, tc.giveObj.Field2, input.Field2, tc.caseDesc)
assert.NotEqual(t, 0, len(input.ID), tc.caseDesc)
@@ -689,7 +690,8 @@ func TestGenericStore_Update(t *testing.T) {
createCalled = true
assert.Equal(t, tc.wantKey, args[1], tc.caseDesc)
input := TestStruct{}
- _ = json.Unmarshal([]byte(args[2].(string)), &input)
+ err := json.Unmarshal([]byte(args[2].(string)), &input)
+ assert.Nil(t, err)
assert.Equal(t, tc.giveObj.Field1, input.Field1, tc.caseDesc)
assert.Equal(t, tc.giveObj.Field2, input.Field2, tc.caseDesc)
assert.NotEqual(t, 0, input.UpdateTime, tc.caseDesc)
diff --git a/api/internal/core/store/storehub.go b/api/internal/core/store/storehub.go
index b2685c9..c38286e 100644
--- a/api/internal/core/store/storehub.go
+++ b/api/internal/core/store/storehub.go
@@ -22,6 +22,7 @@ import (
"github.com/apisix/manager-api/internal/core/entity"
"github.com/apisix/manager-api/internal/utils"
+ "github.com/apisix/manager-api/log"
)
type HubKey string
@@ -50,9 +51,11 @@ func InitStore(key HubKey, opt GenericStoreOption) error {
}
s, err := NewGenericStore(opt)
if err != nil {
+ log.Warnf("NewGenericStore error: %w", err)
return err
}
if err := s.Init(); err != nil {
+ log.Warnf("GenericStore init error: %w", err)
return err
}
diff --git a/api/internal/core/store/validate.go b/api/internal/core/store/validate.go
index ad3b978..23f7154 100644
--- a/api/internal/core/store/validate.go
+++ b/api/internal/core/store/validate.go
@@ -20,12 +20,14 @@ import (
"errors"
"fmt"
"io/ioutil"
+ "regexp"
"github.com/xeipuuv/gojsonschema"
"go.uber.org/zap/buffer"
"github.com/apisix/manager-api/conf"
"github.com/apisix/manager-api/internal/core/entity"
+ "github.com/apisix/manager-api/log"
)
type Validator interface {
@@ -75,11 +77,13 @@ type APISIXJsonSchemaValidator struct {
func NewAPISIXJsonSchemaValidator(jsonPath string) (Validator, error) {
schemaDef := conf.Schema.Get(jsonPath).String()
if schemaDef == "" {
+ log.Warnf("scheme validate failed: schema not found, path: %s", jsonPath)
return nil, fmt.Errorf("scheme validate failed: schema not found, path: %s", jsonPath)
}
s, err := gojsonschema.NewSchema(gojsonschema.NewStringLoader(schemaDef))
if err != nil {
+ log.Warnf("new schema failed: %w", err)
return nil, fmt.Errorf("new schema failed: %w", err)
}
return &APISIXJsonSchemaValidator{
@@ -87,19 +91,22 @@ func NewAPISIXJsonSchemaValidator(jsonPath string) (Validator, error) {
}, nil
}
-func getPlugins(reqBody interface{}) map[string]interface{} {
- switch reqBody.(type) {
+func getPlugins(reqBody interface{}) (map[string]interface{}, string) {
+ switch bodyType := reqBody.(type) {
case *entity.Route:
+ log.Infof("type of reqBody: %#v", bodyType)
route := reqBody.(*entity.Route)
- return route.Plugins
+ return route.Plugins, "schema"
case *entity.Service:
+ log.Infof("type of reqBody: %#v", bodyType)
service := reqBody.(*entity.Service)
- return service.Plugins
+ return service.Plugins, "schema"
case *entity.Consumer:
+ log.Infof("type of reqBody: %#v", bodyType)
consumer := reqBody.(*entity.Consumer)
- return consumer.Plugins
+ return consumer.Plugins, "consumer_schema"
}
- return nil
+ return nil, ""
}
func cHashKeySchemaCheck(upstream *entity.UpstreamDef) error {
@@ -109,7 +116,7 @@ func cHashKeySchemaCheck(upstream *entity.UpstreamDef) error {
if upstream.HashOn != "vars" &&
upstream.HashOn != "header" &&
upstream.HashOn != "cookie" {
- fmt.Errorf("invalid hash_on type: %s", upstream.HashOn)
+ return fmt.Errorf("invalid hash_on type: %s", upstream.HashOn)
}
var schemaDef string
@@ -187,9 +194,10 @@ func checkUpstream(upstream *entity.UpstreamDef) error {
}
func checkConf(reqBody interface{}) error {
- switch reqBody.(type) {
+ switch bodyType := reqBody.(type) {
case *entity.Route:
route := reqBody.(*entity.Route)
+ log.Infof("type of reqBody: %#v", bodyType)
if err := checkUpstream(route.Upstream); err != nil {
return err
}
@@ -210,6 +218,7 @@ func checkConf(reqBody interface{}) error {
func (v *APISIXJsonSchemaValidator) Validate(obj interface{}) error {
ret, err := v.schema.Validate(gojsonschema.NewGoLoader(obj))
if err != nil {
+ log.Warnf("scheme validate failed: %w", err)
return fmt.Errorf("scheme validate failed: %w", err)
}
@@ -229,35 +238,41 @@ func (v *APISIXJsonSchemaValidator) Validate(obj interface{}) error {
return err
}
- //check plugin json schema
- plugins := getPlugins(obj)
- if plugins != nil {
- for pluginName, pluginConf := range plugins {
- schemaDef := conf.Schema.Get("plugins." + pluginName).String()
- if schemaDef == "" {
- return fmt.Errorf("scheme validate failed: schema not found, path: %s", "plugins."+pluginName)
- }
+ plugins, schemaType := getPlugins(obj)
+ //fix lua json.encode transform lua{properties={}} to json{"properties":[]}
+ reg := regexp.MustCompile(`\"properties\":\[\]`)
+ for pluginName, pluginConf := range plugins {
+ var schemaDef string
+ schemaDef = conf.Schema.Get("plugins." + pluginName + "." + schemaType).String()
+ if schemaDef == "" && schemaType == "consumer_schema" {
+ schemaDef = conf.Schema.Get("plugins." + pluginName + ".schema").String()
+ }
+ if schemaDef == "" {
+ log.Warnf("scheme validate failed: schema not found, path: %s", "plugins."+pluginName)
+ return fmt.Errorf("scheme validate failed: schema not found, path: %s", "plugins."+pluginName)
+ }
- s, err := gojsonschema.NewSchema(gojsonschema.NewStringLoader(schemaDef))
- if err != nil {
- return fmt.Errorf("scheme validate failed: %w", err)
- }
+ schemaDef = reg.ReplaceAllString(schemaDef, `"properties":{}`)
+ s, err := gojsonschema.NewSchema(gojsonschema.NewStringLoader(schemaDef))
+ if err != nil {
+ log.Warnf("init scheme validate failed: %w", err)
+ return fmt.Errorf("scheme validate failed: %w", err)
+ }
- ret, err := s.Validate(gojsonschema.NewGoLoader(pluginConf))
- if err != nil {
- return fmt.Errorf("scheme validate failed: %w", err)
- }
+ ret, err := s.Validate(gojsonschema.NewGoLoader(pluginConf))
+ if err != nil {
+ return fmt.Errorf("scheme validate failed: %w", err)
+ }
- if !ret.Valid() {
- errString := buffer.Buffer{}
- for i, vErr := range ret.Errors() {
- if i != 0 {
- errString.AppendString("\n")
- }
- errString.AppendString(vErr.String())
+ if !ret.Valid() {
+ errString := buffer.Buffer{}
+ for i, vErr := range ret.Errors() {
+ if i != 0 {
+ errString.AppendString("\n")
}
- return fmt.Errorf("scheme validate failed: %s", errString.String())
+ errString.AppendString(vErr.String())
}
+ return fmt.Errorf("scheme validate failed: %s", errString.String())
}
}
diff --git a/api/internal/core/store/validate_test.go b/api/internal/core/store/validate_test.go
index f2494dc..3a47f12 100644
--- a/api/internal/core/store/validate_test.go
+++ b/api/internal/core/store/validate_test.go
@@ -76,20 +76,20 @@ func TestAPISIXJsonSchemaValidator_Validate(t *testing.T) {
consumer := &entity.Consumer{}
reqBody := `{
- "id": "jack",
- "username": "jack",
- "plugins": {
- "limit-count": {
- "count": 2,
- "time_window": 60,
- "rejected_code": 503,
- "key": "remote_addr"
- }
- },
- "desc": "test description"
- }`
- json.Unmarshal([]byte(reqBody), consumer)
-
+ "id": "jack",
+ "username": "jack",
+ "plugins": {
+ "limit-count": {
+ "count": 2,
+ "time_window": 60,
+ "rejected_code": 503,
+ "key": "remote_addr"
+ }
+ },
+ "desc": "test description"
+ }`
+ err = json.Unmarshal([]byte(reqBody), consumer)
+ assert.Nil(t, err)
err = validator.Validate(consumer)
assert.Nil(t, err)
@@ -106,7 +106,8 @@ func TestAPISIXJsonSchemaValidator_Validate(t *testing.T) {
},
"desc": "test description"
}`
- json.Unmarshal([]byte(reqBody), consumer2)
+ err = json.Unmarshal([]byte(reqBody), consumer2)
+ assert.Nil(t, err)
err = validator.Validate(consumer2)
assert.NotNil(t, err)
@@ -131,8 +132,8 @@ func TestAPISIXJsonSchemaValidator_Validate(t *testing.T) {
},
"desc": "test description"
}`
- json.Unmarshal([]byte(reqBody), consumer3)
-
+ err = json.Unmarshal([]byte(reqBody), consumer3)
+ assert.Nil(t, err)
err = validator.Validate(consumer3)
assert.NotNil(t, err)
assert.EqualError(t, err, "scheme validate failed: (root): count is required")
@@ -146,39 +147,39 @@ func TestAPISIXJsonSchemaValidator_checkUpstream(t *testing.T) {
// type:chash, hash_on: consumer, missing key, ok
route := &entity.Route{}
reqBody := `{
- "id": "1",
- "methods": ["GET"],
- "upstream": {
- "nodes": {
- "127.0.0.1:8080": 1
- },
- "type": "chash",
- "hash_on":"consumer"
- },
- "desc": "new route",
- "uri": "/index.html"
- }`
- json.Unmarshal([]byte(reqBody), route)
-
+ "id": "1",
+ "methods": ["GET"],
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:8080": 1
+ },
+ "type": "chash",
+ "hash_on":"consumer"
+ },
+ "desc": "new route",
+ "uri": "/index.html"
+ }`
+ err = json.Unmarshal([]byte(reqBody), route)
+ assert.Nil(t, err)
err = validator.Validate(route)
assert.Nil(t, err)
// type:chash, hash_on: default(vars), missing key
route2 := &entity.Route{}
reqBody = `{
- "id": "1",
- "methods": ["GET"],
- "upstream": {
- "nodes": {
- "127.0.0.1:8080": 1
- },
- "type": "chash"
- },
- "desc": "new route",
- "uri": "/index.html"
- }`
- json.Unmarshal([]byte(reqBody), route2)
-
+ "id": "1",
+ "methods": ["GET"],
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:8080": 1
+ },
+ "type": "chash"
+ },
+ "desc": "new route",
+ "uri": "/index.html"
+ }`
+ err = json.Unmarshal([]byte(reqBody), route2)
+ assert.Nil(t, err)
err = validator.Validate(route2)
assert.NotNil(t, err)
assert.EqualError(t, err, "missing key")
@@ -186,20 +187,20 @@ func TestAPISIXJsonSchemaValidator_checkUpstream(t *testing.T) {
//type:chash, hash_on: header, missing key
route3 := &entity.Route{}
reqBody = `{
- "id": "1",
- "methods": ["GET"],
- "upstream": {
- "nodes": {
- "127.0.0.1:8080": 1
- },
- "type": "chash",
- "hash_on":"header"
- },
- "desc": "new route",
- "uri": "/index.html"
- }`
- json.Unmarshal([]byte(reqBody), route3)
-
+ "id": "1",
+ "methods": ["GET"],
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:8080": 1
+ },
+ "type": "chash",
+ "hash_on":"header"
+ },
+ "desc": "new route",
+ "uri": "/index.html"
+ }`
+ err = json.Unmarshal([]byte(reqBody), route3)
+ assert.Nil(t, err)
err = validator.Validate(route3)
assert.NotNil(t, err)
assert.EqualError(t, err, "missing key")
@@ -207,20 +208,20 @@ func TestAPISIXJsonSchemaValidator_checkUpstream(t *testing.T) {
//type:chash, hash_on: cookie, missing key
route4 := &entity.Route{}
reqBody = `{
- "id": "1",
- "methods": ["GET"],
- "upstream": {
- "nodes": {
- "127.0.0.1:8080": 1
- },
- "type": "chash",
- "hash_on":"cookie"
- },
- "desc": "new route",
- "uri": "/index.html"
- }`
- json.Unmarshal([]byte(reqBody), route4)
-
+ "id": "1",
+ "methods": ["GET"],
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:8080": 1
+ },
+ "type": "chash",
+ "hash_on":"cookie"
+ },
+ "desc": "new route",
+ "uri": "/index.html"
+ }`
+ err = json.Unmarshal([]byte(reqBody), route4)
+ assert.Nil(t, err)
err = validator.Validate(route4)
assert.NotNil(t, err)
assert.EqualError(t, err, "missing key")
@@ -228,21 +229,21 @@ func TestAPISIXJsonSchemaValidator_checkUpstream(t *testing.T) {
//type:chash, hash_on: vars, wrong key
route5 := &entity.Route{}
reqBody = `{
- "id": "1",
- "methods": ["GET"],
- "upstream": {
- "nodes": {
- "127.0.0.1:8080": 1
- },
- "type": "chash",
- "hash_on":"vars",
- "key": "not_support"
- },
- "desc": "new route",
- "uri": "/index.html"
- }`
- json.Unmarshal([]byte(reqBody), route5)
-
+ "id": "1",
+ "methods": ["GET"],
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:8080": 1
+ },
+ "type": "chash",
+ "hash_on":"vars",
+ "key": "not_support"
+ },
+ "desc": "new route",
+ "uri": "/index.html"
+ }`
+ err = json.Unmarshal([]byte(reqBody), route5)
+ assert.Nil(t, err)
err = validator.Validate(route5)
assert.NotNil(t, err)
assert.EqualError(t, err, "scheme validate failed: (root): Does not match pattern '^((uri|server_name|server_addr|request_uri|remote_port|remote_addr|query_string|host|hostname)|arg_[0-9a-zA-z_-]+)$'")
diff --git a/api/internal/handler/authentication/authentication.go b/api/internal/handler/authentication/authentication.go
index 5f3a83b..c3f242d 100644
--- a/api/internal/handler/authentication/authentication.go
+++ b/api/internal/handler/authentication/authentication.go
@@ -66,10 +66,10 @@ func (h *Handler) userLogin(c droplet.Context) (interface{}, error) {
claims := jwt.StandardClaims{
Subject: username,
IssuedAt: time.Now().Unix(),
- ExpiresAt: time.Now().Add(time.Second * time.Duration(conf.AuthenticationConfig.Session.ExpireTime)).Unix(),
+ ExpiresAt: time.Now().Add(time.Second * time.Duration(conf.AuthConf.ExpireTime)).Unix(),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
- signedToken, _ := token.SignedString([]byte(conf.AuthenticationConfig.Session.Secret))
+ signedToken, _ := token.SignedString([]byte(conf.AuthConf.Secret))
// output token
return &UserSession{
diff --git a/api/internal/handler/authentication/authentication_test.go b/api/internal/handler/authentication/authentication_test.go
index 01241a9..e1a7e50 100644
--- a/api/internal/handler/authentication/authentication_test.go
+++ b/api/internal/handler/authentication/authentication_test.go
@@ -36,10 +36,11 @@ func TestAuthentication(t *testing.T) {
reqBody := `{
"username": "admin",
"password": "admin"
- }`
- json.Unmarshal([]byte(reqBody), input)
+ }`
+ err := json.Unmarshal([]byte(reqBody), input)
+ assert.Nil(t, err)
ctx.SetInput(input)
- _, err := handler.userLogin(ctx)
+ _, err = handler.userLogin(ctx)
assert.Nil(t, err)
//username error
@@ -47,8 +48,9 @@ func TestAuthentication(t *testing.T) {
reqBody = `{
"username": "sdfasdf",
"password": "admin"
- }`
- json.Unmarshal([]byte(reqBody), input2)
+ }`
+ err = json.Unmarshal([]byte(reqBody), input2)
+ assert.Nil(t, err)
ctx.SetInput(input2)
_, err = handler.userLogin(ctx)
assert.EqualError(t, err, "username or password error")
@@ -58,8 +60,9 @@ func TestAuthentication(t *testing.T) {
reqBody = `{
"username": "admin",
"password": "admin9384938"
- }`
- json.Unmarshal([]byte(reqBody), input3)
+ }`
+ err = json.Unmarshal([]byte(reqBody), input3)
+ assert.Nil(t, err)
ctx.SetInput(input3)
_, err = handler.userLogin(ctx)
assert.EqualError(t, err, "username or password error")
diff --git a/api/internal/handler/consumer/consumer.go b/api/internal/handler/consumer/consumer.go
index 9ceb853..a37c958 100644
--- a/api/internal/handler/consumer/consumer.go
+++ b/api/internal/handler/consumer/consumer.go
@@ -105,6 +105,13 @@ func (h *Handler) Create(c droplet.Context) (interface{}, error) {
}
input.ID = input.Username
+ if _, ok := input.Plugins["jwt-auth"]; ok {
+ jwt := input.Plugins["jwt-auth"].(map[string]interface{})
+ jwt["exp"] = 86400
+
+ input.Plugins["jwt-auth"] = jwt
+ }
+
if err := h.consumerStore.Create(c.Context(), input); err != nil {
return handler.SpecCodeResponse(err), err
}
@@ -128,6 +135,13 @@ func (h *Handler) Update(c droplet.Context) (interface{}, error) {
}
input.Consumer.ID = input.Consumer.Username
+ if _, ok := input.Consumer.Plugins["jwt-auth"]; ok {
+ jwt := input.Consumer.Plugins["jwt-auth"].(map[string]interface{})
+ jwt["exp"] = 86400
+
+ input.Consumer.Plugins["jwt-auth"] = jwt
+ }
+
if err := h.consumerStore.Update(c.Context(), &input.Consumer, true); err != nil {
//if not exists, create
if err.Error() == fmt.Sprintf("key: %s is not found", input.Username) {
diff --git a/api/internal/handler/consumer/consumer_test.go b/api/internal/handler/consumer/consumer_test.go
index 22664fa..1f88c52 100644
--- a/api/internal/handler/consumer/consumer_test.go
+++ b/api/internal/handler/consumer/consumer_test.go
@@ -57,7 +57,8 @@ func TestConsumer(t *testing.T) {
},
"desc": "test description"
}`
- json.Unmarshal([]byte(reqBody), consumer)
+ err = json.Unmarshal([]byte(reqBody), consumer)
+ assert.Nil(t, err)
ctx.SetInput(consumer)
_, err = handler.Create(ctx)
assert.Nil(t, err)
@@ -65,18 +66,19 @@ func TestConsumer(t *testing.T) {
//create consumer 2
consumer2 := &entity.Consumer{}
reqBody = `{
- "username": "pony",
- "plugins": {
- "limit-count": {
- "count": 2,
- "time_window": 60,
- "rejected_code": 503,
- "key": "remote_addr"
- }
- },
- "desc": "test description"
- }`
- json.Unmarshal([]byte(reqBody), consumer2)
+ "username": "pony",
+ "plugins": {
+ "limit-count": {
+ "count": 2,
+ "time_window": 60,
+ "rejected_code": 503,
+ "key": "remote_addr"
+ }
+ },
+ "desc": "test description"
+ }`
+ err = json.Unmarshal([]byte(reqBody), consumer2)
+ assert.Nil(t, err)
ctx.SetInput(consumer2)
_, err = handler.Create(ctx)
assert.Nil(t, err)
@@ -87,7 +89,8 @@ func TestConsumer(t *testing.T) {
//get consumer
input := &GetInput{}
reqBody = `{"username": "jack"}`
- json.Unmarshal([]byte(reqBody), input)
+ err = json.Unmarshal([]byte(reqBody), input)
+ assert.Nil(t, err)
ctx.SetInput(input)
ret, err := handler.Get(ctx)
stored := ret.(*entity.Consumer)
@@ -99,18 +102,19 @@ func TestConsumer(t *testing.T) {
consumer3 := &UpdateInput{}
consumer3.Username = "pony"
reqBody = `{
- "username": "pony",
- "plugins": {
- "limit-count": {
- "count": 2,
- "time_window": 60,
- "rejected_code": 503,
- "key": "remote_addr"
- }
- },
- "desc": "test description2"
- }`
- json.Unmarshal([]byte(reqBody), consumer3)
+ "username": "pony",
+ "plugins": {
+ "limit-count": {
+ "count": 2,
+ "time_window": 60,
+ "rejected_code": 503,
+ "key": "remote_addr"
+ }
+ },
+ "desc": "test description2"
+ }`
+ err = json.Unmarshal([]byte(reqBody), consumer3)
+ assert.Nil(t, err)
ctx.SetInput(consumer3)
_, err = handler.Update(ctx)
assert.Nil(t, err)
@@ -121,7 +125,8 @@ func TestConsumer(t *testing.T) {
//check update
input3 := &GetInput{}
reqBody = `{"username": "pony"}`
- json.Unmarshal([]byte(reqBody), input3)
+ err = json.Unmarshal([]byte(reqBody), input3)
+ assert.Nil(t, err)
ctx.SetInput(input3)
ret3, err := handler.Get(ctx)
stored3 := ret3.(*entity.Consumer)
@@ -132,49 +137,59 @@ func TestConsumer(t *testing.T) {
//list page 1
listInput := &ListInput{}
reqBody = `{"page_size": 1, "page": 1}`
- json.Unmarshal([]byte(reqBody), listInput)
+ err = json.Unmarshal([]byte(reqBody), listInput)
+ assert.Nil(t, err)
ctx.SetInput(listInput)
retPage1, err := handler.List(ctx)
+ assert.Nil(t, err)
dataPage1 := retPage1.(*store.ListOutput)
assert.Equal(t, len(dataPage1.Rows), 1)
//list page 2
listInput2 := &ListInput{}
reqBody = `{"page_size": 1, "page": 2}`
- json.Unmarshal([]byte(reqBody), listInput2)
+ err = json.Unmarshal([]byte(reqBody), listInput2)
+ assert.Nil(t, err)
ctx.SetInput(listInput2)
retPage2, err := handler.List(ctx)
+ assert.Nil(t, err)
dataPage2 := retPage2.(*store.ListOutput)
assert.Equal(t, len(dataPage2.Rows), 1)
//list search match
listInput3 := &ListInput{}
reqBody = `{"page_size": 1, "page": 1, "username": "pony"}`
- json.Unmarshal([]byte(reqBody), listInput3)
+ err = json.Unmarshal([]byte(reqBody), listInput3)
+ assert.Nil(t, err)
ctx.SetInput(listInput3)
retPage, err := handler.List(ctx)
+ assert.Nil(t, err)
dataPage := retPage.(*store.ListOutput)
assert.Equal(t, len(dataPage.Rows), 1)
//list search not match
listInput4 := &ListInput{}
reqBody = `{"page_size": 1, "page": 1, "username": "not-exists"}`
- json.Unmarshal([]byte(reqBody), listInput4)
+ err = json.Unmarshal([]byte(reqBody), listInput4)
+ assert.Nil(t, err)
ctx.SetInput(listInput4)
retPage, err = handler.List(ctx)
+ assert.Nil(t, err)
dataPage = retPage.(*store.ListOutput)
assert.Equal(t, len(dataPage.Rows), 0)
//delete consumer
inputDel := &BatchDelete{}
reqBody = `{"usernames": "jack"}`
- json.Unmarshal([]byte(reqBody), inputDel)
+ err = json.Unmarshal([]byte(reqBody), inputDel)
+ assert.Nil(t, err)
ctx.SetInput(inputDel)
_, err = handler.BatchDelete(ctx)
assert.Nil(t, err)
reqBody = `{"usernames": "pony"}`
- json.Unmarshal([]byte(reqBody), inputDel)
+ err = json.Unmarshal([]byte(reqBody), inputDel)
+ assert.Nil(t, err)
ctx.SetInput(inputDel)
_, err = handler.BatchDelete(ctx)
assert.Nil(t, err)
@@ -192,7 +207,8 @@ func TestConsumer(t *testing.T) {
},
"desc": "test description"
}`
- json.Unmarshal([]byte(reqBody), consumer_fail)
+ err = json.Unmarshal([]byte(reqBody), consumer_fail)
+ assert.Nil(t, err)
ctx.SetInput(consumer_fail)
_, err = handler.Create(ctx)
assert.NotNil(t, err)
@@ -211,7 +227,8 @@ func TestConsumer(t *testing.T) {
},
"desc": "test description"
}`
- json.Unmarshal([]byte(reqBody), consumer6)
+ err = json.Unmarshal([]byte(reqBody), consumer6)
+ assert.Nil(t, err)
ctx.SetInput(consumer6)
_, err = handler.Update(ctx)
assert.Nil(t, err)
@@ -221,7 +238,8 @@ func TestConsumer(t *testing.T) {
//delete consumer
reqBody = `{"usernames": "nnn"}`
- json.Unmarshal([]byte(reqBody), inputDel)
+ err = json.Unmarshal([]byte(reqBody), inputDel)
+ assert.Nil(t, err)
ctx.SetInput(inputDel)
_, err = handler.BatchDelete(ctx)
assert.Nil(t, err)
diff --git a/api/internal/handler/plugin/plugin.go b/api/internal/handler/plugin/plugin.go
index 354c562..6f46655 100644
--- a/api/internal/handler/plugin/plugin.go
+++ b/api/internal/handler/plugin/plugin.go
@@ -42,12 +42,22 @@ func (h *Handler) ApplyRoute(r *gin.Engine) {
}
type GetInput struct {
- Name string `auto_read:"name,path" validate:"required"`
+ Name string `auto_read:"name,path" validate:"required"`
+ SchemaType string `auto_read:"schema_type,query"`
}
func (h *Handler) Schema(c droplet.Context) (interface{}, error) {
input := c.Input().(*GetInput)
- ret := conf.Schema.Get("plugins." + input.Name).Value()
+
+ var ret interface{}
+ if input.SchemaType == "consumer" {
+ ret = conf.Schema.Get("plugins." + input.Name + ".consumer_schema").Value()
+ if ret == nil {
+ ret = conf.Schema.Get("plugins." + input.Name + ".schema").Value()
+ }
+ } else {
+ ret = conf.Schema.Get("plugins." + input.Name + ".schema").Value()
+ }
return ret, nil
}
@@ -55,7 +65,7 @@ func (h *Handler) Plugins(c droplet.Context) (interface{}, error) {
list := conf.Schema.Get("plugins").Map()
var ret []string
- for pluginName, _ := range list {
+ for pluginName := range list {
if pluginName != "serverless-post-function" && pluginName != "serverless-pre-function" {
ret = append(ret, pluginName)
}
diff --git a/api/internal/handler/plugin/plugin_test.go b/api/internal/handler/plugin/plugin_test.go
index d962a6a..85ac9d9 100644
--- a/api/internal/handler/plugin/plugin_test.go
+++ b/api/internal/handler/plugin/plugin_test.go
@@ -40,19 +40,61 @@ func TestPlugin(t *testing.T) {
input := &GetInput{}
reqBody := `{
"name": "limit-count"
- }`
- json.Unmarshal([]byte(reqBody), input)
+ }`
+ err = json.Unmarshal([]byte(reqBody), input)
+ assert.Nil(t, err)
ctx.SetInput(input)
val, _ := handler.Schema(ctx)
assert.NotNil(t, val)
//not exists
- input2 := &GetInput{}
reqBody = `{
"name": "not-exists"
- }`
- json.Unmarshal([]byte(reqBody), input2)
- ctx.SetInput(input2)
+ }`
+ err = json.Unmarshal([]byte(reqBody), input)
+ assert.Nil(t, err)
+ ctx.SetInput(input)
val, _ = handler.Schema(ctx)
assert.Nil(t, val)
+
+ /*
+ get plugin schema with schema_type: consumer
+ plugin has consumer_schema
+ return plugin`s consumer_schema
+ */
+ reqBody = `{
+ "name": "jwt-auth",
+ "schema_type": "consumer"
+ }`
+ json.Unmarshal([]byte(reqBody), input)
+ ctx.SetInput(input)
+ val, _ = handler.Schema(ctx)
+ assert.NotNil(t, val)
+
+ /*
+ get plugin schema with schema_type: consumer
+ plugin does not have consumer_schema
+ return plugin`s schema
+ */
+ reqBody = `{
+ "name": "limit-count",
+ "schema_type": "consumer"
+ }`
+ json.Unmarshal([]byte(reqBody), input)
+ ctx.SetInput(input)
+ val, _ = handler.Schema(ctx)
+ assert.NotNil(t, val)
+
+ /*
+ get plugin schema with wrong schema_type: type,
+ return plugin`s schema
+ */
+ reqBody = `{
+ "name": "jwt-auth",
+ "schema_type": "type"
+ }`
+ json.Unmarshal([]byte(reqBody), input)
+ ctx.SetInput(input)
+ val, _ = handler.Schema(ctx)
+ assert.NotNil(t, val)
}
diff --git a/api/internal/handler/route/route.go b/api/internal/handler/route/route.go
index 5794951..bab3e9a 100644
--- a/api/internal/handler/route/route.go
+++ b/api/internal/handler/route/route.go
@@ -37,6 +37,7 @@ import (
"github.com/apisix/manager-api/internal/handler"
"github.com/apisix/manager-api/internal/utils"
"github.com/apisix/manager-api/internal/utils/consts"
+ "github.com/apisix/manager-api/log"
)
type Handler struct {
@@ -174,7 +175,7 @@ func generateLuaCode(script map[string]interface{}) (string, error) {
}
cmd := exec.Command("sh", "-c",
- "cd "+conf.DagLibPath+" && lua cli.lua "+
+ "cd "+conf.WorkDir+"/dag-to-lua && lua cli.lua "+
"'"+string(scriptString)+"'")
stdout, _ := cmd.StdoutPipe()
@@ -250,6 +251,11 @@ func (h *Handler) Update(c droplet.Context) (interface{}, error) {
input.Route.ID = input.ID
}
+ if input.Route.Host != "" && len(input.Route.Hosts) > 0 {
+ return &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+ fmt.Errorf("only one of host or hosts is allowed")
+ }
+
//check depend
if input.ServiceID != "" {
_, err := h.svcStore.Get(input.ServiceID)
@@ -298,6 +304,14 @@ func (h *Handler) Update(c droplet.Context) (interface{}, error) {
return handler.SpecCodeResponse(err), err
}
}
+ } else {
+ //remove exists script
+ script, _ := h.scriptStore.Get(input.Route.ID)
+ if script != nil {
+ if err := h.scriptStore.BatchDelete(c.Context(), strings.Split(input.Route.ID, ",")); err != nil {
+ log.Warnf("delete script %s failed", input.Route.ID)
+ }
+ }
}
if err := h.routeStore.Update(c.Context(), &input.Route, true); err != nil {
@@ -320,7 +334,13 @@ func (h *Handler) BatchDelete(c droplet.Context) (interface{}, error) {
}
//delete stored script
- h.scriptStore.BatchDelete(c.Context(), strings.Split(input.IDs, ","))
+ if err := h.scriptStore.BatchDelete(c.Context(), strings.Split(input.IDs, ",")); err != nil {
+ //try again
+ log.Warn("try to delete script %s again", input.IDs)
+ if err := h.scriptStore.BatchDelete(c.Context(), strings.Split(input.IDs, ",")); err != nil {
+ return nil, nil
+ }
+ }
return nil, nil
}
diff --git a/api/internal/handler/route/route_test.go b/api/internal/handler/route/route_test.go
index 3f79cd3..00a86a3 100644
--- a/api/internal/handler/route/route_test.go
+++ b/api/internal/handler/route/route_test.go
@@ -51,342 +51,343 @@ func TestRoute(t *testing.T) {
ctx := droplet.NewContext()
route := &entity.Route{}
reqBody := `{
- "id": "1",
- "name": "aaaa",
- "uri": "/index.html",
- "hosts": ["foo.com", "*.bar.com"],
- "vars": [],
- "remote_addrs": ["127.0.0.0/8"],
- "methods": ["PUT", "GET"],
- "upstream": {
- "type": "roundrobin",
- "nodes": [{
- "host": "www.a.com",
- "port": 80,
- "weight": 1
- }]
- },
- "script":{
- "rule":{
- "root":"451106f8-560c-43a4-acf2-2a6ed0ea57b8",
- "451106f8-560c-43a4-acf2-2a6ed0ea57b8":[
- [
- "code == 403",
- "b93d622c-92ef-48b4-b6bb-57e1ce893ee3"
- ],
- [
- "",
- "988ef5c2-c896-4606-a666-3d4cbe24a731"
- ]
- ]
- },
- "conf":{
- "451106f8-560c-43a4-acf2-2a6ed0ea57b8":{
- "name":"uri-blocker",
- "conf":{
- "block_rules":[
- "root.exe",
- "root.m+"
- ],
- "rejected_code":403
- }
- },
- "988ef5c2-c896-4606-a666-3d4cbe24a731":{
- "name":"kafka-logger",
- "conf":{
- "batch_max_size":1000,
- "broker_list":{
-
- },
- "buffer_duration":60,
- "inactive_timeout":5,
- "include_req_body":false,
- "kafka_topic":"1",
- "key":"2",
- "max_retry_count":0,
- "name":"kafka logger",
- "retry_delay":1,
- "timeout":3
- }
- },
- "b93d622c-92ef-48b4-b6bb-57e1ce893ee3":{
- "name":"fault-injection",
- "conf":{
- "abort":{
- "body":"200",
- "http_status":300
- },
- "delay":{
- "duration":500
- }
- }
- }
- },
- "chart":{
- "hovered":{
-
- },
- "links":{
- "3a110c30-d6f3-40b1-a8ac-b828cfaa2489":{
- "from":{
- "nodeId":"3365eca3-4bc8-4769-bab3-1485dfd6a43c",
- "portId":"port3"
- },
- "id":"3a110c30-d6f3-40b1-a8ac-b828cfaa2489",
- "to":{
- "nodeId":"b93d622c-92ef-48b4-b6bb-57e1ce893ee3",
- "portId":"port1"
- }
- },
- "c1958993-c1ef-44b1-bb32-7fc6f34870c2":{
- "from":{
- "nodeId":"3365eca3-4bc8-4769-bab3-1485dfd6a43c",
- "portId":"port2"
- },
- "id":"c1958993-c1ef-44b1-bb32-7fc6f34870c2",
- "to":{
- "nodeId":"988ef5c2-c896-4606-a666-3d4cbe24a731",
- "portId":"port1"
- }
- },
- "f9c42bf6-c8aa-4e86-8498-8dfbc5c53c23":{
- "from":{
- "nodeId":"451106f8-560c-43a4-acf2-2a6ed0ea57b8",
- "portId":"port2"
- },
- "id":"f9c42bf6-c8aa-4e86-8498-8dfbc5c53c23",
- "to":{
- "nodeId":"3365eca3-4bc8-4769-bab3-1485dfd6a43c",
- "portId":"port1"
- }
- }
- },
- "nodes":{
- "3365eca3-4bc8-4769-bab3-1485dfd6a43c":{
- "id":"3365eca3-4bc8-4769-bab3-1485dfd6a43c",
- "orientation":0,
- "ports":{
- "port1":{
- "id":"port1",
- "position":{
- "x":107,
- "y":0
- },
- "type":"input"
- },
- "port2":{
- "id":"port2",
- "position":{
- "x":92,
- "y":96
- },
- "properties":{
- "value":"no"
- },
- "type":"output"
- },
- "port3":{
- "id":"port3",
- "position":{
- "x":122,
- "y":96
- },
- "properties":{
- "value":"yes"
- },
- "type":"output"
- }
- },
- "position":{
- "x":750.2627969928922,
- "y":301.0370335799397
- },
- "properties":{
- "customData":{
- "name":"code == 403",
- "type":1
- }
- },
- "size":{
- "height":96,
- "width":214
- },
- "type":"判断条件"
- },
- "451106f8-560c-43a4-acf2-2a6ed0ea57b8":{
- "id":"451106f8-560c-43a4-acf2-2a6ed0ea57b8",
- "orientation":0,
- "ports":{
- "port1":{
- "id":"port1",
- "position":{
- "x":100,
- "y":0
- },
- "properties":{
- "custom":"property"
- },
- "type":"input"
- },
- "port2":{
- "id":"port2",
- "position":{
- "x":100,
- "y":96
- },
- "properties":{
- "custom":"property"
- },
- "type":"output"
- }
- },
- "position":{
- "x":741.5684544145346,
- "y":126.75879247285502
- },
- "properties":{
- "customData":{
- "data":{
- "block_rules":[
- "root.exe",
- "root.m+"
- ],
- "rejected_code":403
- },
- "name":"uri-blocker",
- "type":0
- }
- },
- "size":{
- "height":96,
- "width":201
- },
- "type":"uri-blocker"
- },
- "988ef5c2-c896-4606-a666-3d4cbe24a731":{
- "id":"988ef5c2-c896-4606-a666-3d4cbe24a731",
- "orientation":0,
- "ports":{
- "port1":{
- "id":"port1",
- "position":{
- "x":106,
- "y":0
- },
- "properties":{
- "custom":"property"
- },
- "type":"input"
- },
- "port2":{
- "id":"port2",
- "position":{
- "x":106,
- "y":96
- },
- "properties":{
- "custom":"property"
- },
- "type":"output"
- }
- },
- "position":{
- "x":607.9687500000001,
- "y":471.17788461538447
- },
- "properties":{
- "customData":{
- "data":{
- "batch_max_size":1000,
- "broker_list":{
-
- },
- "buffer_duration":60,
- "inactive_timeout":5,
- "include_req_body":false,
- "kafka_topic":"1",
- "key":"2",
- "max_retry_count":0,
- "name":"kafka logger",
- "retry_delay":1,
- "timeout":3
- },
- "name":"kafka-logger",
- "type":0
- }
- },
- "size":{
- "height":96,
- "width":212
- },
- "type":"kafka-logger"
- },
- "b93d622c-92ef-48b4-b6bb-57e1ce893ee3":{
- "id":"b93d622c-92ef-48b4-b6bb-57e1ce893ee3",
- "orientation":0,
- "ports":{
- "port1":{
- "id":"port1",
- "position":{
- "x":110,
- "y":0
- },
- "properties":{
- "custom":"property"
- },
- "type":"input"
- },
- "port2":{
- "id":"port2",
- "position":{
- "x":110,
- "y":96
- },
- "properties":{
- "custom":"property"
- },
- "type":"output"
- }
- },
- "position":{
- "x":988.9074986362261,
- "y":478.62041800736495
- },
- "properties":{
- "customData":{
- "data":{
- "abort":{
- "body":"200",
- "http_status":300
- },
- "delay":{
- "duration":500
- }
- },
- "name":"fault-injection",
- "type":0
- }
- },
- "size":{
- "height":96,
- "width":219
- },
- "type":"fault-injection"
- }
- },
- "offset":{
- "x":-376.83,
- "y":87.98
- },
- "scale":0.832,
- "selected":{
- "id":"b93d622c-92ef-48b4-b6bb-57e1ce893ee3",
- "type":"node"
- }
- }
- }
- }`
- json.Unmarshal([]byte(reqBody), route)
+ "id": "1",
+ "name": "aaaa",
+ "uri": "/index.html",
+ "hosts": ["foo.com", "*.bar.com"],
+ "vars": [],
+ "remote_addrs": ["127.0.0.0/8"],
+ "methods": ["PUT", "GET"],
+ "upstream": {
+ "type": "roundrobin",
+ "nodes": [{
+ "host": "www.a.com",
+ "port": 80,
+ "weight": 1
+ }]
+ },
+ "script":{
+ "rule":{
+ "root":"451106f8-560c-43a4-acf2-2a6ed0ea57b8",
+ "451106f8-560c-43a4-acf2-2a6ed0ea57b8":[
+ [
+ "code == 403",
+ "b93d622c-92ef-48b4-b6bb-57e1ce893ee3"
+ ],
+ [
+ "",
+ "988ef5c2-c896-4606-a666-3d4cbe24a731"
+ ]
+ ]
+ },
+ "conf":{
+ "451106f8-560c-43a4-acf2-2a6ed0ea57b8":{
+ "name":"uri-blocker",
+ "conf":{
+ "block_rules":[
+ "root.exe",
+ "root.m+"
+ ],
+ "rejected_code":403
+ }
+ },
+ "988ef5c2-c896-4606-a666-3d4cbe24a731":{
+ "name":"kafka-logger",
+ "conf":{
+ "batch_max_size":1000,
+ "broker_list":{
+
+ },
+ "buffer_duration":60,
+ "inactive_timeout":5,
+ "include_req_body":false,
+ "kafka_topic":"1",
+ "key":"2",
+ "max_retry_count":0,
+ "name":"kafka logger",
+ "retry_delay":1,
+ "timeout":3
+ }
+ },
+ "b93d622c-92ef-48b4-b6bb-57e1ce893ee3":{
+ "name":"fault-injection",
+ "conf":{
+ "abort":{
+ "body":"200",
+ "http_status":300
+ },
+ "delay":{
+ "duration":500
+ }
+ }
+ }
+ },
+ "chart":{
+ "hovered":{
+
+ },
+ "links":{
+ "3a110c30-d6f3-40b1-a8ac-b828cfaa2489":{
+ "from":{
+ "nodeId":"3365eca3-4bc8-4769-bab3-1485dfd6a43c",
+ "portId":"port3"
+ },
+ "id":"3a110c30-d6f3-40b1-a8ac-b828cfaa2489",
+ "to":{
+ "nodeId":"b93d622c-92ef-48b4-b6bb-57e1ce893ee3",
+ "portId":"port1"
+ }
+ },
+ "c1958993-c1ef-44b1-bb32-7fc6f34870c2":{
+ "from":{
+ "nodeId":"3365eca3-4bc8-4769-bab3-1485dfd6a43c",
+ "portId":"port2"
+ },
+ "id":"c1958993-c1ef-44b1-bb32-7fc6f34870c2",
+ "to":{
+ "nodeId":"988ef5c2-c896-4606-a666-3d4cbe24a731",
+ "portId":"port1"
+ }
+ },
+ "f9c42bf6-c8aa-4e86-8498-8dfbc5c53c23":{
+ "from":{
+ "nodeId":"451106f8-560c-43a4-acf2-2a6ed0ea57b8",
+ "portId":"port2"
+ },
+ "id":"f9c42bf6-c8aa-4e86-8498-8dfbc5c53c23",
+ "to":{
+ "nodeId":"3365eca3-4bc8-4769-bab3-1485dfd6a43c",
+ "portId":"port1"
+ }
+ }
+ },
+ "nodes":{
+ "3365eca3-4bc8-4769-bab3-1485dfd6a43c":{
+ "id":"3365eca3-4bc8-4769-bab3-1485dfd6a43c",
+ "orientation":0,
+ "ports":{
+ "port1":{
+ "id":"port1",
+ "position":{
+ "x":107,
+ "y":0
+ },
+ "type":"input"
+ },
+ "port2":{
+ "id":"port2",
+ "position":{
+ "x":92,
+ "y":96
+ },
+ "properties":{
+ "value":"no"
+ },
+ "type":"output"
+ },
+ "port3":{
+ "id":"port3",
+ "position":{
+ "x":122,
+ "y":96
+ },
+ "properties":{
+ "value":"yes"
+ },
+ "type":"output"
+ }
+ },
+ "position":{
+ "x":750.2627969928922,
+ "y":301.0370335799397
+ },
+ "properties":{
+ "customData":{
+ "name":"code == 403",
+ "type":1
+ }
+ },
+ "size":{
+ "height":96,
+ "width":214
+ },
+ "type":"判断条件"
+ },
+ "451106f8-560c-43a4-acf2-2a6ed0ea57b8":{
+ "id":"451106f8-560c-43a4-acf2-2a6ed0ea57b8",
+ "orientation":0,
+ "ports":{
+ "port1":{
+ "id":"port1",
+ "position":{
+ "x":100,
+ "y":0
+ },
+ "properties":{
+ "custom":"property"
+ },
+ "type":"input"
+ },
+ "port2":{
+ "id":"port2",
+ "position":{
+ "x":100,
+ "y":96
+ },
+ "properties":{
+ "custom":"property"
+ },
+ "type":"output"
+ }
+ },
+ "position":{
+ "x":741.5684544145346,
+ "y":126.75879247285502
+ },
+ "properties":{
+ "customData":{
+ "data":{
+ "block_rules":[
+ "root.exe",
+ "root.m+"
+ ],
+ "rejected_code":403
+ },
+ "name":"uri-blocker",
+ "type":0
+ }
+ },
+ "size":{
+ "height":96,
+ "width":201
+ },
+ "type":"uri-blocker"
+ },
+ "988ef5c2-c896-4606-a666-3d4cbe24a731":{
+ "id":"988ef5c2-c896-4606-a666-3d4cbe24a731",
+ "orientation":0,
+ "ports":{
+ "port1":{
+ "id":"port1",
+ "position":{
+ "x":106,
+ "y":0
+ },
+ "properties":{
+ "custom":"property"
+ },
+ "type":"input"
+ },
+ "port2":{
+ "id":"port2",
+ "position":{
+ "x":106,
+ "y":96
+ },
+ "properties":{
+ "custom":"property"
+ },
+ "type":"output"
+ }
+ },
+ "position":{
+ "x":607.9687500000001,
+ "y":471.17788461538447
+ },
+ "properties":{
+ "customData":{
+ "data":{
+ "batch_max_size":1000,
+ "broker_list":{
+
+ },
+ "buffer_duration":60,
+ "inactive_timeout":5,
+ "include_req_body":false,
+ "kafka_topic":"1",
+ "key":"2",
+ "max_retry_count":0,
+ "name":"kafka logger",
+ "retry_delay":1,
+ "timeout":3
+ },
+ "name":"kafka-logger",
+ "type":0
+ }
+ },
+ "size":{
+ "height":96,
+ "width":212
+ },
+ "type":"kafka-logger"
+ },
+ "b93d622c-92ef-48b4-b6bb-57e1ce893ee3":{
+ "id":"b93d622c-92ef-48b4-b6bb-57e1ce893ee3",
+ "orientation":0,
+ "ports":{
+ "port1":{
+ "id":"port1",
+ "position":{
+ "x":110,
+ "y":0
+ },
+ "properties":{
+ "custom":"property"
+ },
+ "type":"input"
+ },
+ "port2":{
+ "id":"port2",
+ "position":{
+ "x":110,
+ "y":96
+ },
+ "properties":{
+ "custom":"property"
+ },
+ "type":"output"
+ }
+ },
+ "position":{
+ "x":988.9074986362261,
+ "y":478.62041800736495
+ },
+ "properties":{
+ "customData":{
+ "data":{
+ "abort":{
+ "body":"200",
+ "http_status":300
+ },
+ "delay":{
+ "duration":500
+ }
+ },
+ "name":"fault-injection",
+ "type":0
+ }
+ },
+ "size":{
+ "height":96,
+ "width":219
+ },
+ "type":"fault-injection"
+ }
+ },
+ "offset":{
+ "x":-376.83,
+ "y":87.98
+ },
+ "scale":0.832,
+ "selected":{
+ "id":"b93d622c-92ef-48b4-b6bb-57e1ce893ee3",
+ "type":"node"
+ }
+ }
+ }
+ }`
+ err = json.Unmarshal([]byte(reqBody), route)
+ assert.Nil(t, err)
ctx.SetInput(route)
_, err = handler.Create(ctx)
assert.Nil(t, err)
@@ -407,342 +408,343 @@ func TestRoute(t *testing.T) {
route2 := &UpdateInput{}
route2.ID = "1"
reqBody = `{
- "id": "1",
- "name": "aaaa",
- "uri": "/index.html",
- "hosts": ["foo.com", "*.bar.com"],
- "remote_addrs": ["127.0.0.0/8"],
- "methods": ["PUT", "GET"],
- "upstream": {
- "type": "roundrobin",
- "nodes": [{
- "host": "www.a.com",
- "port": 80,
- "weight": 1
- }]
- },
- "script":{
- "rule":{
- "root":"451106f8-560c-43a4-acf2-2a6ed0ea57b8",
- "451106f8-560c-43a4-acf2-2a6ed0ea57b8":[
- [
- "code == 403",
- "b93d622c-92ef-48b4-b6bb-57e1ce893ee3"
- ],
- [
- "",
- "988ef5c2-c896-4606-a666-3d4cbe24a731"
- ]
- ]
- },
- "conf":{
- "451106f8-560c-43a4-acf2-2a6ed0ea57b8":{
- "name":"uri-blocker",
- "conf":{
- "block_rules":[
- "root.exe",
- "root.m+"
- ],
- "rejected_code":403
- }
- },
- "988ef5c2-c896-4606-a666-3d4cbe24a731":{
- "name":"kafka-logger",
- "conf":{
- "batch_max_size":1000,
- "broker_list":{
-
- },
- "buffer_duration":60,
- "inactive_timeout":5,
- "include_req_body":false,
- "kafka_topic":"1",
- "key":"2",
- "max_retry_count":0,
- "name":"kafka logger",
- "retry_delay":1,
- "timeout":3
- }
- },
- "b93d622c-92ef-48b4-b6bb-57e1ce893ee3":{
- "name":"fault-injection",
- "conf":{
- "abort":{
- "body":"200",
- "http_status":300
- },
- "delay":{
- "duration":500
- }
- }
- }
- },
- "chart":{
- "hovered":{
-
- },
- "links":{
- "3a110c30-d6f3-40b1-a8ac-b828cfaa2489":{
- "from":{
- "nodeId":"3365eca3-4bc8-4769-bab3-1485dfd6a43c",
- "portId":"port3"
- },
- "id":"3a110c30-d6f3-40b1-a8ac-b828cfaa2489",
- "to":{
- "nodeId":"b93d622c-92ef-48b4-b6bb-57e1ce893ee3",
- "portId":"port1"
- }
- },
- "c1958993-c1ef-44b1-bb32-7fc6f34870c2":{
- "from":{
- "nodeId":"3365eca3-4bc8-4769-bab3-1485dfd6a43c",
- "portId":"port2"
- },
- "id":"c1958993-c1ef-44b1-bb32-7fc6f34870c2",
- "to":{
- "nodeId":"988ef5c2-c896-4606-a666-3d4cbe24a731",
- "portId":"port1"
- }
- },
- "f9c42bf6-c8aa-4e86-8498-8dfbc5c53c23":{
- "from":{
- "nodeId":"451106f8-560c-43a4-acf2-2a6ed0ea57b8",
- "portId":"port2"
- },
- "id":"f9c42bf6-c8aa-4e86-8498-8dfbc5c53c23",
- "to":{
- "nodeId":"3365eca3-4bc8-4769-bab3-1485dfd6a43c",
- "portId":"port1"
- }
- }
- },
- "nodes":{
- "3365eca3-4bc8-4769-bab3-1485dfd6a43c":{
- "id":"3365eca3-4bc8-4769-bab3-1485dfd6a43c",
- "orientation":0,
- "ports":{
- "port1":{
- "id":"port1",
- "position":{
- "x":107,
- "y":0
- },
- "type":"input"
- },
- "port2":{
- "id":"port2",
- "position":{
- "x":92,
- "y":96
- },
- "properties":{
- "value":"no"
- },
- "type":"output"
- },
- "port3":{
- "id":"port3",
- "position":{
- "x":122,
- "y":96
- },
- "properties":{
- "value":"yes"
- },
- "type":"output"
- }
- },
- "position":{
- "x":750.2627969928922,
- "y":301.0370335799397
- },
- "properties":{
- "customData":{
- "name":"code == 403",
- "type":1
- }
- },
- "size":{
- "height":96,
- "width":214
- },
- "type":"判断条件"
- },
- "451106f8-560c-43a4-acf2-2a6ed0ea57b8":{
- "id":"451106f8-560c-43a4-acf2-2a6ed0ea57b8",
- "orientation":0,
- "ports":{
- "port1":{
- "id":"port1",
- "position":{
- "x":100,
- "y":0
- },
- "properties":{
- "custom":"property"
- },
- "type":"input"
- },
- "port2":{
- "id":"port2",
- "position":{
- "x":100,
- "y":96
- },
- "properties":{
- "custom":"property"
- },
- "type":"output"
- }
- },
- "position":{
- "x":741.5684544145346,
- "y":126.75879247285502
- },
- "properties":{
- "customData":{
- "data":{
- "block_rules":[
- "root.exe",
- "root.m+"
- ],
- "rejected_code":403
- },
- "name":"uri-blocker",
- "type":0
- }
- },
- "size":{
- "height":96,
- "width":201
- },
- "type":"uri-blocker"
- },
- "988ef5c2-c896-4606-a666-3d4cbe24a731":{
- "id":"988ef5c2-c896-4606-a666-3d4cbe24a731",
- "orientation":0,
- "ports":{
- "port1":{
- "id":"port1",
- "position":{
- "x":106,
- "y":0
- },
- "properties":{
- "custom":"property"
- },
- "type":"input"
- },
- "port2":{
- "id":"port2",
- "position":{
- "x":106,
- "y":96
- },
- "properties":{
- "custom":"property"
- },
- "type":"output"
- }
- },
- "position":{
- "x":607.9687500000001,
- "y":471.17788461538447
- },
- "properties":{
- "customData":{
- "data":{
- "batch_max_size":1000,
- "broker_list":{
-
- },
- "buffer_duration":60,
- "inactive_timeout":5,
- "include_req_body":false,
- "kafka_topic":"1",
- "key":"2",
- "max_retry_count":0,
- "name":"kafka logger",
- "retry_delay":1,
- "timeout":3
- },
- "name":"kafka-logger",
- "type":0
- }
- },
- "size":{
- "height":96,
- "width":212
- },
- "type":"kafka-logger"
- },
- "b93d622c-92ef-48b4-b6bb-57e1ce893ee3":{
- "id":"b93d622c-92ef-48b4-b6bb-57e1ce893ee3",
- "orientation":0,
- "ports":{
- "port1":{
- "id":"port1",
- "position":{
- "x":110,
- "y":0
- },
- "properties":{
- "custom":"property"
- },
- "type":"input"
- },
- "port2":{
- "id":"port2",
- "position":{
- "x":110,
- "y":96
- },
- "properties":{
- "custom":"property"
- },
- "type":"output"
- }
- },
- "position":{
- "x":988.9074986362261,
- "y":478.62041800736495
- },
- "properties":{
- "customData":{
- "data":{
- "abort":{
- "body":"200",
- "http_status":300
- },
- "delay":{
- "duration":500
- }
- },
- "name":"fault-injection",
- "type":0
- }
- },
- "size":{
- "height":96,
- "width":219
- },
- "type":"fault-injection"
- }
- },
- "offset":{
- "x":-376.83,
- "y":87.98
- },
- "scale":0.832,
- "selected":{
- "id":"b93d622c-92ef-48b4-b6bb-57e1ce893ee3",
- "type":"node"
- }
- }
- }
- }`
-
- json.Unmarshal([]byte(reqBody), route2)
+ "id": "1",
+ "name": "aaaa",
+ "uri": "/index.html",
+ "hosts": ["foo.com", "*.bar.com"],
+ "remote_addrs": ["127.0.0.0/8"],
+ "methods": ["PUT", "GET"],
+ "upstream": {
+ "type": "roundrobin",
+ "nodes": [{
+ "host": "www.a.com",
+ "port": 80,
+ "weight": 1
+ }]
+ },
+ "script":{
+ "rule":{
+ "root":"451106f8-560c-43a4-acf2-2a6ed0ea57b8",
+ "451106f8-560c-43a4-acf2-2a6ed0ea57b8":[
+ [
+ "code == 403",
+ "b93d622c-92ef-48b4-b6bb-57e1ce893ee3"
+ ],
+ [
+ "",
+ "988ef5c2-c896-4606-a666-3d4cbe24a731"
+ ]
+ ]
+ },
+ "conf":{
+ "451106f8-560c-43a4-acf2-2a6ed0ea57b8":{
+ "name":"uri-blocker",
+ "conf":{
+ "block_rules":[
+ "root.exe",
+ "root.m+"
+ ],
+ "rejected_code":403
+ }
+ },
+ "988ef5c2-c896-4606-a666-3d4cbe24a731":{
+ "name":"kafka-logger",
+ "conf":{
+ "batch_max_size":1000,
+ "broker_list":{
+
+ },
+ "buffer_duration":60,
+ "inactive_timeout":5,
+ "include_req_body":false,
+ "kafka_topic":"1",
+ "key":"2",
+ "max_retry_count":0,
+ "name":"kafka logger",
+ "retry_delay":1,
+ "timeout":3
+ }
+ },
+ "b93d622c-92ef-48b4-b6bb-57e1ce893ee3":{
+ "name":"fault-injection",
+ "conf":{
+ "abort":{
+ "body":"200",
+ "http_status":300
+ },
+ "delay":{
+ "duration":500
+ }
+ }
+ }
+ },
+ "chart":{
+ "hovered":{
+
+ },
+ "links":{
+ "3a110c30-d6f3-40b1-a8ac-b828cfaa2489":{
+ "from":{
+ "nodeId":"3365eca3-4bc8-4769-bab3-1485dfd6a43c",
+ "portId":"port3"
+ },
+ "id":"3a110c30-d6f3-40b1-a8ac-b828cfaa2489",
+ "to":{
+ "nodeId":"b93d622c-92ef-48b4-b6bb-57e1ce893ee3",
+ "portId":"port1"
+ }
+ },
+ "c1958993-c1ef-44b1-bb32-7fc6f34870c2":{
+ "from":{
+ "nodeId":"3365eca3-4bc8-4769-bab3-1485dfd6a43c",
+ "portId":"port2"
+ },
+ "id":"c1958993-c1ef-44b1-bb32-7fc6f34870c2",
+ "to":{
+ "nodeId":"988ef5c2-c896-4606-a666-3d4cbe24a731",
+ "portId":"port1"
+ }
+ },
+ "f9c42bf6-c8aa-4e86-8498-8dfbc5c53c23":{
+ "from":{
+ "nodeId":"451106f8-560c-43a4-acf2-2a6ed0ea57b8",
+ "portId":"port2"
+ },
+ "id":"f9c42bf6-c8aa-4e86-8498-8dfbc5c53c23",
+ "to":{
+ "nodeId":"3365eca3-4bc8-4769-bab3-1485dfd6a43c",
+ "portId":"port1"
+ }
+ }
+ },
+ "nodes":{
+ "3365eca3-4bc8-4769-bab3-1485dfd6a43c":{
+ "id":"3365eca3-4bc8-4769-bab3-1485dfd6a43c",
+ "orientation":0,
+ "ports":{
+ "port1":{
+ "id":"port1",
+ "position":{
+ "x":107,
+ "y":0
+ },
+ "type":"input"
+ },
+ "port2":{
+ "id":"port2",
+ "position":{
+ "x":92,
+ "y":96
+ },
+ "properties":{
+ "value":"no"
+ },
+ "type":"output"
+ },
+ "port3":{
+ "id":"port3",
+ "position":{
+ "x":122,
+ "y":96
+ },
+ "properties":{
+ "value":"yes"
+ },
+ "type":"output"
+ }
+ },
+ "position":{
+ "x":750.2627969928922,
+ "y":301.0370335799397
+ },
+ "properties":{
+ "customData":{
+ "name":"code == 403",
+ "type":1
+ }
+ },
+ "size":{
+ "height":96,
+ "width":214
+ },
+ "type":"判断条件"
+ },
+ "451106f8-560c-43a4-acf2-2a6ed0ea57b8":{
+ "id":"451106f8-560c-43a4-acf2-2a6ed0ea57b8",
+ "orientation":0,
+ "ports":{
+ "port1":{
+ "id":"port1",
+ "position":{
+ "x":100,
+ "y":0
+ },
+ "properties":{
+ "custom":"property"
+ },
+ "type":"input"
+ },
+ "port2":{
+ "id":"port2",
+ "position":{
+ "x":100,
+ "y":96
+ },
+ "properties":{
+ "custom":"property"
+ },
+ "type":"output"
+ }
+ },
+ "position":{
+ "x":741.5684544145346,
+ "y":126.75879247285502
+ },
+ "properties":{
+ "customData":{
+ "data":{
+ "block_rules":[
+ "root.exe",
+ "root.m+"
+ ],
+ "rejected_code":403
+ },
+ "name":"uri-blocker",
+ "type":0
+ }
+ },
+ "size":{
+ "height":96,
+ "width":201
+ },
+ "type":"uri-blocker"
+ },
+ "988ef5c2-c896-4606-a666-3d4cbe24a731":{
+ "id":"988ef5c2-c896-4606-a666-3d4cbe24a731",
+ "orientation":0,
+ "ports":{
+ "port1":{
+ "id":"port1",
+ "position":{
+ "x":106,
+ "y":0
+ },
+ "properties":{
+ "custom":"property"
+ },
+ "type":"input"
+ },
+ "port2":{
+ "id":"port2",
+ "position":{
+ "x":106,
+ "y":96
+ },
+ "properties":{
+ "custom":"property"
+ },
+ "type":"output"
+ }
+ },
+ "position":{
+ "x":607.9687500000001,
+ "y":471.17788461538447
+ },
+ "properties":{
+ "customData":{
+ "data":{
+ "batch_max_size":1000,
+ "broker_list":{
+
+ },
+ "buffer_duration":60,
+ "inactive_timeout":5,
+ "include_req_body":false,
+ "kafka_topic":"1",
+ "key":"2",
+ "max_retry_count":0,
+ "name":"kafka logger",
+ "retry_delay":1,
+ "timeout":3
+ },
+ "name":"kafka-logger",
+ "type":0
+ }
+ },
+ "size":{
+ "height":96,
+ "width":212
+ },
+ "type":"kafka-logger"
+ },
+ "b93d622c-92ef-48b4-b6bb-57e1ce893ee3":{
+ "id":"b93d622c-92ef-48b4-b6bb-57e1ce893ee3",
+ "orientation":0,
+ "ports":{
+ "port1":{
+ "id":"port1",
+ "position":{
+ "x":110,
+ "y":0
+ },
+ "properties":{
+ "custom":"property"
+ },
+ "type":"input"
+ },
+ "port2":{
+ "id":"port2",
+ "position":{
+ "x":110,
+ "y":96
+ },
+ "properties":{
+ "custom":"property"
+ },
+ "type":"output"
+ }
+ },
+ "position":{
+ "x":988.9074986362261,
+ "y":478.62041800736495
+ },
+ "properties":{
+ "customData":{
+ "data":{
+ "abort":{
+ "body":"200",
+ "http_status":300
+ },
+ "delay":{
+ "duration":500
+ }
+ },
+ "name":"fault-injection",
+ "type":0
+ }
+ },
+ "size":{
+ "height":96,
+ "width":219
+ },
+ "type":"fault-injection"
+ }
+ },
+ "offset":{
+ "x":-376.83,
+ "y":87.98
+ },
+ "scale":0.832,
+ "selected":{
+ "id":"b93d622c-92ef-48b4-b6bb-57e1ce893ee3",
+ "type":"node"
+ }
+ }
+ }
+ }`
+
+ err = json.Unmarshal([]byte(reqBody), route2)
+ assert.Nil(t, err)
ctx.SetInput(route2)
_, err = handler.Update(ctx)
assert.Nil(t, err)
@@ -753,7 +755,8 @@ func TestRoute(t *testing.T) {
//list
listInput := &ListInput{}
reqBody = `{"page_size": 1, "page": 1}`
- json.Unmarshal([]byte(reqBody), listInput)
+ err = json.Unmarshal([]byte(reqBody), listInput)
+ assert.Nil(t, err)
ctx.SetInput(listInput)
retPage, err := handler.List(ctx)
assert.Nil(t, err)
@@ -763,7 +766,8 @@ func TestRoute(t *testing.T) {
//list search match
listInput2 := &ListInput{}
reqBody = `{"page_size": 1, "page": 1, "name": "a", "uri": "index"}`
- json.Unmarshal([]byte(reqBody), listInput2)
+ err = json.Unmarshal([]byte(reqBody), listInput2)
+ assert.Nil(t, err)
ctx.SetInput(listInput2)
retPage, err = handler.List(ctx)
assert.Nil(t, err)
@@ -773,7 +777,8 @@ func TestRoute(t *testing.T) {
//list search name not match
listInput3 := &ListInput{}
reqBody = `{"page_size": 1, "page": 1, "name": "not-exists", "uri": "index"}`
- json.Unmarshal([]byte(reqBody), listInput3)
+ err = json.Unmarshal([]byte(reqBody), listInput3)
+ assert.Nil(t, err)
ctx.SetInput(listInput3)
retPage, err = handler.List(ctx)
assert.Nil(t, err)
@@ -783,7 +788,8 @@ func TestRoute(t *testing.T) {
//list search uri not match
listInput4 := &ListInput{}
reqBody = `{"page_size": 1, "page": 1, "name": "a", "uri": "not-exists"}`
- json.Unmarshal([]byte(reqBody), listInput4)
+ err = json.Unmarshal([]byte(reqBody), listInput4)
+ assert.Nil(t, err)
ctx.SetInput(listInput4)
retPage, err = handler.List(ctx)
assert.Nil(t, err)
@@ -793,18 +799,19 @@ func TestRoute(t *testing.T) {
//create route using uris
route3 := &entity.Route{}
reqBody = `{
- "id": "2",
- "name": "bbbbb",
- "uris": ["/aa", "/bb"],
- "hosts": ["foo.com", "*.bar.com"],
- "remote_addrs": ["127.0.0.0/8"],
- "methods": ["PUT", "GET"],
- "upstream": {
- "type": "roundrobin",
- "nodes": {"www.a.com:80": 1}
- }
- }`
- json.Unmarshal([]byte(reqBody), route3)
+ "id": "2",
+ "name": "bbbbb",
+ "uris": ["/aa", "/bb"],
+ "hosts": ["foo.com", "*.bar.com"],
+ "remote_addrs": ["127.0.0.0/8"],
+ "methods": ["PUT", "GET"],
+ "upstream": {
+ "type": "roundrobin",
+ "nodes": {"www.a.com:80": 1}
+ }
+ }`
+ err = json.Unmarshal([]byte(reqBody), route3)
+ assert.Nil(t, err)
ctx.SetInput(route3)
_, err = handler.Create(ctx)
assert.Nil(t, err)
@@ -815,7 +822,8 @@ func TestRoute(t *testing.T) {
//list search match uris
listInput5 := &ListInput{}
reqBody = `{"page_size": 1, "page": 1, "name": "bbb", "uri": "bb"}`
- json.Unmarshal([]byte(reqBody), listInput5)
+ err = json.Unmarshal([]byte(reqBody), listInput5)
+ assert.Nil(t, err)
ctx.SetInput(listInput5)
retPage, err = handler.List(ctx)
assert.Nil(t, err)
@@ -825,7 +833,8 @@ func TestRoute(t *testing.T) {
//delete test data
inputDel := &BatchDelete{}
reqBody = `{"ids": "1,2"}`
- json.Unmarshal([]byte(reqBody), inputDel)
+ err = json.Unmarshal([]byte(reqBody), inputDel)
+ assert.Nil(t, err)
ctx.SetInput(inputDel)
_, err = handler.BatchDelete(ctx)
assert.Nil(t, err)
@@ -836,7 +845,8 @@ func TestRoute(t *testing.T) {
//get route -- deleted, not found
getInput := &GetInput{}
reqBody = `{"id": "1"}`
- json.Unmarshal([]byte(reqBody), getInput)
+ err = json.Unmarshal([]byte(reqBody), getInput)
+ assert.Nil(t, err)
ctx.SetInput(getInput)
ret, err = handler.Get(ctx)
assert.EqualError(t, err, "data not found")
@@ -844,7 +854,8 @@ func TestRoute(t *testing.T) {
//delete test data
reqBody = `{"ids": "not-exists"}`
- json.Unmarshal([]byte(reqBody), inputDel)
+ err = json.Unmarshal([]byte(reqBody), inputDel)
+ assert.Nil(t, err)
ctx.SetInput(inputDel)
ret, err = handler.BatchDelete(ctx)
assert.NotNil(t, err)
@@ -853,12 +864,13 @@ func TestRoute(t *testing.T) {
//create route with not exist upstream id
route4 := &entity.Route{}
reqBody = `{
- "id": "2222",
- "name": "r222",
- "uris": ["/aa", "/bb"],
- "upstream_id": "not-exists"
- }`
- json.Unmarshal([]byte(reqBody), route4)
+ "id": "2222",
+ "name": "r222",
+ "uris": ["/aa", "/bb"],
+ "upstream_id": "not-exists"
+ }`
+ err = json.Unmarshal([]byte(reqBody), route4)
+ assert.Nil(t, err)
ctx.SetInput(route4)
ret, err = handler.Create(ctx)
assert.NotNil(t, err)
@@ -867,20 +879,21 @@ func TestRoute(t *testing.T) {
//type:chash, hash_on: vars, wrong key
route5 := &entity.Route{}
reqBody = `{
- "id": "1",
- "methods": ["GET"],
- "upstream": {
- "nodes": {
- "127.0.0.1:8080": 1
- },
- "type": "chash",
- "hash_on":"vars",
- "key": "not_support"
- },
- "desc": "new route",
- "uri": "/index.html"
- }`
- json.Unmarshal([]byte(reqBody), route5)
+ "id": "1",
+ "methods": ["GET"],
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:8080": 1
+ },
+ "type": "chash",
+ "hash_on":"vars",
+ "key": "not_support"
+ },
+ "desc": "new route",
+ "uri": "/index.html"
+ }`
+ err = json.Unmarshal([]byte(reqBody), route5)
+ assert.Nil(t, err)
ctx.SetInput(route5)
ret, err = handler.Create(ctx)
assert.NotNil(t, err)
@@ -889,19 +902,20 @@ func TestRoute(t *testing.T) {
//type:chash, hash_on: cookie, missing key
route6 := &entity.Route{}
reqBody = `{
- "id": "1",
- "methods": ["GET"],
- "upstream": {
- "nodes": {
- "127.0.0.1:8080": 1
- },
- "type": "chash",
- "hash_on":"cookie"
- },
- "desc": "new route",
- "uri": "/index.html"
- }`
- json.Unmarshal([]byte(reqBody), route6)
+ "id": "1",
+ "methods": ["GET"],
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:8080": 1
+ },
+ "type": "chash",
+ "hash_on":"cookie"
+ },
+ "desc": "new route",
+ "uri": "/index.html"
+ }`
+ err = json.Unmarshal([]byte(reqBody), route6)
+ assert.Nil(t, err)
ctx.SetInput(route6)
ret, err = handler.Create(ctx)
assert.NotNil(t, err)
@@ -910,22 +924,23 @@ func TestRoute(t *testing.T) {
//create route with out upstream
route11 := &entity.Route{}
reqBody = `{
- "id": "11",
- "name": "bbbbb",
- "uri": "/r11",
- "hosts": ["foo.com", "*.bar.com"],
- "remote_addrs": ["127.0.0.0/8"],
- "methods": ["PUT", "GET"],
- "plugins": {
- "limit-count": {
- "count": 2,
- "time_window": 60,
- "rejected_code": 503,
- "key": "remote_addr"
- }
- }
- }`
- json.Unmarshal([]byte(reqBody), route11)
+ "id": "11",
+ "name": "bbbbb",
+ "uri": "/r11",
+ "hosts": ["foo.com", "*.bar.com"],
... 8144 lines suppressed ...