From 4cabd32e08c3a9b9b13d67531a720351baad3237 Mon Sep 17 00:00:00 2001 From: Baoyuan Date: Thu, 23 Mar 2023 17:20:15 +0800 Subject: [PATCH 1/3] chore: backport commits to 3.0 (#2780) * chore: update the year in the NOTICE (#2726) fix: https://github.com/apache/apisix-dashboard/issues/2724 * fix plugins display in list of routes (#2704) Co-authored-by: litesun * fix: plugin config page error (#2739) * fix: plugin disable invalid in API /plugin?all=true (#2737) * chore(deps): bump http-cache-semantics from 4.1.0 to 4.1.1 in /web (#2730) * fix: update URL of the online playground (#2760) * chore: update dependency (#2752) * chore: update dependency --------- Co-authored-by: rongxin * fix: remove route name length limit (#2759) * fix: change regex template to optional in proxy write (#2762) * fix: ssl table expiration time display (#2763) * feat: add search functionality for id, host, and description fields (#2750) Co-authored-by: Anil Durmus * fix: disable global plugin invalid (#2757) * feat: support ipv6 in upstream nodes (#2766) * fix: upstream nodes metadata miss (#2773) * fix: remove ssl check in redirect https (#2770) --------- Co-authored-by: Shivam0500 <121167056+Shivam0500@users.noreply.github.com> Co-authored-by: incubator4 Co-authored-by: litesun Co-authored-by: Joanthan Chen Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: JunXu Chen Co-authored-by: Xin Rong Co-authored-by: rongxin Co-authored-by: Anil Baki Durmus Co-authored-by: Anil Durmus --- NOTICE | 2 +- README.md | 2 +- api/go.mod | 71 +++++++++- api/go.sum | 91 ++++++++---- api/internal/core/entity/entity.go | 6 +- api/internal/core/entity/format.go | 28 ++-- api/internal/core/entity/format_test.go | 129 ++++++++++++++++++ api/internal/handler/route/route.go | 17 +++ api/internal/handler/schema/plugin.go | 9 +- api/internal/handler/service/service.go | 10 ++ api/internal/handler/upstream/upstream.go | 9 ++ api/test/e2e/route/route_test.go | 24 ++++ .../e2e/route/route_with_plugin_jwt_test.go | 7 + .../create-delete-in-drawer-plugin.cy.js | 47 +++++++ .../create-edit-duplicate-delete-route.cy.js | 79 ++++++++++- ...eate-edit-route-with-redirect-plugin.cy.js | 40 ++++++ ...eate-route-with-proxy-rewrite-plugin.cy.js | 28 +++- web/cypress/e2e/route/search-route.cy.js | 3 + web/src/components/Plugin/PluginDetail.tsx | 4 +- web/src/components/Plugin/PluginPage.tsx | 8 +- .../components/Upstream/components/Nodes.tsx | 5 +- web/src/components/Upstream/service.ts | 52 +++++-- web/src/helpers.tsx | 8 +- web/src/pages/Plugin/List.tsx | 2 +- web/src/pages/Route/Create.tsx | 17 +-- web/src/pages/Route/List.tsx | 12 +- .../Route/components/Step1/ProxyRewrite.tsx | 9 +- web/src/pages/Route/service.ts | 5 +- web/src/pages/Route/typing.d.ts | 1 + web/src/pages/SSL/typing.d.ts | 4 +- web/src/pages/Service/List.tsx | 4 +- web/src/pages/Service/service.ts | 2 + web/src/pages/Upstream/List.tsx | 2 - web/src/pages/Upstream/service.ts | 2 + web/yarn.lock | 6 +- 35 files changed, 630 insertions(+), 115 deletions(-) diff --git a/NOTICE b/NOTICE index 13e98eb201..c663509f2a 100644 --- a/NOTICE +++ b/NOTICE @@ -1,5 +1,5 @@ Apache APISIX -Copyright 2019-2022 The Apache Software Foundation +Copyright 2019-2023 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). diff --git a/README.md b/README.md index 87128b46ef..e572a73bde 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ Note: Currently the Dashboard does not have complete coverage of Apache APISIX f ## Demo -[Online Playground](http://20.210.250.99:9000/) +[Online Playground](https://apisix-dashboard.apiseven.com/) ```text Username: admin diff --git a/api/go.mod b/api/go.mod index 885f5d7ac2..6bb8f3cbf5 100644 --- a/api/go.mod +++ b/api/go.mod @@ -1,6 +1,6 @@ module github.com/apisix/manager-api -go 1.16 +go 1.19 require ( github.com/coreos/go-oidc/v3 v3.3.0 @@ -8,7 +8,7 @@ require ( github.com/getkin/kin-openapi v0.33.0 github.com/gin-contrib/gzip v0.0.3 github.com/gin-contrib/static v0.0.0-20200916080430-d45d9a37d28e - github.com/gin-gonic/gin v1.7.0 + github.com/gin-gonic/gin v1.9.0 github.com/golang-jwt/jwt v3.2.2+incompatible github.com/gorilla/sessions v1.2.1 github.com/juliangruber/go-intersect v1.1.0 @@ -19,13 +19,74 @@ require ( github.com/sony/sonyflake v1.0.0 github.com/spf13/cobra v1.6.1 github.com/spf13/viper v1.8.1 - github.com/stretchr/testify v1.8.0 - github.com/tidwall/gjson v1.6.7 + github.com/stretchr/testify v1.8.2 + github.com/tidwall/gjson v1.14.4 github.com/xeipuuv/gojsonschema v1.2.0 github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da go.etcd.io/etcd/client/pkg/v3 v3.5.5 go.etcd.io/etcd/client/v3 v3.5.5 go.uber.org/zap v1.17.0 - golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f // indirect golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 ) + +require ( + github.com/bytedance/sonic v1.8.0 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/coreos/go-semver v0.3.0 // indirect + github.com/coreos/go-systemd/v22 v22.3.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/swag v0.19.5 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.11.2 // indirect + github.com/goccy/go-json v0.10.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/gorilla/securecookie v1.1.1 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.0.9 // indirect + github.com/leodido/go-urn v1.2.1 // indirect + github.com/magiconair/properties v1.8.5 // indirect + github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/mapstructure v1.4.1 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml v1.9.3 // indirect + github.com/pelletier/go-toml/v2 v2.0.6 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/spf13/afero v1.6.0 // indirect + github.com/spf13/cast v1.3.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/objx v0.5.0 // indirect + github.com/subosito/gotenv v1.2.0 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.9 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + go.etcd.io/etcd/api/v3 v3.5.5 // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/multierr v1.6.0 // indirect + golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect + golang.org/x/crypto v0.5.0 // indirect + golang.org/x/net v0.7.0 // indirect + golang.org/x/sys v0.5.0 // indirect + golang.org/x/text v0.7.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90 // indirect + google.golang.org/grpc v1.47.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/ini.v1 v1.62.0 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/api/go.sum b/api/go.sum index 7764773782..18ae650a7d 100644 --- a/api/go.sum +++ b/api/go.sum @@ -74,9 +74,15 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA= +github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= 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/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -131,8 +137,9 @@ github.com/gin-contrib/static v0.0.0-20200916080430-d45d9a37d28e h1:8bZpGwoPxkai github.com/gin-contrib/static v0.0.0-20200916080430-d45d9a37d28e/go.mod h1:VhW/Ch/3FhimwZb8Oj+qJmdMmoB8r7lmJ5auRjm50oQ= github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= -github.com/gin-gonic/gin v1.7.0 h1:jGB9xAJQ12AIGNB4HguylppmDK1Am9ppF7XnGXXJuoU= github.com/gin-gonic/gin v1.7.0/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= +github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= +github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -146,19 +153,24 @@ github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUe github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= 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= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.3.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= +github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= +github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -283,8 +295,9 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV 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/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= @@ -295,19 +308,22 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 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/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 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/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 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/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -316,8 +332,9 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN 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/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/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -333,13 +350,16 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ 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/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= +github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -365,6 +385,7 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 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= @@ -399,8 +420,9 @@ github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 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= @@ -408,20 +430,24 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 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.7 h1:Mb1M9HZCRWEcXQ8ieJo7auYyyiSux6w9XN3AdTpxJrE= -github.com/tidwall/gjson v1.6.7/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI= -github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE= -github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU= -github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= +github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU= +github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= @@ -458,6 +484,8 @@ go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 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= @@ -466,8 +494,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f h1:OeJjE6G4dgCY4PIXvIRQbE8+RX+uXZyGhUy/ksMGJoc= -golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= +golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= 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= @@ -542,7 +570,6 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -550,8 +577,9 @@ golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWIEjGcGAkacif7oYQaUY= golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 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= @@ -661,8 +689,10 @@ golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -673,8 +703,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 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/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -914,13 +945,14 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 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/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 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= @@ -949,6 +981,7 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 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 f8fcc1c604..b8de0a9e0c 100644 --- a/api/internal/core/entity/entity.go +++ b/api/internal/core/entity/entity.go @@ -65,8 +65,8 @@ type Route struct { BaseInfo URI string `json:"uri,omitempty"` Uris []string `json:"uris,omitempty"` - Name string `json:"name" validate:"max=50"` - Desc string `json:"desc,omitempty" validate:"max=256"` + Name string `json:"name"` + Desc string `json:"desc,omitempty"` Priority int `json:"priority,omitempty"` Methods []string `json:"methods,omitempty"` Host string `json:"host,omitempty"` @@ -280,7 +280,7 @@ type ServerInfo struct { // swagger:model GlobalPlugins type PluginConfig struct { BaseInfo - Desc string `json:"desc,omitempty" validate:"max=256"` + Desc string `json:"desc,omitempty"` Plugins map[string]interface{} `json:"plugins"` Labels map[string]string `json:"labels,omitempty"` } diff --git a/api/internal/core/entity/format.go b/api/internal/core/entity/format.go index c13bb6cb91..d7df2b13c9 100644 --- a/api/internal/core/entity/format.go +++ b/api/internal/core/entity/format.go @@ -18,6 +18,7 @@ package entity import ( "errors" + "net" "strconv" "strings" @@ -25,15 +26,21 @@ import ( ) func mapKV2Node(key string, val float64) (*Node, error) { - hp := strings.Split(key, ":") - host := hp[0] - // according to APISIX upstream nodes policy, port is optional - port := "0" + host, port, err := net.SplitHostPort(key) - if len(hp) > 2 { - return nil, errors.New("invalid upstream node") - } else if len(hp) == 2 { - port = hp[1] + // ipv6 address + if strings.Count(host, ":") >= 2 { + host = "[" + host + "]" + } + + if err != nil { + if strings.Contains(err.Error(), "missing port in address") { + // according to APISIX upstream nodes policy, port is optional + host = key + port = "0" + } else { + return nil, errors.New("invalid upstream node") + } } portInt, err := strconv.Atoi(port) @@ -92,6 +99,11 @@ func NodesFormat(obj interface{}) interface{} { if _, ok := val["priority"]; ok { node.Priority = int(val["priority"].(float64)) } + + if _, ok := val["metadata"]; ok { + node.Metadata = val["metadata"].(map[string]interface{}) + } + nodes = append(nodes, node) } return nodes diff --git a/api/internal/core/entity/format_test.go b/api/internal/core/entity/format_test.go index 109aa384e8..ef12542040 100644 --- a/api/internal/core/entity/format_test.go +++ b/api/internal/core/entity/format_test.go @@ -56,6 +56,39 @@ func TestNodesFormat(t *testing.T) { assert.Contains(t, jsonStr, `"priority":10`) } +func TestNodesFormat_ipv6(t *testing.T) { + // route data saved in ETCD + routeStr := `{ + "uris": ["/*"], + "upstream": { + "type": "roundrobin", + "nodes": [{ + "host": "::1", + "port": 80, + "weight": 0, + "priority":10 + }] + } + }` + + // bind struct + var route Route + err := json.Unmarshal([]byte(routeStr), &route) + assert.Nil(t, err) + + // nodes format + nodes := NodesFormat(route.Upstream.Nodes) + + // json encode for client + res, err := json.Marshal(nodes) + assert.Nil(t, err) + jsonStr := string(res) + assert.Contains(t, jsonStr, `"weight":0`) + assert.Contains(t, jsonStr, `"port":80`) + assert.Contains(t, jsonStr, `"host":"::1"`) + assert.Contains(t, jsonStr, `"priority":10`) +} + func TestNodesFormat_struct(t *testing.T) { // route data saved in ETCD var route Route @@ -77,6 +110,27 @@ func TestNodesFormat_struct(t *testing.T) { assert.Contains(t, jsonStr, `"host":"127.0.0.1"`) } +func TestNodesFormat_struct_ipv6(t *testing.T) { + // route data saved in ETCD + var route Route + route.Uris = []string{"/*"} + route.Upstream = &UpstreamDef{} + route.Upstream.Type = "roundrobin" + var nodes = []*Node{{Host: "::1", Port: 80, Weight: 0}} + route.Upstream.Nodes = nodes + + // nodes format + formattedNodes := NodesFormat(route.Upstream.Nodes) + + // json encode for client + res, err := json.Marshal(formattedNodes) + assert.Nil(t, err) + jsonStr := string(res) + assert.Contains(t, jsonStr, `"weight":0`) + assert.Contains(t, jsonStr, `"port":80`) + assert.Contains(t, jsonStr, `"host":"::1"`) +} + func TestNodesFormat_Map(t *testing.T) { // route data saved in ETCD routeStr := `{ @@ -104,6 +158,33 @@ func TestNodesFormat_Map(t *testing.T) { assert.Contains(t, jsonStr, `"host":"127.0.0.1"`) } +func TestNodesFormat_Map_ipv6(t *testing.T) { + // route data saved in ETCD + routeStr := `{ + "uris": ["/*"], + "upstream": { + "type": "roundrobin", + "nodes": {"[::1]:8080": 0} + } + }` + + // bind struct + var route Route + err := json.Unmarshal([]byte(routeStr), &route) + assert.Nil(t, err) + + // nodes format + nodes := NodesFormat(route.Upstream.Nodes) + + // json encode for client + res, err := json.Marshal(nodes) + assert.Nil(t, err) + jsonStr := string(res) + assert.Contains(t, jsonStr, `"weight":0`) + assert.Contains(t, jsonStr, `"port":8080`) + assert.Contains(t, jsonStr, `"host":"[::1]"`) +} + func TestNodesFormat_empty_struct(t *testing.T) { // route data saved in ETCD routeStr := `{ @@ -277,6 +358,17 @@ func TestMapKV2Node(t *testing.T) { Weight: 0, }, }, + { + name: "address with ipv6", + key: "[::1]:443", + value: 100, + wantErr: false, + wantRes: &Node{ + Host: "[::1]", + Port: 443, + Weight: 100, + }, + }, } for _, tc := range testCases { @@ -293,3 +385,40 @@ func TestMapKV2Node(t *testing.T) { }) } } + +func TestNodesFormatWithMetadata(t *testing.T) { + // route data saved in ETCD + routeStr := `{ + "uris": ["/*"], + "upstream": { + "type": "roundrobin", + "nodes": [{ + "host": "127.0.0.1", + "port": 80, + "weight": 0, + "priority":10, + "metadata": { + "name": "test" + } + }] + } + }` + + // bind struct + var route Route + err := json.Unmarshal([]byte(routeStr), &route) + assert.Nil(t, err) + + // nodes format + nodes := NodesFormat(route.Upstream.Nodes) + + // json encode for client + res, err := json.Marshal(nodes) + assert.Nil(t, err) + jsonStr := string(res) + assert.Contains(t, jsonStr, `"weight":0`) + assert.Contains(t, jsonStr, `"port":80`) + assert.Contains(t, jsonStr, `"host":"127.0.0.1"`) + assert.Contains(t, jsonStr, `"priority":10`) + assert.Contains(t, jsonStr, `"metadata":{"name":"test"}`) +} diff --git a/api/internal/handler/route/route.go b/api/internal/handler/route/route.go index fae4429d99..d100c85b40 100644 --- a/api/internal/handler/route/route.go +++ b/api/internal/handler/route/route.go @@ -194,6 +194,9 @@ type ListInput struct { URI string `auto_read:"uri,query"` Label string `auto_read:"label,query"` Status string `auto_read:"status,query"` + Host string `auto_read:"host,query"` + ID string `auto_read:"id,query"` + Desc string `auto_read:"desc,query"` store.Pagination } @@ -236,6 +239,20 @@ func (h *Handler) List(c droplet.Context) (interface{}, error) { return false } + if input.Host != "" && !strings.Contains(obj.(*entity.Route).Host, input.Host) { + return false + } + + if input.Desc != "" && !strings.Contains(obj.(*entity.Route).Desc, input.Desc) { + return false + } + + if obj != nil && obj.(*entity.Route) != nil && obj.(*entity.Route).ID != nil && input.ID != "" { + if !strings.Contains(utils.InterfaceToString(obj.(*entity.Route).ID), input.ID) { + return false // IDs do not match, so object should not be included in the filtered result + } + } + return true }, Format: func(obj interface{}) interface{} { diff --git a/api/internal/handler/schema/plugin.go b/api/internal/handler/schema/plugin.go index d282640c9e..4585f56d0c 100644 --- a/api/internal/handler/schema/plugin.go +++ b/api/internal/handler/schema/plugin.go @@ -51,8 +51,11 @@ func (h *Handler) Plugins(c droplet.Context) (interface{}, error) { if input.All { var res []map[string]interface{} list := plugins.Value().(map[string]interface{}) - for name, conf := range list { - plugin := conf.(map[string]interface{}) + for name, schemaConfig := range list { + if enable, ok := conf.Plugins[name]; !ok || !enable { + continue + } + plugin := schemaConfig.(map[string]interface{}) plugin["name"] = name if _, ok := plugin["type"]; !ok { plugin["type"] = "other" @@ -65,7 +68,7 @@ func (h *Handler) Plugins(c droplet.Context) (interface{}, error) { var ret []string list := plugins.Map() for pluginName := range list { - if res, ok := conf.Plugins[pluginName]; !ok || !res { + if enable, ok := conf.Plugins[pluginName]; !ok || !enable { continue } diff --git a/api/internal/handler/service/service.go b/api/internal/handler/service/service.go index fe382b0685..ab94bfd804 100644 --- a/api/internal/handler/service/service.go +++ b/api/internal/handler/service/service.go @@ -90,6 +90,8 @@ func (h *Handler) Get(c droplet.Context) (interface{}, error) { type ListInput struct { Name string `auto_read:"name,query"` + ID string `auto_read:"id,query"` + Desc string `auto_read:"desc,query"` store.Pagination } @@ -135,6 +137,14 @@ func (h *Handler) List(c droplet.Context) (interface{}, error) { if input.Name != "" { return strings.Contains(obj.(*entity.Service).Name, input.Name) } + + if input.Desc != "" { + return strings.Contains(obj.(*entity.Service).Desc, input.Desc) + } + + if input.ID != "" { + return strings.Contains(utils.InterfaceToString(obj.(*entity.Service).ID), input.ID) + } return true }, Format: func(obj interface{}) interface{} { diff --git a/api/internal/handler/upstream/upstream.go b/api/internal/handler/upstream/upstream.go index 3157fdda8d..55c08a50bd 100644 --- a/api/internal/handler/upstream/upstream.go +++ b/api/internal/handler/upstream/upstream.go @@ -96,6 +96,8 @@ func (h *Handler) Get(c droplet.Context) (interface{}, error) { type ListInput struct { Name string `auto_read:"name,query"` + ID string `auto_read:"id,query"` + Desc string `auto_read:"desc,query"` store.Pagination } @@ -141,6 +143,13 @@ func (h *Handler) List(c droplet.Context) (interface{}, error) { if input.Name != "" { return strings.Contains(obj.(*entity.Upstream).Name, input.Name) } + + if input.Desc != "" { + return strings.Contains(obj.(*entity.Upstream).Desc, input.Desc) + } + if input.ID != "" { + return strings.Contains(utils.InterfaceToString(obj.(*entity.Upstream).ID), input.ID) + } return true }, Format: func(obj interface{}) interface{} { diff --git a/api/test/e2e/route/route_test.go b/api/test/e2e/route/route_test.go index d73cf949ed..099c27925e 100644 --- a/api/test/e2e/route/route_test.go +++ b/api/test/e2e/route/route_test.go @@ -63,6 +63,23 @@ var _ = Describe("Route", func() { Headers: map[string]string{"Authorization": base.GetToken()}, ExpectStatus: http.StatusOK, }), + Entry("create long name route3 success", base.HttpTestCase{ + Object: base.ManagerApiExpect(), + Method: http.MethodPut, + Path: "/apisix/admin/routes/r3", + Body: `{ + "name": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + "uri": "/hello_", + "upstream": { + "nodes": { + "` + base.UpstreamIp + `:1980": 1 + }, + "type": "roundrobin" + } + }`, + Headers: map[string]string{"Authorization": base.GetToken()}, + ExpectStatus: http.StatusOK, + }), Entry("create route failed, name existed", base.HttpTestCase{ Object: base.ManagerApiExpect(), Method: http.MethodPost, @@ -146,6 +163,13 @@ var _ = Describe("Route", func() { Headers: map[string]string{"Authorization": base.GetToken()}, ExpectStatus: http.StatusOK, }), + Entry("delete route3", base.HttpTestCase{ + Object: base.ManagerApiExpect(), + Method: http.MethodDelete, + Path: "/apisix/admin/routes/r3", + Headers: map[string]string{"Authorization": base.GetToken()}, + ExpectStatus: http.StatusOK, + }), Entry("hit route1 that just deleted", base.HttpTestCase{ Object: base.APISIXExpect(), Method: http.MethodGet, diff --git a/api/test/e2e/route/route_with_plugin_jwt_test.go b/api/test/e2e/route/route_with_plugin_jwt_test.go index 72509d961e..c1694a4fe0 100644 --- a/api/test/e2e/route/route_with_plugin_jwt_test.go +++ b/api/test/e2e/route/route_with_plugin_jwt_test.go @@ -311,6 +311,13 @@ var _ = Describe("route with jwt plugin", func() { Headers: map[string]string{"Authorization": base.GetToken()}, ExpectStatus: http.StatusOK, }), + Entry("delete the route", base.HttpTestCase{ + Object: base.ManagerApiExpect(), + Method: http.MethodDelete, + Path: "/apisix/admin/routes/jwt-sign", + Headers: map[string]string{"Authorization": base.GetToken()}, + ExpectStatus: http.StatusOK, + }), Entry("verify the deleted route", base.HttpTestCase{ Object: base.APISIXExpect(), Method: http.MethodGet, diff --git a/web/cypress/e2e/plugin/create-delete-in-drawer-plugin.cy.js b/web/cypress/e2e/plugin/create-delete-in-drawer-plugin.cy.js index f665600982..8053503c23 100644 --- a/web/cypress/e2e/plugin/create-delete-in-drawer-plugin.cy.js +++ b/web/cypress/e2e/plugin/create-delete-in-drawer-plugin.cy.js @@ -225,6 +225,53 @@ context('Delete Plugin List with the Drawer', () => { cy.get(selector.empty).should('be.visible'); }); + it('should disabled global plugin normally', () => { + cy.visit('/plugin/list'); + cy.get(selector.refresh).click(); + cy.contains('button', 'Enable').click(); + cy.contains(data.basicAuthPlugin) + .parents(selector.pluginCardBordered) + .within(() => { + cy.get('button').click({ + force: true, + }); + }); + cy.get(selector.drawer) + .should('be.visible') + .within(() => { + cy.get('#disable').should('have.attr', 'aria-checked', 'false'); + cy.get(selector.disabledSwitcher).click(); + cy.get(selector.checkedSwitcher).should('exist'); + }); + cy.contains('button', 'Submit').click({ force: true }); + cy.wait(timeout); + cy.visit('/plugin/list'); + cy.contains(data.basicAuthPlugin).siblings().contains('Configure').click(); + cy.get(selector.drawer) + .should('be.visible') + .within(() => { + cy.get('#disable').should('have.attr', 'aria-checked', 'true'); + cy.get(selector.disabledSwitcher).click(); + }); + cy.contains('button', 'Submit').click({ force: true }); + cy.get(selector.drawer).should('not.exist'); + cy.contains(data.basicAuthPlugin).should('be.visible'); + cy.contains(data.basicAuthPlugin).siblings().contains('Configure').click(); + cy.get(selector.drawer) + .should('be.visible') + .within(() => { + cy.get('#disable').should('have.attr', 'aria-checked', 'false'); + }); + + cy.contains('button', 'Cancel').click({ + force: true, + }); + cy.contains(data.basicAuthPlugin).siblings().contains('Delete').click(); + cy.contains('button', 'Confirm').click({ + force: true, + }); + }); + it('should be deleted one of the plugins instead of all', function () { cy.visit('/plugin/list'); cy.get(selector.refresh).click(); diff --git a/web/cypress/e2e/route/create-edit-duplicate-delete-route.cy.js b/web/cypress/e2e/route/create-edit-duplicate-delete-route.cy.js index ba33c31717..62e2a5e00d 100755 --- a/web/cypress/e2e/route/create-edit-duplicate-delete-route.cy.js +++ b/web/cypress/e2e/route/create-edit-duplicate-delete-route.cy.js @@ -36,6 +36,7 @@ context('Create and Delete Route', () => { operator: '#operator', value: '#value', nodes_0_host: '#submitNodes_0_host', + nodes_1_host: '#submitNodes_1_host', nodes_0_port: '#submitNodes_0_port', nodes_0_weight: '#submitNodes_0_weight', pluginCardBordered: '.ant-card-bordered', @@ -52,6 +53,7 @@ context('Create and Delete Route', () => { notificationCloseIcon: '.ant-notification-close-icon', notification: '.ant-notification-notice-message', addHost: '[data-cy=addHost]', + addNode: '[data-cy=add-node]', schemaErrorMessage: '.ant-form-item-explain.ant-form-item-explain-error', stepCheck: '.ant-steps-finish-icon', advancedMatchingTable: '.ant-table-row.ant-table-row-level-0', @@ -66,6 +68,8 @@ context('Create and Delete Route', () => { host3: '10.10.10.10', host4: '@', host5: '*1', + host_ipv6: '2001:0db8:85a3:0000:0000:8a2e:0370:7334', + host_ipv6_2: '::1', port: '80', weight: 1, basicAuthPlugin: 'basic-auth', @@ -74,12 +78,7 @@ context('Create and Delete Route', () => { deleteRouteSuccess: 'Delete Route Successfully', }; - const opreatorList = [ - 'Equal(==)', - 'Case insensitive regular match(~*)', - 'HAS', - 'Reverse the result(!)', - ]; + const opreatorList = ['Equal(==)', 'Case insensitive regular match(~*)', 'HAS']; before(() => { cy.clearLocalStorageSnapshot(); @@ -92,7 +91,7 @@ context('Create and Delete Route', () => { cy.visit('/'); }); - it.only('should not create route with name above 100 characters', function () { + it('should not create route with name above 100 characters', function () { cy.visit('/'); cy.contains('Route').click(); cy.get(selector.empty).should('be.visible'); @@ -325,4 +324,70 @@ context('Create and Delete Route', () => { cy.get(selector.notificationCloseIcon).click(); }); }); + + it('should create route with ipv6 upstream node', () => { + cy.visit('/'); + cy.contains('Route').click(); + cy.get(selector.empty).should('be.visible'); + cy.contains('Create').click(); + + // step 1 + cy.get(selector.name).type(name); + cy.get(selector.description).type(data.description); + cy.contains('Next').click(); + + // step2 + cy.get(selector.nodes_0_host).type(data.host_ipv6); + cy.get(selector.nodes_0_port).type(80); + cy.get(selector.addNode).click(); + cy.get(selector.nodes_1_host).type(data.host_ipv6_2); + cy.contains('Next').click(); + cy.contains('Next').click(); + cy.contains('button', 'Submit').click(); + cy.contains(data.submitSuccess); + cy.contains('Goto List').click(); + cy.url().should('contains', 'routes/list'); + + cy.get(selector.nameSelector).type(name); + cy.contains('Search').click(); + cy.contains(name).siblings().contains('Configure').click(); + cy.get('#status').should('have.class', 'ant-switch-checked'); + + cy.contains('Next').click(); + cy.get(selector.nodes_0_host).should('have.value', data.host_ipv6); + cy.get(selector.nodes_0_port).should('have.value', 80); + cy.get(selector.nodes_1_host).should('have.value', data.host_ipv6_2); + + cy.contains('Next').click(); + cy.contains('Next').click(); + cy.contains('Submit').click(); + cy.contains(data.submitSuccess); + cy.contains('Goto List').click(); + cy.url().should('contains', 'routes/list'); + cy.contains(name).siblings().contains('More').click(); + cy.contains('View').click(); + cy.get(selector.drawer).should('be.visible'); + + cy.get(selector.monacoScroll).within(() => { + cy.contains(name).should('exist'); + cy.contains(`[${data.host_ipv6}]`).should('exist'); + cy.contains(`[${data.host_ipv6_2}]`).should('exist'); + }); + + cy.visit('/routes/list'); + cy.get(selector.name).clear().type(name); + cy.contains('Search').click(); + cy.contains(name).siblings().contains('More').click(); + cy.contains('Delete').click(); + cy.get(selector.deleteAlert) + .should('be.visible') + .within(() => { + cy.contains('OK').click(); + }); + cy.get(selector.deleteAlert).within(() => { + cy.get('.ant-btn-loading-icon').should('be.visible'); + }); + cy.get(selector.notification).should('contain', data.deleteRouteSuccess); + cy.get(selector.notificationCloseIcon).click(); + }); }); diff --git a/web/cypress/e2e/route/create-edit-route-with-redirect-plugin.cy.js b/web/cypress/e2e/route/create-edit-route-with-redirect-plugin.cy.js index f3f779c7dc..05bae93b1b 100644 --- a/web/cypress/e2e/route/create-edit-route-with-redirect-plugin.cy.js +++ b/web/cypress/e2e/route/create-edit-route-with-redirect-plugin.cy.js @@ -26,6 +26,7 @@ context('Create Edit and Delete Route with redirect plugin', () => { name: '#name', redirect: '[data-cy=route-redirect]', customRedirectSelectOpt: '#redirectOption_list_1', + httpsRedirectSelectOpt: '#redirectOption_list_2', customRedirectUrI: '#redirectURI', customRedirectCode: '[data-cy=redirect_code]', customRedirectLabel: "[title='Custom Redirect']", @@ -34,10 +35,13 @@ context('Create Edit and Delete Route with redirect plugin', () => { notification: '.ant-notification-notice-message', webSocketSelector: '[title=WebSocket]', enable_websocket_button: '#enable_websocket', + hosts_0: '#hosts_0', + nodes_0_host: '#submitNodes_0_host', }; const data = { customRedirectUrI: '/test', + host1: 'test.com', submitSuccess: 'Submit Successfully', deleteRouteSuccess: 'Delete Route Successfully', step2Title: 'Define API Backend Server', @@ -130,4 +134,40 @@ context('Create Edit and Delete Route with redirect plugin', () => { cy.get(selector.notification).should('contain', data.deleteRouteSuccess); cy.get(selector.notificationCloseIcon).click({ multiple: true }); }); + + it('should enable https redirect without ssl', () => { + cy.visit('/'); + cy.contains('Route').click(); + cy.wait(timeout * 2); + cy.get(selector.empty).should('be.visible'); + cy.contains('Create').click(); + cy.wait(timeout * 2); + cy.contains('Next').click(); + cy.contains('Next').click(); + cy.get(selector.name).type(name); + cy.get(selector.redirect).click(); + cy.contains('Enable HTTPS').click({ force: true }); + + cy.get(selector.hosts_0).type(data.host1); + cy.contains('Next').click(); + cy.get(selector.nodes_0_host).type(data.host1); + cy.contains('Next').click(); + cy.contains('Next').click(); + cy.contains('Submit').click(); + cy.contains(data.submitSuccess); + cy.contains('Goto List').click(); + cy.url().should('contains', 'routes/list'); + + cy.get(selector.name).focus().clear().type(name); + cy.contains('Search').click(); + cy.contains(name).siblings().contains('More').click(); + cy.contains('Delete').click(); + cy.get(selector.deleteAlert) + .should('be.visible') + .within(() => { + cy.contains('OK').click(); + }); + cy.get(selector.notification).should('contain', data.deleteRouteSuccess); + cy.get(selector.notificationCloseIcon).click({ multiple: true }); + }); }); diff --git a/web/cypress/e2e/route/create-route-with-proxy-rewrite-plugin.cy.js b/web/cypress/e2e/route/create-route-with-proxy-rewrite-plugin.cy.js index 721d317c35..4086a4bcc4 100644 --- a/web/cypress/e2e/route/create-route-with-proxy-rewrite-plugin.cy.js +++ b/web/cypress/e2e/route/create-route-with-proxy-rewrite-plugin.cy.js @@ -15,8 +15,8 @@ * limitations under the License. */ /* eslint-disable no-undef */ -import menuLocaleUS from '../../../src/locales/en-US/menu'; import componentLocaleUS from '../../../src/locales/en-US/component'; +import menuLocaleUS from '../../../src/locales/en-US/menu'; import routeLocaleUS from '../../../src/pages/Route/locales/en-US'; context('create route with proxy-rewrite plugin', () => { @@ -29,6 +29,7 @@ context('create route with proxy-rewrite plugin', () => { deleteAlert: '.ant-modal-body', notification: '.ant-notification-notice-message', staticUri: '[data-cy=uri-static]', + regexUri: '[data-cy=uri-regex]', staticHost: '[data-cy=host-static]', keepHost: '[data-cy=host-keep]', newUri: '#proxyRewrite_uri', @@ -56,6 +57,7 @@ context('create route with proxy-rewrite plugin', () => { rewriteHeaderKey2: 'test2', rewriteHeaderValue1: '1', rewriteHeaderValue2: '2', + regex: '^/iresty/(.)/(.)/(.*)', }; beforeEach(() => { @@ -154,6 +156,30 @@ context('create route with proxy-rewrite plugin', () => { cy.contains(data.submitSuccess).should('be.visible'); }); + it('should use proxy rewrite in regex uri moode without template', () => { + cy.visit('/'); + cy.contains(menuLocaleUS['menu.routes']).click(); + + cy.get(selector.nameSelector).type(data.routeName); + cy.contains('Search').click(); + cy.contains(data.routeName).siblings().contains('Configure').click(); + + cy.get('#status').should('have.class', 'ant-switch-checked'); + cy.get(selector.regexUri).click(); + cy.get(selector.uriRewriteReg).should('be.visible').type(data.regex); + cy.get(selector.uriRewriteTemp).should('have.value', ''); + cy.contains('Next').click(); + cy.get(selector.nodes_0_host).type(data.host2); + cy.get(selector.nodes_0_port).type(data.port); + cy.get(selector.nodes_0_weight).type(data.weight); + cy.contains('Next').click(); + + cy.contains('proxy-rewrite').should('not.exist'); + cy.contains('Next').click(); + cy.contains('Submit').click(); + cy.contains(data.submitSuccess).should('be.visible'); + }); + it('should delete the route', function () { cy.visit('/routes/list'); cy.get(selector.nameSelector).type(data.routeName); diff --git a/web/cypress/e2e/route/search-route.cy.js b/web/cypress/e2e/route/search-route.cy.js index d947d977a7..622881437d 100644 --- a/web/cypress/e2e/route/search-route.cy.js +++ b/web/cypress/e2e/route/search-route.cy.js @@ -148,6 +148,8 @@ context('Create and Search Route', () => { cy.contains('Route').click(); cy.wait(timeout); // full match + // expand search + cy.get(selector.expandSearch).click(); cy.get(selector.pathSearchInput).type(data.uris1); cy.contains('Search').click(); cy.contains(data.uris1).should('contain', data.uris1); @@ -197,6 +199,7 @@ context('Create and Search Route', () => { force: true, multiple: true, }); + cy.wait(timeout); } }); }); diff --git a/web/src/components/Plugin/PluginDetail.tsx b/web/src/components/Plugin/PluginDetail.tsx index 69c7a268f8..5963fb3c8c 100644 --- a/web/src/components/Plugin/PluginDetail.tsx +++ b/web/src/components/Plugin/PluginDetail.tsx @@ -181,7 +181,7 @@ const PluginDetail: React.FC = ({ useEffect(() => { form.setFieldsValue({ - disable: isEnabled ? true : initialData[name] && !initialData[name]._meta.disable, + disable: isEnabled ? true : initialData[name] && !initialData[name]?._meta?.disable, scope: 'global', }); if (PLUGIN_UI_LIST.includes(name)) { @@ -416,7 +416,7 @@ const PluginDetail: React.FC = ({ > diff --git a/web/src/components/Plugin/PluginPage.tsx b/web/src/components/Plugin/PluginPage.tsx index 5c843f3c37..aa6c9ad582 100644 --- a/web/src/components/Plugin/PluginPage.tsx +++ b/web/src/components/Plugin/PluginPage.tsx @@ -101,7 +101,7 @@ const PluginPage: React.FC = ({ useEffect(() => { const openPluginList = pluginList.filter( - (item) => initialData[item.name] && !initialData[item.name]._meta.disable, + (item) => initialData[item.name] && !initialData[item.name]?._meta?.disable, ); setPlugins(initialData); setEnablePluginsList(openPluginList); @@ -244,16 +244,16 @@ const PluginPage: React.FC = ({ actions={[ , diff --git a/web/src/components/Upstream/components/Nodes.tsx b/web/src/components/Upstream/components/Nodes.tsx index 40122545d9..63d09e9f14 100644 --- a/web/src/components/Upstream/components/Nodes.tsx +++ b/web/src/components/Upstream/components/Nodes.tsx @@ -54,7 +54,8 @@ const Component: React.FC = ({ readonly }) => { }), }, { - pattern: new RegExp(/^\*?[0-9a-zA-Z-._]+$/, 'g'), + // eslint-disable-next-line no-useless-escape + pattern: new RegExp(/^\*?[0-9a-zA-Z-._\[\]:]+$/), message: formatMessage({ id: 'page.route.form.itemRulesPatternMessage.domain', }), @@ -115,7 +116,7 @@ const Component: React.FC = ({ readonly }) => { {!readonly && ( - diff --git a/web/src/components/Upstream/service.ts b/web/src/components/Upstream/service.ts index c7587d7ddc..acb5f88f8f 100644 --- a/web/src/components/Upstream/service.ts +++ b/web/src/components/Upstream/service.ts @@ -18,6 +18,10 @@ import { notification } from 'antd'; import { cloneDeep, isNil, omit, omitBy } from 'lodash'; import { formatMessage, request } from 'umi'; +const ipv6RegexExp = new RegExp( + /(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/, +); + /** * Because we have some `custom` field in Upstream Form, like custom.tls/custom.checks.active etc, * we need to transform data that doesn't have `custom` field to data contains `custom` field @@ -58,13 +62,32 @@ export const convertToFormData = (originData: UpstreamComponent.ResponseData) => // nodes have two types // https://github.com/apache/apisix-dashboard/issues/2080 if (data.nodes instanceof Array) { - data.submitNodes = data.nodes; + data.submitNodes = data.nodes.map((key) => { + if (key.host.indexOf(']') !== -1) { + // handle ipv6 address + return { + ...key, + host: key.host.match(/\[(.*?)\]/)?.[1] || '', + }; + } + return key; + }); } else if (data.nodes) { - data.submitNodes = Object.keys(data.nodes as Object).map((key) => ({ - host: key.split(':')[0], - port: key.split(':')[1], - weight: (data.nodes as Object)[key], - })); + data.submitNodes = Object.keys(data.nodes as Object).map((key) => { + if (key.indexOf(']') !== -1) { + // handle ipv6 address + return { + host: key.match(/\[(.*?)\]/)?.[1] || '', + port: key.split(']:')[1], + weight: (data.nodes as Object)[key], + }; + } + return { + host: key.split(':')[0], + port: key.split(':')[1], + weight: (data.nodes as Object)[key], + }; + }); } if (data.discovery_type && data.service_name) { @@ -135,10 +158,19 @@ export const convertToRequestData = ( data.nodes = {}; submitNodes?.forEach((item) => { const port = item.port ? `:${item.port}` : ''; - data.nodes = { - ...data.nodes, - [`${item.host}${port}`]: item.weight as number, - }; + if (ipv6RegexExp.test(item.host as string)) { + // ipv6 host need add [] on host + // like [::1]:80 + data.nodes = { + ...data.nodes, + [`[${item.host}]${port}`]: item.weight as number, + }; + } else { + data.nodes = { + ...data.nodes, + [`${item.host}${port}`]: item.weight as number, + }; + } }); return omit(data, ['upstream_type', 'submitNodes']); } diff --git a/web/src/helpers.tsx b/web/src/helpers.tsx index 0ee105032e..bc9f5af3cf 100644 --- a/web/src/helpers.tsx +++ b/web/src/helpers.tsx @@ -18,6 +18,7 @@ import { FileTextOutlined, InfoCircleOutlined } from '@ant-design/icons'; import type { MenuDataItem } from '@ant-design/pro-layout'; import { notification } from 'antd'; import yaml from 'js-yaml'; +import { isNumber } from 'lodash'; import moment from 'moment'; import React from 'react'; import { history } from 'umi'; @@ -128,12 +129,11 @@ export const getUrlQuery: (key: string) => string | false = (key: string) => { }; export const timestampToLocaleString = (timestamp: number) => { - if (!timestamp) { - // TODO: i18n - return 'None'; + if (isNumber(timestamp)) { + return moment.unix(timestamp).format('YYYY-MM-DD HH:mm:ss'); } - return moment.unix(timestamp).format('YYYY-MM-DD HH:mm:ss'); + return 'None'; }; /** diff --git a/web/src/pages/Plugin/List.tsx b/web/src/pages/Plugin/List.tsx index f0434e455b..7071d30c06 100644 --- a/web/src/pages/Plugin/List.tsx +++ b/web/src/pages/Plugin/List.tsx @@ -124,7 +124,7 @@ const Page: React.FC = () => { const disable = !formData.disable; let plugins = { ...initialData, - [name]: { ...monacoData, disable }, + [name]: { ...monacoData, _meta: { disable } }, }; if (shouldDelete === true) { plugins = omit(plugins, name); diff --git a/web/src/pages/Route/Create.tsx b/web/src/pages/Route/Create.tsx index d0240bf6a2..71fcb6a596 100644 --- a/web/src/pages/Route/Create.tsx +++ b/web/src/pages/Route/Create.tsx @@ -31,7 +31,7 @@ import Step2 from './components/Step2'; import Step3 from './components/Step3'; import { DEFAULT_STEP_1_DATA, DEFAULT_STEP_3_DATA } from './constants'; import styles from './Create.less'; -import { checkHostWithSSL, checkUniqueName, create, fetchItem, update } from './service'; +import { checkUniqueName, create, fetchItem, update } from './service'; import { transformProxyRewrite2Plugin } from './transform'; const { Step } = Steps; @@ -260,17 +260,10 @@ const Page: React.FC = (props) => { if (nextStep === 2) { if (step === 1) { form1.validateFields().then((value) => { - const { redirectOption, hosts } = value; - const filterHosts = hosts.filter(Boolean); - Promise.all([ - redirectOption === 'forceHttps' && filterHosts.length !== 0 - ? checkHostWithSSL(hosts) - : Promise.resolve(), - checkUniqueName( - value.name, - props.route.path.indexOf('edit') > 0 ? (props as any).match.params.rid : '', - ), - ]).then(() => { + checkUniqueName( + value.name, + props.route.path.indexOf('edit') > 0 ? (props as any).match.params.rid : '', + ).then(() => { setStep(nextStep); }); }); diff --git a/web/src/pages/Route/List.tsx b/web/src/pages/Route/List.tsx index 63de96ed38..7ff4d7de2a 100755 --- a/web/src/pages/Route/List.tsx +++ b/web/src/pages/Route/List.tsx @@ -322,13 +322,12 @@ const Page: React.FC = () => { }, { title: formatMessage({ id: 'component.global.id' }), - hideInSearch: true, dataIndex: 'id', width: 200, }, { title: formatMessage({ id: 'page.route.host' }), - hideInSearch: true, + dataIndex: 'host', width: 224, render: (_, record) => { const list = record.hosts || (record.host && [record.host]) || []; @@ -361,13 +360,13 @@ const Page: React.FC = () => { { title: formatMessage({ id: 'component.global.description' }), dataIndex: 'desc', - hideInSearch: true, ellipsis: true, width: 200, }, { title: formatMessage({ id: 'component.global.labels' }), dataIndex: 'labels', + width: 240, render: (_, record) => { return Object.keys(record.labels || {}) .filter((item) => item !== 'API_VERSION') @@ -550,6 +549,13 @@ const Page: React.FC = () => { { title: formatMessage({ id: 'menu.plugin' }), dataIndex: 'plugins', + width: 240, + render: (_, record) => { + const plugins = record.plugins || {}; + return Object.keys(plugins).length > 0 + ? Object.keys(plugins).map((key) => {key}) + : '-'; + }, }, ]; diff --git a/web/src/pages/Route/components/Step1/ProxyRewrite.tsx b/web/src/pages/Route/components/Step1/ProxyRewrite.tsx index 7770ab213e..cbe8738410 100644 --- a/web/src/pages/Route/components/Step1/ProxyRewrite.tsx +++ b/web/src/pages/Route/components/Step1/ProxyRewrite.tsx @@ -100,14 +100,6 @@ const ProxyRewrite: React.FC = ({ form, disabled }) label={formatMessage({ id: 'page.route.form.itemLabel.template' })} name={field.name} key={field.name} - rules={[ - { - required: true, - message: `${formatMessage({ - id: 'component.global.pleaseEnter', - })} ${formatMessage({ id: 'page.route.form.itemLabel.template' })}`, - }, - ]} > = ({ form, disabled }) { value: URI_REWRITE_TYPE.REGEXP, label: formatMessage({ id: 'page.route.radio.regex' }), + dataCypress: 'uri-regex', }, ]; diff --git a/web/src/pages/Route/service.ts b/web/src/pages/Route/service.ts index dbd182a503..794db91598 100644 --- a/web/src/pages/Route/service.ts +++ b/web/src/pages/Route/service.ts @@ -41,7 +41,7 @@ export const fetchItem = (rid: number) => request(`/routes/${rid}`).then((data) => transformRouteData(data.data)); export const fetchList = ({ current = 1, pageSize = 10, ...res }) => { - const { labels = [], API_VERSION = [], status } = res; + const { labels = [], API_VERSION = [], host = "", id = "", desc = "", status} = res; return request>>('/routes', { params: { @@ -51,6 +51,9 @@ export const fetchList = ({ current = 1, pageSize = 10, ...res }) => { page: current, page_size: pageSize, status, + host, + desc, + id, }, }).then(({ data }) => { return { diff --git a/web/src/pages/Route/typing.d.ts b/web/src/pages/Route/typing.d.ts index 64c4bb723a..234fc9feb4 100644 --- a/web/src/pages/Route/typing.d.ts +++ b/web/src/pages/Route/typing.d.ts @@ -214,6 +214,7 @@ declare namespace RouteModule { create_time: number; update_time: number; status: number; + plugins: Record; }; type RouteStatus = 0 | 1; diff --git a/web/src/pages/SSL/typing.d.ts b/web/src/pages/SSL/typing.d.ts index 985e3051a3..3c9281cc4f 100644 --- a/web/src/pages/SSL/typing.d.ts +++ b/web/src/pages/SSL/typing.d.ts @@ -52,7 +52,7 @@ declare namespace SSLModule { snis: string[]; status: number; update_time: number; - validity_start: number; - validity_end: number; + validity_start?: number; + validity_end?: number; }; } diff --git a/web/src/pages/Service/List.tsx b/web/src/pages/Service/List.tsx index c509a95b65..05feb47aab 100644 --- a/web/src/pages/Service/List.tsx +++ b/web/src/pages/Service/List.tsx @@ -42,9 +42,8 @@ const Page: React.FC = () => { const columns: ProColumns[] = [ { - title: 'ID', + title: formatMessage({ id: 'component.global.id' }), dataIndex: 'id', - hideInSearch: true, }, { title: formatMessage({ id: 'component.global.name' }), @@ -53,7 +52,6 @@ const Page: React.FC = () => { { title: formatMessage({ id: 'component.global.description' }), dataIndex: 'desc', - hideInSearch: true, }, { title: formatMessage({ id: 'component.global.operation' }), diff --git a/web/src/pages/Service/service.ts b/web/src/pages/Service/service.ts index b652335601..def2860b3b 100644 --- a/web/src/pages/Service/service.ts +++ b/web/src/pages/Service/service.ts @@ -21,6 +21,8 @@ import { transformData } from './transform'; export const fetchList = ({ current = 1, pageSize = 10, ...res }) => request('/services', { params: { + id: res.id || '', + desc: res.desc || '', name: res.name, page: current, page_size: pageSize, diff --git a/web/src/pages/Upstream/List.tsx b/web/src/pages/Upstream/List.tsx index c593b1eabc..5c31749d67 100644 --- a/web/src/pages/Upstream/List.tsx +++ b/web/src/pages/Upstream/List.tsx @@ -45,7 +45,6 @@ const Page: React.FC = () => { { title: formatMessage({ id: 'page.upstream.list.id' }), dataIndex: 'id', - hideInSearch: true, }, { title: formatMessage({ id: 'page.upstream.list.name' }), @@ -59,7 +58,6 @@ const Page: React.FC = () => { { title: formatMessage({ id: 'page.upstream.list.description' }), dataIndex: 'desc', - hideInSearch: true, }, { title: formatMessage({ id: 'page.upstream.list.edit.time' }), diff --git a/web/src/pages/Upstream/service.ts b/web/src/pages/Upstream/service.ts index a04925fdc6..a4d5ffefbe 100644 --- a/web/src/pages/Upstream/service.ts +++ b/web/src/pages/Upstream/service.ts @@ -21,6 +21,8 @@ import { convertToFormData } from '@/components/Upstream/service'; export const fetchList = ({ current = 1, pageSize = 10, ...res }) => { return request>>('/upstreams', { params: { + id: res.id || '', + desc: res.desc || '', name: res.name, page: current, page_size: pageSize, diff --git a/web/yarn.lock b/web/yarn.lock index fe721ab686..4417ceb831 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -8802,9 +8802,9 @@ htmlparser2@^7.0.0: entities "^3.0.1" http-cache-semantics@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" - integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== + version "4.1.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" + integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== http-deceiver@^1.2.7: version "1.2.7" From 397c0cb52e9b7e2cc7da2bbda544c62cb8fe10c6 Mon Sep 17 00:00:00 2001 From: Baoyuan Date: Fri, 24 Mar 2023 08:11:19 +0800 Subject: [PATCH 2/3] feat: release 3.0.1 (#2781) --- CHANGELOG.md | 27 +++++++++++++++++++++++++++ README.md | 2 +- api/VERSION | 2 +- docs/en/latest/config.json | 2 +- docs/en/latest/install.md | 2 +- web/package.json | 2 +- 6 files changed, 32 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a75fdd238..b98d6b12c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ # Table of Contents +- [3.0.1](#301) - [3.0.0](#300) - [2.15.0](#2150) - [2.14.0](#2140) @@ -43,6 +44,32 @@ - [1.5.0](#150) - [1.0.0](#100) +## 3.0.1 + +### Core + +- feat: add search functionality for ID, host, and description fields [#2750](https://github.com/apache/apisix-dashboard/pull/2750) +- feat: support ipv6 in upstream nodes [#2766](https://github.com/apache/apisix-dashboard/pull/2766) + +### Bugfix + +- fix: plugins display in list of routes [#2704](https://github.com/apache/apisix-dashboard/pull/2704) +- fix: plugin config page error [#2739](https://github.com/apache/apisix-dashboard/pull/2739) +- fix: Plugin disable invalid in API /plugin?all=true [#2737](https://github.com/apache/apisix-dashboard/pull/2737) +- fix: update URL of the online playground [#2760](https://github.com/apache/apisix-dashboard/pull/2760) +- fix: remove route name length limit [#2759](https://github.com/apache/apisix-dashboard/pull/2759) +- fix: change regex template to optional in proxy write [#2762](https://github.com/apache/apisix-dashboard/pull/2762) +- fix: ssl table expiration time display [#2763](https://github.com/apache/apisix-dashboard/pull/2763) +- fix: disable global plugin invalid [#2757](https://github.com/apache/apisix-dashboard/pull/2757) +- fix: upstream nodes metadata miss [#2773](https://github.com/apache/apisix-dashboard/pull/2773) +- fix: remove ssl check in redirect https [#2770](https://github.com/apache/apisix-dashboard/pull/2770) + +### Chore + +- chore(deps): bump http-cache-semantics from 4.1.0 to 4.1.1 in /web [#2730](https://github.com/apache/apisix-dashboard/pull/2730) +- chore: update dependency [#2752](https://github.com/apache/apisix-dashboard/pull/2752) +- chore: update the year in the NOTICE [#2726](https://github.com/apache/apisix-dashboard/pull/2726) + ## 3.0.0 ### Core diff --git a/README.md b/README.md index e572a73bde..7bd19a8246 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ - The master version should be used with Apache APISIX master version. -- The latest released version is [3.0.0](https://apisix.apache.org/downloads/) and is compatible with [Apache APISIX 3.0.x](https://apisix.apache.org/downloads/). +- The latest released version is [3.0.1](https://apisix.apache.org/downloads/) and is compatible with [Apache APISIX 3.0.x](https://apisix.apache.org/downloads/). ## What's Apache APISIX Dashboard diff --git a/api/VERSION b/api/VERSION index 4a36342fca..cb2b00e4f7 100644 --- a/api/VERSION +++ b/api/VERSION @@ -1 +1 @@ -3.0.0 +3.0.1 diff --git a/docs/en/latest/config.json b/docs/en/latest/config.json index 7d3b343935..5b175d690a 100644 --- a/docs/en/latest/config.json +++ b/docs/en/latest/config.json @@ -1,5 +1,5 @@ { - "version": "3.0.0", + "version": "3.0.1", "sidebar": [ { "type": "category", diff --git a/docs/en/latest/install.md b/docs/en/latest/install.md index 2a9fcbebec..82f5d447ff 100644 --- a/docs/en/latest/install.md +++ b/docs/en/latest/install.md @@ -48,7 +48,7 @@ Please replace `` to your configure file path. ```shell # 1. install RPM package -sudo yum install -y https://github.com/apache/apisix-dashboard/releases/download/v3.0.0/apisix-dashboard-3.0.0-0.el7.x86_64.rpm +sudo yum install -y https://github.com/apache/apisix-dashboard/releases/download/v3.0.1/apisix-dashboard-3.0.1-0.el7.x86_64.rpm ``` ### Launch diff --git a/web/package.json b/web/package.json index bd2b6f1216..854ae9f027 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "apisix-dashboard", - "version": "3.0.0", + "version": "3.0.1", "private": true, "description": "Dashboard for Apache APISIX", "scripts": { From 4133aa1f3c9ce62a5bed5ba8a9162888193ee455 Mon Sep 17 00:00:00 2001 From: hauer <254958181@qq.com> Date: Mon, 19 Feb 2024 15:24:38 +0800 Subject: [PATCH 3/3] fix: memory leak when etcd watch failed (#2920) --- api/internal/core/store/store.go | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/api/internal/core/store/store.go b/api/internal/core/store/store.go index b75f406dda..6383575651 100644 --- a/api/internal/core/store/store.go +++ b/api/internal/core/store/store.go @@ -63,6 +63,7 @@ type GenericStore struct { cancel context.CancelFunc closing bool + inited bool //is inited } type GenericStoreOption struct { @@ -109,12 +110,20 @@ func ReInit() error { return err } } + + //clear storeNeedReInit + storeNeedReInit = storeNeedReInit[:0] return nil } func (s *GenericStore) Init() error { s.initLock.Lock() defer s.initLock.Unlock() + //return if inited + if s.IsInited() { + return nil + } + return s.listAndWatch() } @@ -351,6 +360,7 @@ func (s *GenericStore) listAndWatch() error { // start watch s.cancel = s.watch() + s.SetIsInited(true) return nil } @@ -362,7 +372,11 @@ func (s *GenericStore) watch() context.CancelFunc { defer func() { if !s.closing { log.Errorf("etcd watch exception closed, restarting: resource: %s", s.Type()) - storeNeedReInit = append(storeNeedReInit, s) + //only add to storeNeedReInit when from inited to uninited + if s.IsInited() { + s.SetIsInited(false) + storeNeedReInit = append(storeNeedReInit, s) + } } }() defer runtime.HandlePanic() @@ -421,3 +435,11 @@ func (s *GenericStore) GetObjStorageKey(obj interface{}) string { func (s *GenericStore) GetStorageKey(key string) string { return fmt.Sprintf("%s/%s", s.opt.BasePath, key) } + +func (s *GenericStore) IsInited() bool { + return s.inited +} + +func (s *GenericStore) SetIsInited(inited bool) { + s.inited = inited +}