You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by al...@apache.org on 2023/05/23 06:52:32 UTC
[dubbo-admin] branch refactor-with-go updated: Support traffic management (#1135)
This is an automated email from the ASF dual-hosted git repository.
albumenj pushed a commit to branch refactor-with-go
in repository https://gitbox.apache.org/repos/asf/dubbo-admin.git
The following commit(s) were added to refs/heads/refactor-with-go by this push:
new d301f511 Support traffic management (#1135)
d301f511 is described below
commit d301f5112e64f08b8f009f9e4add8fd0c759600f
Author: Ken Liu <ke...@gmail.com>
AuthorDate: Tue May 23 14:52:21 2023 +0800
Support traffic management (#1135)
* update link
* Support traffic policies
* go fmt
* delete unused files
* add ASF headers
* ignore license check
* fix ut
* run gofmt
* fix lint
---------
Co-authored-by: ken.lj <ke...@alibaba-inc.com>
---
.licenserc.yaml | 1 +
Makefile | 2 +-
go.mod | 1 +
go.sum | 2 +
hack/swagger/swagger.json | 2709 +++++++++++++++++++-
pkg/admin/config/governance_config.go | 26 +
.../{ => mock_config}/governance_config_mock.go | 102 +-
pkg/admin/handlers/overrides.go | 6 +-
pkg/admin/handlers/traffic/accesslog.go | 123 +
pkg/admin/handlers/traffic/argument.go | 123 +
pkg/admin/handlers/traffic/gray.go | 123 +
pkg/admin/handlers/traffic/mock.go | 123 +
pkg/admin/handlers/traffic/region.go | 123 +
pkg/admin/handlers/traffic/retry.go | 123 +
pkg/admin/handlers/traffic/timeout.go | 123 +
pkg/admin/handlers/traffic/weight.go | 123 +
pkg/admin/model/condition_route.go | 2 +-
pkg/admin/model/match.go | 8 +-
pkg/admin/model/override.go | 21 +-
pkg/admin/model/tag_route.go | 6 +-
pkg/admin/model/traffic.go | 191 ++
pkg/admin/{ => model}/util/override_utils.go | 8 +-
pkg/admin/{ => model}/util/override_utils_test.go | 0
pkg/admin/{ => model}/util/sync_utils.go | 5 +-
pkg/admin/{ => model}/util/sync_utils_test.go | 0
pkg/admin/router/router.go | 65 +
pkg/admin/services/consumer_service_impl.go | 2 +-
pkg/admin/services/override_service_impl.go | 27 +-
pkg/admin/services/override_service_impl_test.go | 40 +-
pkg/admin/services/prometheus_service_impl.go | 7 +-
pkg/admin/services/provider_service_impl.go | 2 +-
pkg/admin/services/provider_service_impl_test.go | 2 +-
pkg/admin/services/route_service_impl.go | 38 +-
pkg/admin/services/route_service_impl_test.go | 100 +-
pkg/admin/services/traffic/accesslog.go | 66 +
pkg/admin/services/traffic/argument.go | 89 +
.../services/traffic/generic_rule_operation.go | 332 +++
pkg/admin/services/traffic/gray.go | 70 +
pkg/admin/services/traffic/mock.go | 78 +
pkg/admin/services/traffic/region.go | 89 +
pkg/admin/services/traffic/retry.go | 79 +
pkg/admin/services/traffic/timeout.go | 79 +
pkg/admin/services/traffic/timeout_test.go | 313 +++
pkg/admin/services/traffic/weight.go | 91 +
pkg/admin/util/base_service_metadata.go | 49 +-
45 files changed, 5377 insertions(+), 315 deletions(-)
diff --git a/.licenserc.yaml b/.licenserc.yaml
index 74476ff1..d70dad43 100644
--- a/.licenserc.yaml
+++ b/.licenserc.yaml
@@ -76,6 +76,7 @@ header:
- '**/cmd/ui/dist/**'
- '**/dubbo-admin-ui/public/echarts-en.min.js'
- '**/dubbo-admin-ui/tests/**'
+ - '**/governance_config_mock.go'
comment: on-failure
license-location-threshold: 130
diff --git a/Makefile b/Makefile
index eb091d2c..74ede81a 100644
--- a/Makefile
+++ b/Makefile
@@ -97,7 +97,7 @@ generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and
.PHONY: dubbo-admin-swagger
dubbo-admin-swagger: swagger-install ## Generate dubbo-admin swagger docs.
- $(SWAGGER) init -d cmd/admin,pkg/admin -o hack/swagger
+ $(SWAGGER) init --parseDependency -d cmd/admin,pkg/admin -o hack/swagger
@rm -f hack/swagger/docs.go hack/swagger/swagger.yaml
.PHONY: fmt
diff --git a/go.mod b/go.mod
index aad5e282..4aa349c1 100644
--- a/go.mod
+++ b/go.mod
@@ -28,6 +28,7 @@ require (
github.com/golang/mock v1.6.0
github.com/google/yamlfmt v0.9.0
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
+ github.com/herkyl/patchwerk v0.0.0-20190629103337-f0ea77068152
github.com/kylelemons/godebug v1.1.0
github.com/mattbaird/jsonpatch v0.0.0-20200820163806-098863c1fc24
github.com/prometheus/client_golang v1.14.0
diff --git a/go.sum b/go.sum
index 4b3a8538..60609266 100644
--- a/go.sum
+++ b/go.sum
@@ -938,6 +938,8 @@ github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvh
github.com/hashicorp/vault/sdk v0.7.0/go.mod h1:KyfArJkhooyba7gYCKSq8v66QdqJmnbAxtV/OX1+JTs=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
+github.com/herkyl/patchwerk v0.0.0-20190629103337-f0ea77068152 h1:GITUy7r2Eijl7u/Xe5AOs3HBV3Gt/3+l0j2bTh2UO5Y=
+github.com/herkyl/patchwerk v0.0.0-20190629103337-f0ea77068152/go.mod h1:bRtCxY0f88xmUw+Y0Xfl/uGaCWMUy04wUGSKbnQdsJs=
github.com/hjson/hjson-go/v4 v4.0.0 h1:wlm6IYYqHjOdXH1gHev4VoXCaW20HdQAGCxdOEEg2cs=
github.com/hjson/hjson-go/v4 v4.0.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
diff --git a/hack/swagger/swagger.json b/hack/swagger/swagger.json
index 1654316a..6386a451 100644
--- a/hack/swagger/swagger.json
+++ b/hack/swagger/swagger.json
@@ -13,6 +13,88 @@
"host": "127.0.0.1:38080",
"basePath": "/",
"paths": {
+ "/api/{env}/applications": {
+ "get": {
+ "description": "Get all applications",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "Services"
+ ],
+ "summary": "Get all applications",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "dev",
+ "description": "environment",
+ "name": "env",
+ "in": "path"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ }
+ },
+ "/api/{env}/consumers": {
+ "get": {
+ "description": "Get all consumers",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "Services"
+ ],
+ "summary": "Get all consumers",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "dev",
+ "description": "environment",
+ "name": "env",
+ "in": "path"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ }
+ },
"/api/{env}/mock/rule": {
"post": {
"description": "Create or update MockRule",
@@ -424,7 +506,7 @@
"200": {
"description": "OK",
"schema": {
- "type": "boolean"
+ "$ref": "#/definitions/model.DynamicConfig"
}
},
"400": {
@@ -788,7 +870,7 @@
"200": {
"description": "OK",
"schema": {
- "type": "boolean"
+ "$ref": "#/definitions/model.ConditionRouteDto"
}
},
"500": {
@@ -900,106 +982,2148 @@
}
}
}
- }
- },
- "definitions": {
- "model.AddressMatch": {
- "type": "object",
- "properties": {
- "cird": {
- "type": "string"
- },
- "exact": {
- "type": "string"
- },
- "wildcard": {
- "type": "string"
- }
- }
},
- "model.ConditionMatch": {
- "type": "object",
- "properties": {
- "address": {
- "$ref": "#/definitions/model.AddressMatch"
- },
- "application": {
- "$ref": "#/definitions/model.ListStringMatch"
- },
- "param": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/model.ParamMatch"
+ "/api/{env}/rules/route/tag": {
+ "get": {
+ "description": "Search rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TagRule"
+ ],
+ "summary": "Search rule",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "dev",
+ "description": "environment",
+ "name": "env",
+ "in": "path"
+ },
+ {
+ "type": "string",
+ "description": "application and service must not left empty at the same time",
+ "name": "application",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/model.TagRouteDto"
+ }
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
}
- },
- "service": {
- "$ref": "#/definitions/model.ListStringMatch"
}
- }
- },
- "model.ConditionRouteDto": {
- "type": "object",
- "required": [
- "conditions",
- "configVersion",
- "enabled"
- ],
- "properties": {
- "application": {
- "type": "string"
- },
- "conditions": {
- "type": "array",
- "items": {
- "type": "string"
+ },
+ "post": {
+ "description": "Create a new tag rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TagRule"
+ ],
+ "summary": "Create a new tag rule",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "dev",
+ "description": "environment",
+ "name": "env",
+ "in": "path"
+ },
+ {
+ "description": "rule input",
+ "name": "tagRoute",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.TagRouteDto"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "boolean"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
}
- },
- "configVersion": {
- "type": "string"
- },
- "enabled": {
- "type": "boolean"
- },
- "force": {
- "type": "boolean"
- },
- "id": {
- "type": "string"
- },
- "priority": {
- "type": "integer"
- },
- "runtime": {
- "type": "boolean"
- },
- "service": {
- "type": "string"
- },
- "serviceGroup": {
- "type": "string"
- },
- "serviceVersion": {
- "type": "string"
}
}
},
- "model.DynamicConfig": {
- "type": "object",
- "properties": {
- "application": {
- "type": "string"
- },
- "configVersion": {
- "type": "string"
- },
- "configs": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/model.OverrideConfig"
- }
- },
- "enabled": {
- "type": "boolean"
+ "/api/{env}/rules/route/tag/disable/{id}": {
+ "put": {
+ "description": "Disable the specified rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TagRule"
+ ],
+ "summary": "Disable the specified rule",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "dev",
+ "description": "environment",
+ "name": "env",
+ "in": "path"
+ },
+ {
+ "type": "string",
+ "description": "rule id",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "boolean"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ }
+ },
+ "/api/{env}/rules/route/tag/enable/{id}": {
+ "put": {
+ "description": "Enable the specified rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TagRule"
+ ],
+ "summary": "Enable the specified rule",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "dev",
+ "description": "environment",
+ "name": "env",
+ "in": "path"
+ },
+ {
+ "type": "string",
+ "description": "rule id",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "boolean"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ }
+ },
+ "/api/{env}/rules/route/tag/{id}": {
+ "get": {
+ "description": "Show the detail of one specified rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TagRule"
+ ],
+ "summary": "Show the detail of one specified rule",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "dev",
+ "description": "environment",
+ "name": "env",
+ "in": "path"
+ },
+ {
+ "type": "string",
+ "description": "rule id",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/model.TagRouteDto"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "post": {
+ "description": "Update rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TagRule"
+ ],
+ "summary": "Update rule",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "dev",
+ "description": "environment",
+ "name": "env",
+ "in": "path"
+ },
+ {
+ "type": "string",
+ "description": "rule id",
+ "name": "id",
+ "in": "path",
+ "required": true
+ },
+ {
+ "description": "rule input",
+ "name": "tagRoute",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.TagRouteDto"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "boolean"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "delete": {
+ "description": "Delete the specified rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TagRule"
+ ],
+ "summary": "Delete the specified rule",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "dev",
+ "description": "environment",
+ "name": "env",
+ "in": "path"
+ },
+ {
+ "type": "string",
+ "description": "rule id",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "boolean"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ }
+ },
+ "/api/{env}/service": {
+ "get": {
+ "description": "Search services by different patterns and keywords",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "Services"
+ ],
+ "summary": "Search services by different patterns and keywords",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "dev",
+ "description": "environment",
+ "name": "env",
+ "in": "path"
+ },
+ {
+ "type": "string",
+ "description": "supported values: application, service or ip",
+ "name": "pattern",
+ "in": "query",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "keyword to search",
+ "name": "filter",
+ "in": "query",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "page number",
+ "name": "page",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "page size",
+ "name": "size",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/model.ListServiceByPage"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ }
+ },
+ "/api/{env}/service/{service}": {
+ "get": {
+ "description": "Show detail of the specified service",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "Services"
+ ],
+ "summary": "Show detail of the specified service",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "dev",
+ "description": "environment",
+ "name": "env",
+ "in": "path"
+ },
+ {
+ "type": "string",
+ "description": "service format: 'group/service:version'",
+ "name": "service",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/model.ServiceDetailDTO"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ }
+ },
+ "/api/{env}/services": {
+ "get": {
+ "description": "Get all services",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "Services"
+ ],
+ "summary": "Get all services",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "dev",
+ "description": "environment",
+ "name": "env",
+ "in": "path"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ }
+ },
+ "/api/{env}/traffic/accesslog": {
+ "get": {
+ "description": "get rule list",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficAccesslog"
+ ],
+ "summary": "get rule list",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "accesslog",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Accesslog"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/model.Accesslog"
+ }
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "put": {
+ "description": "create rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficAccesslog"
+ ],
+ "summary": "create rule",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "accesslog",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Accesslog"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "bool"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "post": {
+ "description": "create rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficAccesslog"
+ ],
+ "summary": "create rule",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "accesslog",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Accesslog"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "bool"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "delete": {
+ "description": "delete rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficAccesslog"
+ ],
+ "summary": "delete rule",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "accesslog",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Accesslog"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "bool"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ }
+ },
+ "/api/{env}/traffic/argument": {
+ "get": {
+ "description": "get rule list",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficArgument"
+ ],
+ "summary": "get rule list",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "argument",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Argument"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/model.Argument"
+ }
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "put": {
+ "description": "update rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficArgument"
+ ],
+ "summary": "update rule",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "argument",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Argument"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "bool"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "post": {
+ "description": "create rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficArgument"
+ ],
+ "summary": "create rule",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "argument",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Argument"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "bool"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "delete": {
+ "description": "delete rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficArgument"
+ ],
+ "summary": "delete rule",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "argument",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Argument"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "bool"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ }
+ },
+ "/api/{env}/traffic/gray": {
+ "get": {
+ "description": "get rule list",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficGray"
+ ],
+ "summary": "get rule list",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "gray",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Gray"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/model.Gray"
+ }
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "put": {
+ "description": "update rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficGray"
+ ],
+ "summary": "update rule",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "gray",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Gray"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "bool"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "post": {
+ "description": "create rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficGray"
+ ],
+ "summary": "create rule",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "gray",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Gray"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "bool"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "delete": {
+ "description": "delete rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficGray"
+ ],
+ "summary": "delete rule",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "gray",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Gray"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "bool"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ }
+ },
+ "/api/{env}/traffic/mock": {
+ "get": {
+ "description": "get rule list",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficMock"
+ ],
+ "summary": "get rule list",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "mock",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Mock"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/model.Mock"
+ }
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "put": {
+ "description": "update rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficMock"
+ ],
+ "summary": "update rule",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "mock",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Mock"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "bool"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "post": {
+ "description": "create rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficMock"
+ ],
+ "summary": "create rule",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "mock",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Mock"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "bool"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "delete": {
+ "description": "delete rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficMock"
+ ],
+ "summary": "delete rule",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "mock",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Mock"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "bool"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ }
+ },
+ "/api/{env}/traffic/region": {
+ "get": {
+ "description": "get rule list",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficRegion"
+ ],
+ "summary": "get rule list",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "region",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Region"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/model.Region"
+ }
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "put": {
+ "description": "update rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficRegion"
+ ],
+ "summary": "update rule",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "region",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Region"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "bool"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "post": {
+ "description": "create rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficRegion"
+ ],
+ "summary": "create rule",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "region",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Region"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "bool"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "delete": {
+ "description": "delete rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficRegion"
+ ],
+ "summary": "delete rule",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "region",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Region"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "bool"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ }
+ },
+ "/api/{env}/traffic/retry": {
+ "get": {
+ "description": "get rule list",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficRetry"
+ ],
+ "summary": "get rule list",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "retry",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Retry"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/model.Retry"
+ }
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "put": {
+ "description": "update rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficRetry"
+ ],
+ "summary": "update rule",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "retry",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Retry"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "bool"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "post": {
+ "description": "create rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficRetry"
+ ],
+ "summary": "create rule",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "retry",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Retry"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "bool"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "delete": {
+ "description": "delete rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficRetry"
+ ],
+ "summary": "delete rule",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "retry",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Retry"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "bool"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ }
+ },
+ "/api/{env}/traffic/timeout": {
+ "get": {
+ "description": "get timeout rule list",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficTimeout"
+ ],
+ "summary": "get timeout rule list",
+ "parameters": [
+ {
+ "description": "timeout rule",
+ "name": "timeout",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Timeout"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/model.Timeout"
+ }
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "put": {
+ "description": "update a new timeout rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficTimeout"
+ ],
+ "summary": "update a new timeout rule",
+ "parameters": [
+ {
+ "description": "timeout rule",
+ "name": "timeout",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Timeout"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "boolean"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "post": {
+ "description": "Create a new timeout rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficTimeout"
+ ],
+ "summary": "Create a new timeout rule",
+ "parameters": [
+ {
+ "description": "timeout rule",
+ "name": "timeout",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Timeout"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "boolean"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "delete": {
+ "description": "delete a new timeout rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficTimeout"
+ ],
+ "summary": "delete a new timeout rule",
+ "parameters": [
+ {
+ "description": "timeout rule",
+ "name": "timeout",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Timeout"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "boolean"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ }
+ },
+ "/api/{env}/traffic/weight": {
+ "get": {
+ "description": "get rule list",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficWeight"
+ ],
+ "summary": "get rule list",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "weight",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Weight"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/model.Weight"
+ }
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "put": {
+ "description": "update rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficWeight"
+ ],
+ "summary": "update rule",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "weight",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Weight"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "bool"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "post": {
+ "description": "create rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficWeight"
+ ],
+ "summary": "create rule",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "weight",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Weight"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "bool"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "delete": {
+ "description": "delete rule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "TrafficWeight"
+ ],
+ "summary": "delete rule",
+ "parameters": [
+ {
+ "description": "rule",
+ "name": "weight",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.Weight"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "bool"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ }
+ }
+ },
+ "definitions": {
+ "model.Accesslog": {
+ "type": "object",
+ "required": [
+ "accesslog",
+ "application"
+ ],
+ "properties": {
+ "accesslog": {
+ "type": "string"
+ },
+ "application": {
+ "type": "string"
+ }
+ }
+ },
+ "model.AddressMatch": {
+ "type": "object",
+ "properties": {
+ "cird": {
+ "type": "string"
+ },
+ "exact": {
+ "type": "string"
+ },
+ "wildcard": {
+ "type": "string"
+ }
+ }
+ },
+ "model.Argument": {
+ "type": "object",
+ "required": [
+ "application",
+ "rule"
+ ],
+ "properties": {
+ "application": {
+ "type": "string"
+ },
+ "group": {
+ "type": "string"
+ },
+ "rule": {
+ "type": "string"
+ },
+ "version": {
+ "type": "string"
+ }
+ }
+ },
+ "model.ConditionMatch": {
+ "type": "object",
+ "properties": {
+ "address": {
+ "$ref": "#/definitions/model.AddressMatch"
+ },
+ "application": {
+ "$ref": "#/definitions/model.ListStringMatch"
+ },
+ "param": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/model.ParamMatch"
+ }
+ },
+ "service": {
+ "$ref": "#/definitions/model.ListStringMatch"
+ }
+ }
+ },
+ "model.ConditionRouteDto": {
+ "type": "object",
+ "required": [
+ "conditions",
+ "configVersion",
+ "enabled"
+ ],
+ "properties": {
+ "application": {
+ "type": "string"
+ },
+ "conditions": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "configVersion": {
+ "type": "string"
+ },
+ "enabled": {
+ "type": "boolean"
+ },
+ "force": {
+ "type": "boolean"
+ },
+ "id": {
+ "type": "string"
+ },
+ "priority": {
+ "type": "integer"
+ },
+ "runtime": {
+ "type": "boolean"
+ },
+ "service": {
+ "type": "string"
+ },
+ "serviceGroup": {
+ "type": "string"
+ },
+ "serviceVersion": {
+ "type": "string"
+ }
+ }
+ },
+ "model.Consumer": {
+ "type": "object",
+ "properties": {
+ "address": {
+ "type": "string"
+ },
+ "alived": {
+ "type": "integer"
+ },
+ "application": {
+ "type": "string"
+ },
+ "collected": {
+ "$ref": "#/definitions/time.Duration"
+ },
+ "created": {
+ "type": "string"
+ },
+ "expired": {
+ "$ref": "#/definitions/time.Duration"
+ },
+ "hash": {
+ "type": "string"
+ },
+ "id": {
+ "type": "integer"
+ },
+ "ids": {
+ "type": "array",
+ "items": {
+ "type": "integer"
+ }
+ },
+ "miss": {
+ "type": "boolean"
+ },
+ "modified": {
+ "type": "string"
+ },
+ "now": {
+ "type": "string"
+ },
+ "operator": {
+ "type": "string"
+ },
+ "operatorAddress": {
+ "type": "string"
+ },
+ "parameters": {
+ "type": "string"
+ },
+ "registry": {
+ "type": "string"
+ },
+ "result": {
+ "type": "string"
+ },
+ "service": {
+ "type": "string"
+ },
+ "statistics": {
+ "type": "string"
+ },
+ "username": {
+ "type": "string"
+ }
+ }
+ },
+ "model.DynamicConfig": {
+ "type": "object",
+ "properties": {
+ "application": {
+ "type": "string"
+ },
+ "configVersion": {
+ "type": "string"
+ },
+ "configs": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/model.OverrideConfig"
+ }
+ },
+ "enabled": {
+ "type": "boolean"
},
"id": {
"type": "string"
@@ -1015,6 +3139,24 @@
}
}
},
+ "model.Gray": {
+ "type": "object",
+ "required": [
+ "application",
+ "tags"
+ ],
+ "properties": {
+ "application": {
+ "type": "string"
+ },
+ "tags": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/model.Tag"
+ }
+ }
+ }
+ },
"model.HTTPError": {
"type": "object",
"properties": {
@@ -1038,6 +3180,38 @@
}
}
},
+ "model.ListServiceByPage": {
+ "type": "object",
+ "properties": {
+ "content": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/model.ServiceDTO"
+ }
+ },
+ "first": {
+ "type": "boolean"
+ },
+ "last": {
+ "type": "boolean"
+ },
+ "offset": {
+ "type": "integer"
+ },
+ "pageNumber": {
+ "type": "string"
+ },
+ "size": {
+ "type": "string"
+ },
+ "totalElements": {
+ "type": "integer"
+ },
+ "totalPages": {
+ "type": "integer"
+ }
+ }
+ },
"model.ListStringMatch": {
"type": "object",
"properties": {
@@ -1049,6 +3223,27 @@
}
}
},
+ "model.Mock": {
+ "type": "object",
+ "required": [
+ "mock",
+ "service"
+ ],
+ "properties": {
+ "group": {
+ "type": "string"
+ },
+ "mock": {
+ "type": "string"
+ },
+ "service": {
+ "type": "string"
+ },
+ "version": {
+ "type": "string"
+ }
+ }
+ },
"model.MockRule": {
"type": "object",
"properties": {
@@ -1092,9 +3287,7 @@
},
"parameters": {
"type": "object",
- "additionalProperties": {
- "type": "string"
- }
+ "additionalProperties": true
},
"providerAddresses": {
"type": "array",
@@ -1127,6 +3320,181 @@
}
}
},
+ "model.Provider": {
+ "type": "object",
+ "properties": {
+ "address": {
+ "type": "string"
+ },
+ "alived": {
+ "type": "integer"
+ },
+ "application": {
+ "type": "string"
+ },
+ "created": {
+ "type": "string"
+ },
+ "dynamic": {
+ "type": "boolean"
+ },
+ "enabled": {
+ "type": "boolean"
+ },
+ "expired": {
+ "$ref": "#/definitions/time.Duration"
+ },
+ "hash": {
+ "type": "string"
+ },
+ "id": {
+ "type": "integer"
+ },
+ "ids": {
+ "type": "array",
+ "items": {
+ "type": "integer"
+ }
+ },
+ "miss": {
+ "type": "boolean"
+ },
+ "modified": {
+ "type": "string"
+ },
+ "now": {
+ "type": "string"
+ },
+ "operator": {
+ "type": "string"
+ },
+ "operatorAddress": {
+ "type": "string"
+ },
+ "parameters": {
+ "type": "string"
+ },
+ "registry": {
+ "type": "string"
+ },
+ "registrySource": {
+ "$ref": "#/definitions/model.RegistrySource"
+ },
+ "serialization": {
+ "type": "string"
+ },
+ "service": {
+ "type": "string"
+ },
+ "timeout": {
+ "type": "integer"
+ },
+ "url": {
+ "type": "string"
+ },
+ "username": {
+ "type": "string"
+ },
+ "weight": {
+ "type": "integer"
+ }
+ }
+ },
+ "model.Region": {
+ "type": "object",
+ "required": [
+ "rule",
+ "service"
+ ],
+ "properties": {
+ "group": {
+ "type": "string"
+ },
+ "rule": {
+ "type": "string"
+ },
+ "service": {
+ "type": "string"
+ },
+ "version": {
+ "type": "string"
+ }
+ }
+ },
+ "model.RegistrySource": {
+ "type": "string",
+ "enum": [
+ "ALL"
+ ],
+ "x-enum-varnames": [
+ "All"
+ ]
+ },
+ "model.Retry": {
+ "type": "object",
+ "required": [
+ "retry",
+ "service"
+ ],
+ "properties": {
+ "group": {
+ "type": "string"
+ },
+ "retry": {
+ "type": "integer"
+ },
+ "service": {
+ "type": "string"
+ },
+ "version": {
+ "type": "string"
+ }
+ }
+ },
+ "model.ServiceDTO": {
+ "type": "object",
+ "properties": {
+ "appName": {
+ "type": "string"
+ },
+ "group": {
+ "type": "string"
+ },
+ "registrySource": {
+ "$ref": "#/definitions/model.RegistrySource"
+ },
+ "service": {
+ "type": "string"
+ },
+ "version": {
+ "type": "string"
+ }
+ }
+ },
+ "model.ServiceDetailDTO": {
+ "type": "object",
+ "properties": {
+ "application": {
+ "type": "string"
+ },
+ "consumers": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/model.Consumer"
+ }
+ },
+ "metadata": {},
+ "providers": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/model.Provider"
+ }
+ },
+ "service": {
+ "type": "string"
+ }
+ }
+ },
"model.StringMatch": {
"type": "object",
"properties": {
@@ -1149,6 +3517,151 @@
"type": "string"
}
}
+ },
+ "model.Tag": {
+ "type": "object",
+ "required": [
+ "match",
+ "name"
+ ],
+ "properties": {
+ "addresses": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "match": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/model.ParamMatch"
+ }
+ },
+ "name": {
+ "type": "string"
+ }
+ }
+ },
+ "model.TagRouteDto": {
+ "type": "object",
+ "required": [
+ "configVersion",
+ "enabled",
+ "tags"
+ ],
+ "properties": {
+ "application": {
+ "type": "string"
+ },
+ "configVersion": {
+ "type": "string"
+ },
+ "enabled": {
+ "type": "boolean"
+ },
+ "force": {
+ "type": "boolean"
+ },
+ "id": {
+ "type": "string"
+ },
+ "priority": {
+ "type": "integer"
+ },
+ "runtime": {
+ "type": "boolean"
+ },
+ "service": {
+ "type": "string"
+ },
+ "serviceGroup": {
+ "type": "string"
+ },
+ "serviceVersion": {
+ "type": "string"
+ },
+ "tags": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/model.Tag"
+ }
+ }
+ }
+ },
+ "model.Timeout": {
+ "type": "object",
+ "required": [
+ "service",
+ "timeout"
+ ],
+ "properties": {
+ "group": {
+ "type": "string"
+ },
+ "service": {
+ "type": "string"
+ },
+ "timeout": {
+ "type": "integer"
+ },
+ "version": {
+ "type": "string"
+ }
+ }
+ },
+ "model.Weight": {
+ "type": "object",
+ "required": [
+ "match",
+ "weight"
+ ],
+ "properties": {
+ "match": {
+ "$ref": "#/definitions/model.ConditionMatch"
+ },
+ "weight": {
+ "type": "integer"
+ }
+ }
+ },
+ "time.Duration": {
+ "type": "integer",
+ "enum": [
+ -9223372036854775808,
+ 9223372036854775807,
+ 1,
+ 1000,
+ 1000000,
+ 1000000000,
+ 60000000000,
+ 3600000000000,
+ -9223372036854775808,
+ 9223372036854775807,
+ 1,
+ 1000,
+ 1000000,
+ 1000000000,
+ 60000000000,
+ 3600000000000
+ ],
+ "x-enum-varnames": [
+ "minDuration",
+ "maxDuration",
+ "Nanosecond",
+ "Microsecond",
+ "Millisecond",
+ "Second",
+ "Minute",
+ "Hour",
+ "minDuration",
+ "maxDuration",
+ "Nanosecond",
+ "Microsecond",
+ "Millisecond",
+ "Second",
+ "Minute",
+ "Hour"
+ ]
}
}
}
\ No newline at end of file
diff --git a/pkg/admin/config/governance_config.go b/pkg/admin/config/governance_config.go
index 0e309f0c..f9705e77 100644
--- a/pkg/admin/config/governance_config.go
+++ b/pkg/admin/config/governance_config.go
@@ -55,6 +55,7 @@ type GovernanceConfig interface {
DeleteConfigWithGroup(group string, key string) error
Register(url *common.URL) error
UnRegister(url *common.URL) error
+ GetList(group string) (map[string]string, error)
}
var impls map[string]func(cc config_center.DynamicConfiguration) GovernanceConfig
@@ -135,6 +136,23 @@ func (g *GovernanceConfigImpl) UnRegister(url *common.URL) error {
return RegistryCenter.UnRegister(url)
}
+func (g *GovernanceConfigImpl) GetList(group string) (map[string]string, error) {
+ keys, err := g.configCenter.GetConfigKeysByGroup(group)
+ if err != nil {
+ return nil, err
+ }
+
+ list := make(map[string]string)
+ for k := range keys.Items {
+ rule, err := g.configCenter.GetRule(k.(string), config_center.WithGroup(group))
+ if err != nil {
+ return nil, err
+ }
+ list[k.(string)] = rule
+ }
+ return list, nil
+}
+
type ZkGovImpl struct {
GovernanceConfig
configCenter config_center.DynamicConfiguration
@@ -171,6 +189,10 @@ func (zk *ZkGovImpl) SetConfig(key string, value string) error {
return nil
}
+func (zk *ZkGovImpl) GetList(group string) (map[string]string, error) {
+ return zk.GovernanceConfig.GetList(group)
+}
+
type NacosGovImpl struct {
GovernanceConfig
configCenter config_center.DynamicConfiguration
@@ -186,3 +208,7 @@ func (n *NacosGovImpl) GetConfig(key string) (string, error) {
func (n *NacosGovImpl) SetConfig(key string, value string) error {
return n.GovernanceConfig.SetConfig(key, value)
}
+
+func (n *NacosGovImpl) GetList(group string) (map[string]string, error) {
+ return n.GovernanceConfig.GetList(group)
+}
diff --git a/pkg/admin/config/governance_config_mock.go b/pkg/admin/config/mock_config/governance_config_mock.go
similarity index 54%
rename from pkg/admin/config/governance_config_mock.go
rename to pkg/admin/config/mock_config/governance_config_mock.go
index 0904812c..8fdc9681 100644
--- a/pkg/admin/config/governance_config_mock.go
+++ b/pkg/admin/config/mock_config/governance_config_mock.go
@@ -1,25 +1,8 @@
-/*
- * 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.
- */
-
// Code generated by MockGen. DO NOT EDIT.
-// Source: github.com/apache/dubbo-admin/pkg/admin/config (interfaces: GovernanceConfig)
+// Source: governance_config.go
-// Package config is a generated GoMock package.
-package config
+// Package mock_config is a generated GoMock package.
+package mock_config
import (
reflect "reflect"
@@ -52,115 +35,130 @@ func (m *MockGovernanceConfig) EXPECT() *MockGovernanceConfigMockRecorder {
}
// DeleteConfig mocks base method.
-func (m *MockGovernanceConfig) DeleteConfig(arg0 string) error {
+func (m *MockGovernanceConfig) DeleteConfig(key string) error {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "DeleteConfig", arg0)
+ ret := m.ctrl.Call(m, "DeleteConfig", key)
ret0, _ := ret[0].(error)
return ret0
}
// DeleteConfig indicates an expected call of DeleteConfig.
-func (mr *MockGovernanceConfigMockRecorder) DeleteConfig(arg0 interface{}) *gomock.Call {
+func (mr *MockGovernanceConfigMockRecorder) DeleteConfig(key interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteConfig", reflect.TypeOf((*MockGovernanceConfig)(nil).DeleteConfig), arg0)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteConfig", reflect.TypeOf((*MockGovernanceConfig)(nil).DeleteConfig), key)
}
// DeleteConfigWithGroup mocks base method.
-func (m *MockGovernanceConfig) DeleteConfigWithGroup(arg0, arg1 string) error {
+func (m *MockGovernanceConfig) DeleteConfigWithGroup(group, key string) error {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "DeleteConfigWithGroup", arg0, arg1)
+ ret := m.ctrl.Call(m, "DeleteConfigWithGroup", group, key)
ret0, _ := ret[0].(error)
return ret0
}
// DeleteConfigWithGroup indicates an expected call of DeleteConfigWithGroup.
-func (mr *MockGovernanceConfigMockRecorder) DeleteConfigWithGroup(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockGovernanceConfigMockRecorder) DeleteConfigWithGroup(group, key interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteConfigWithGroup", reflect.TypeOf((*MockGovernanceConfig)(nil).DeleteConfigWithGroup), arg0, arg1)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteConfigWithGroup", reflect.TypeOf((*MockGovernanceConfig)(nil).DeleteConfigWithGroup), group, key)
}
// GetConfig mocks base method.
-func (m *MockGovernanceConfig) GetConfig(arg0 string) (string, error) {
+func (m *MockGovernanceConfig) GetConfig(key string) (string, error) {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetConfig", arg0)
+ ret := m.ctrl.Call(m, "GetConfig", key)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetConfig indicates an expected call of GetConfig.
-func (mr *MockGovernanceConfigMockRecorder) GetConfig(arg0 interface{}) *gomock.Call {
+func (mr *MockGovernanceConfigMockRecorder) GetConfig(key interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConfig", reflect.TypeOf((*MockGovernanceConfig)(nil).GetConfig), arg0)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConfig", reflect.TypeOf((*MockGovernanceConfig)(nil).GetConfig), key)
}
// GetConfigWithGroup mocks base method.
-func (m *MockGovernanceConfig) GetConfigWithGroup(arg0, arg1 string) (string, error) {
+func (m *MockGovernanceConfig) GetConfigWithGroup(group, key string) (string, error) {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetConfigWithGroup", arg0, arg1)
+ ret := m.ctrl.Call(m, "GetConfigWithGroup", group, key)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetConfigWithGroup indicates an expected call of GetConfigWithGroup.
-func (mr *MockGovernanceConfigMockRecorder) GetConfigWithGroup(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockGovernanceConfigMockRecorder) GetConfigWithGroup(group, key interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConfigWithGroup", reflect.TypeOf((*MockGovernanceConfig)(nil).GetConfigWithGroup), group, key)
+}
+
+// GetList mocks base method.
+func (m *MockGovernanceConfig) GetList(group string) (map[string]string, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "GetList", group)
+ ret0, _ := ret[0].(map[string]string)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// GetList indicates an expected call of GetList.
+func (mr *MockGovernanceConfigMockRecorder) GetList(group interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConfigWithGroup", reflect.TypeOf((*MockGovernanceConfig)(nil).GetConfigWithGroup), arg0, arg1)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetList", reflect.TypeOf((*MockGovernanceConfig)(nil).GetList), group)
}
// Register mocks base method.
-func (m *MockGovernanceConfig) Register(arg0 *common.URL) error {
+func (m *MockGovernanceConfig) Register(url *common.URL) error {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "Register", arg0)
+ ret := m.ctrl.Call(m, "Register", url)
ret0, _ := ret[0].(error)
return ret0
}
// Register indicates an expected call of Register.
-func (mr *MockGovernanceConfigMockRecorder) Register(arg0 interface{}) *gomock.Call {
+func (mr *MockGovernanceConfigMockRecorder) Register(url interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Register", reflect.TypeOf((*MockGovernanceConfig)(nil).Register), arg0)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Register", reflect.TypeOf((*MockGovernanceConfig)(nil).Register), url)
}
// SetConfig mocks base method.
-func (m *MockGovernanceConfig) SetConfig(arg0, arg1 string) error {
+func (m *MockGovernanceConfig) SetConfig(key, value string) error {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "SetConfig", arg0, arg1)
+ ret := m.ctrl.Call(m, "SetConfig", key, value)
ret0, _ := ret[0].(error)
return ret0
}
// SetConfig indicates an expected call of SetConfig.
-func (mr *MockGovernanceConfigMockRecorder) SetConfig(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockGovernanceConfigMockRecorder) SetConfig(key, value interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetConfig", reflect.TypeOf((*MockGovernanceConfig)(nil).SetConfig), arg0, arg1)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetConfig", reflect.TypeOf((*MockGovernanceConfig)(nil).SetConfig), key, value)
}
// SetConfigWithGroup mocks base method.
-func (m *MockGovernanceConfig) SetConfigWithGroup(arg0, arg1, arg2 string) error {
+func (m *MockGovernanceConfig) SetConfigWithGroup(group, key, value string) error {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "SetConfigWithGroup", arg0, arg1, arg2)
+ ret := m.ctrl.Call(m, "SetConfigWithGroup", group, key, value)
ret0, _ := ret[0].(error)
return ret0
}
// SetConfigWithGroup indicates an expected call of SetConfigWithGroup.
-func (mr *MockGovernanceConfigMockRecorder) SetConfigWithGroup(arg0, arg1, arg2 interface{}) *gomock.Call {
+func (mr *MockGovernanceConfigMockRecorder) SetConfigWithGroup(group, key, value interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetConfigWithGroup", reflect.TypeOf((*MockGovernanceConfig)(nil).SetConfigWithGroup), arg0, arg1, arg2)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetConfigWithGroup", reflect.TypeOf((*MockGovernanceConfig)(nil).SetConfigWithGroup), group, key, value)
}
// UnRegister mocks base method.
-func (m *MockGovernanceConfig) UnRegister(arg0 *common.URL) error {
+func (m *MockGovernanceConfig) UnRegister(url *common.URL) error {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "UnRegister", arg0)
+ ret := m.ctrl.Call(m, "UnRegister", url)
ret0, _ := ret[0].(error)
return ret0
}
// UnRegister indicates an expected call of UnRegister.
-func (mr *MockGovernanceConfigMockRecorder) UnRegister(arg0 interface{}) *gomock.Call {
+func (mr *MockGovernanceConfigMockRecorder) UnRegister(url interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnRegister", reflect.TypeOf((*MockGovernanceConfig)(nil).UnRegister), arg0)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnRegister", reflect.TypeOf((*MockGovernanceConfig)(nil).UnRegister), url)
}
diff --git a/pkg/admin/handlers/overrides.go b/pkg/admin/handlers/overrides.go
index 8850a4df..42109ce9 100644
--- a/pkg/admin/handlers/overrides.go
+++ b/pkg/admin/handlers/overrides.go
@@ -139,11 +139,7 @@ func SearchOverride(c *gin.Context) {
result := make([]*model.DynamicConfig, 0)
var err error
if service != "" {
- id := util.BuildServiceKey(model.Base{
- Service: service,
- ServiceGroup: serviceGroup,
- ServiceVersion: serviceVersion,
- })
+ id := util.BuildServiceKey("", service, serviceGroup, serviceVersion)
override, err = overrideServiceImpl.FindOverride(id)
} else if application != "" {
override, err = overrideServiceImpl.FindOverride(application)
diff --git a/pkg/admin/handlers/traffic/accesslog.go b/pkg/admin/handlers/traffic/accesslog.go
new file mode 100644
index 00000000..9241715c
--- /dev/null
+++ b/pkg/admin/handlers/traffic/accesslog.go
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+package traffic
+
+import (
+ "net/http"
+
+ "github.com/apache/dubbo-admin/pkg/admin/model"
+ "github.com/apache/dubbo-admin/pkg/admin/services/traffic"
+ "github.com/apache/dubbo-admin/pkg/logger"
+ "github.com/gin-gonic/gin"
+)
+
+var accesslogSvc = &traffic.AccesslogService{}
+
+// CreateAccesslog create rule
+// @Summary create rule
+// @Description create rule
+// @Tags TrafficAccesslog
+// @Accept json
+// @Produce json
+// @Param accesslog body model.Accesslog true "rule"
+// @Success 200 {bool} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/accesslog [post]
+func CreateAccesslog(c *gin.Context) {
+ doAccesslogUpdate(c, func(a *model.Accesslog) error {
+ return accesslogSvc.CreateOrUpdate(a)
+ })
+}
+
+// UpdateAccesslog create rule
+// @Summary create rule
+// @Description create rule
+// @Tags TrafficAccesslog
+// @Accept json
+// @Produce json
+// @Param accesslog body model.Accesslog true "rule"
+// @Success 200 {bool} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/accesslog [put]
+func UpdateAccesslog(c *gin.Context) {
+ doAccesslogUpdate(c, func(a *model.Accesslog) error {
+ return accesslogSvc.CreateOrUpdate(a)
+ })
+}
+
+// DeleteAccesslog delete rule
+// @Summary delete rule
+// @Description delete rule
+// @Tags TrafficAccesslog
+// @Accept json
+// @Produce json
+// @Param accesslog body model.Accesslog true "rule"
+// @Success 200 {bool} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/accesslog [delete]
+func DeleteAccesslog(c *gin.Context) {
+ doAccesslogUpdate(c, func(a *model.Accesslog) error {
+ return accesslogSvc.Delete(a)
+ })
+}
+
+// SearchAccesslog get rule list
+// @Summary get rule list
+// @Description get rule list
+// @Tags TrafficAccesslog
+// @Accept json
+// @Produce json
+// @Param accesslog body model.Accesslog true "rule"
+// @Success 200 {object} []model.Accesslog
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/accesslog [get]
+func SearchAccesslog(c *gin.Context) {
+ var a *model.Accesslog
+ if err := c.ShouldBindJSON(&a); err != nil {
+ logger.Errorf("Error parsing rule input when trying to create override rule, err msg is %s.", err.Error())
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error: err.Error()})
+ return
+ }
+
+ result, err := accesslogSvc.Search(a)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, model.HTTPError{Error: err.Error()})
+ }
+
+ c.JSON(http.StatusOK, result)
+}
+
+func doAccesslogUpdate(c *gin.Context, handle func(a *model.Accesslog) error) {
+ var a *model.Accesslog
+ if err := c.ShouldBindJSON(&a); err != nil {
+ logger.Errorf("Error parsing rule input when trying to create override rule, err msg is %s.", err.Error())
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error: err.Error()})
+ return
+ }
+
+ err := handle(a)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, model.HTTPError{Error: err.Error()})
+ }
+
+ c.JSON(http.StatusOK, true)
+}
diff --git a/pkg/admin/handlers/traffic/argument.go b/pkg/admin/handlers/traffic/argument.go
new file mode 100644
index 00000000..399ad148
--- /dev/null
+++ b/pkg/admin/handlers/traffic/argument.go
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+package traffic
+
+import (
+ "net/http"
+
+ "github.com/apache/dubbo-admin/pkg/admin/model"
+ "github.com/apache/dubbo-admin/pkg/admin/services/traffic"
+ "github.com/apache/dubbo-admin/pkg/logger"
+ "github.com/gin-gonic/gin"
+)
+
+var argumentSvc = &traffic.ArgumentService{}
+
+// CreateArgument create rule
+// @Summary create rule
+// @Description create rule
+// @Tags TrafficArgument
+// @Accept json
+// @Produce json
+// @Param argument body model.Argument true "rule"
+// @Success 200 {bool} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/argument [post]
+func CreateArgument(c *gin.Context) {
+ doArgumentUpdate(c, func(a *model.Argument) error {
+ return argumentSvc.CreateOrUpdate(a)
+ })
+}
+
+// UpdateArgument update rule
+// @Summary update rule
+// @Description update rule
+// @Tags TrafficArgument
+// @Accept json
+// @Produce json
+// @Param argument body model.Argument true "rule"
+// @Success 200 {bool} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/argument [put]
+func UpdateArgument(c *gin.Context) {
+ doArgumentUpdate(c, func(a *model.Argument) error {
+ return argumentSvc.CreateOrUpdate(a)
+ })
+}
+
+// DeleteArgument delete rule
+// @Summary delete rule
+// @Description delete rule
+// @Tags TrafficArgument
+// @Accept json
+// @Produce json
+// @Param argument body model.Argument true "rule"
+// @Success 200 {bool} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/argument [delete]
+func DeleteArgument(c *gin.Context) {
+ doArgumentUpdate(c, func(a *model.Argument) error {
+ return argumentSvc.Delete(a)
+ })
+}
+
+// SearchArgument get rule list
+// @Summary get rule list
+// @Description get rule list
+// @Tags TrafficArgument
+// @Accept json
+// @Produce json
+// @Param argument body model.Argument true "rule"
+// @Success 200 {object} []model.Argument
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/argument [get]
+func SearchArgument(c *gin.Context) {
+ var a *model.Argument
+ if err := c.ShouldBindJSON(&a); err != nil {
+ logger.Errorf("Error parsing rule input when trying to create override rule, err msg is %s.", err.Error())
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error: err.Error()})
+ return
+ }
+
+ result, err := argumentSvc.Search(a)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, model.HTTPError{Error: err.Error()})
+ }
+
+ c.JSON(http.StatusOK, result)
+}
+
+func doArgumentUpdate(c *gin.Context, handle func(a *model.Argument) error) {
+ var a *model.Argument
+ if err := c.ShouldBindJSON(&a); err != nil {
+ logger.Errorf("Error parsing rule input when trying to create override rule, err msg is %s.", err.Error())
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error: err.Error()})
+ return
+ }
+
+ err := handle(a)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, model.HTTPError{Error: err.Error()})
+ }
+
+ c.JSON(http.StatusOK, true)
+}
diff --git a/pkg/admin/handlers/traffic/gray.go b/pkg/admin/handlers/traffic/gray.go
new file mode 100644
index 00000000..544c68a7
--- /dev/null
+++ b/pkg/admin/handlers/traffic/gray.go
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+package traffic
+
+import (
+ "net/http"
+
+ "github.com/apache/dubbo-admin/pkg/admin/model"
+ "github.com/apache/dubbo-admin/pkg/admin/services/traffic"
+ "github.com/apache/dubbo-admin/pkg/logger"
+ "github.com/gin-gonic/gin"
+)
+
+var graySVC = &traffic.GrayService{}
+
+// CreateGray create rule
+// @Summary create rule
+// @Description create rule
+// @Tags TrafficGray
+// @Accept json
+// @Produce json
+// @Param gray body model.Gray true "rule"
+// @Success 200 {bool} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/gray [post]
+func CreateGray(c *gin.Context) {
+ doGrayUpdate(c, func(g *model.Gray) error {
+ return graySVC.CreateOrUpdate(g)
+ })
+}
+
+// UpdateGray update rule
+// @Summary update rule
+// @Description update rule
+// @Tags TrafficGray
+// @Accept json
+// @Produce json
+// @Param gray body model.Gray true "rule"
+// @Success 200 {bool} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/gray [put]
+func UpdateGray(c *gin.Context) {
+ doGrayUpdate(c, func(g *model.Gray) error {
+ return graySVC.CreateOrUpdate(g)
+ })
+}
+
+// DeleteGray delete rule
+// @Summary delete rule
+// @Description delete rule
+// @Tags TrafficGray
+// @Accept json
+// @Produce json
+// @Param gray body model.Gray true "rule"
+// @Success 200 {bool} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/gray [delete]
+func DeleteGray(c *gin.Context) {
+ doGrayUpdate(c, func(g *model.Gray) error {
+ return graySVC.Delete(g)
+ })
+}
+
+// SearchGray get rule list
+// @Summary get rule list
+// @Description get rule list
+// @Tags TrafficGray
+// @Accept json
+// @Produce json
+// @Param gray body model.Gray true "rule"
+// @Success 200 {object} []model.Gray
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/gray [get]
+func SearchGray(c *gin.Context) {
+ var g *model.Gray
+ if err := c.ShouldBindJSON(&g); err != nil {
+ logger.Errorf("Error parsing rule input when trying to create override rule, err msg is %s.", err.Error())
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error: err.Error()})
+ return
+ }
+
+ result, err := graySVC.Search(g)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, model.HTTPError{Error: err.Error()})
+ }
+
+ c.JSON(http.StatusOK, result)
+}
+
+func doGrayUpdate(c *gin.Context, handle func(g *model.Gray) error) {
+ var g *model.Gray
+ if err := c.ShouldBindJSON(&g); err != nil {
+ logger.Errorf("Error parsing rule input when trying to create override rule, err msg is %s.", err.Error())
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error: err.Error()})
+ return
+ }
+
+ err := handle(g)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, model.HTTPError{Error: err.Error()})
+ }
+
+ c.JSON(http.StatusOK, true)
+}
diff --git a/pkg/admin/handlers/traffic/mock.go b/pkg/admin/handlers/traffic/mock.go
new file mode 100644
index 00000000..16d766ed
--- /dev/null
+++ b/pkg/admin/handlers/traffic/mock.go
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+package traffic
+
+import (
+ "net/http"
+
+ "github.com/apache/dubbo-admin/pkg/admin/model"
+ "github.com/apache/dubbo-admin/pkg/admin/services/traffic"
+ "github.com/apache/dubbo-admin/pkg/logger"
+ "github.com/gin-gonic/gin"
+)
+
+var mockSvc = &traffic.MockService{}
+
+// CreateMock create rule
+// @Summary create rule
+// @Description create rule
+// @Tags TrafficMock
+// @Accept json
+// @Produce json
+// @Param mock body model.Mock true "rule"
+// @Success 200 {bool} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/mock [post]
+func CreateMock(c *gin.Context) {
+ doMockUpdate(c, func(m *model.Mock) error {
+ return mockSvc.CreateOrUpdate(m)
+ })
+}
+
+// UpdateMock update rule
+// @Summary update rule
+// @Description update rule
+// @Tags TrafficMock
+// @Accept json
+// @Produce json
+// @Param mock body model.Mock true "rule"
+// @Success 200 {bool} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/mock [put]
+func UpdateMock(c *gin.Context) {
+ doMockUpdate(c, func(m *model.Mock) error {
+ return mockSvc.CreateOrUpdate(m)
+ })
+}
+
+// DeleteMock delete rule
+// @Summary delete rule
+// @Description delete rule
+// @Tags TrafficMock
+// @Accept json
+// @Produce json
+// @Param mock body model.Mock true "rule"
+// @Success 200 {bool} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/mock [delete]
+func DeleteMock(c *gin.Context) {
+ doMockUpdate(c, func(m *model.Mock) error {
+ return mockSvc.Delete(m)
+ })
+}
+
+// SearchMock get rule list
+// @Summary get rule list
+// @Description get rule list
+// @Tags TrafficMock
+// @Accept json
+// @Produce json
+// @Param mock body model.Mock true "rule"
+// @Success 200 {object} []model.Mock
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/mock [get]
+func SearchMock(c *gin.Context) {
+ var m *model.Mock
+ if err := c.ShouldBindJSON(&m); err != nil {
+ logger.Errorf("Error parsing rule input when trying to create override rule, err msg is %s.", err.Error())
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error: err.Error()})
+ return
+ }
+
+ result, err := mockSvc.Search(m)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, model.HTTPError{Error: err.Error()})
+ }
+
+ c.JSON(http.StatusOK, result)
+}
+
+func doMockUpdate(c *gin.Context, handle func(m *model.Mock) error) {
+ var m *model.Mock
+ if err := c.ShouldBindJSON(&m); err != nil {
+ logger.Errorf("Error parsing rule input when trying to create override rule, err msg is %s.", err.Error())
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error: err.Error()})
+ return
+ }
+
+ err := handle(m)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, model.HTTPError{Error: err.Error()})
+ }
+
+ c.JSON(http.StatusOK, true)
+}
diff --git a/pkg/admin/handlers/traffic/region.go b/pkg/admin/handlers/traffic/region.go
new file mode 100644
index 00000000..e9553f1b
--- /dev/null
+++ b/pkg/admin/handlers/traffic/region.go
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+package traffic
+
+import (
+ "net/http"
+
+ "github.com/apache/dubbo-admin/pkg/admin/model"
+ "github.com/apache/dubbo-admin/pkg/admin/services/traffic"
+ "github.com/apache/dubbo-admin/pkg/logger"
+ "github.com/gin-gonic/gin"
+)
+
+var regionSVC = &traffic.RegionService{}
+
+// CreateRegion create rule
+// @Summary create rule
+// @Description create rule
+// @Tags TrafficRegion
+// @Accept json
+// @Produce json
+// @Param region body model.Region true "rule"
+// @Success 200 {bool} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/region [post]
+func CreateRegion(c *gin.Context) {
+ doRegionUpdate(c, func(r *model.Region) error {
+ return regionSVC.CreateOrUpdate(r)
+ })
+}
+
+// UpdateRegion update rule
+// @Summary update rule
+// @Description update rule
+// @Tags TrafficRegion
+// @Accept json
+// @Produce json
+// @Param region body model.Region true "rule"
+// @Success 200 {bool} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/region [put]
+func UpdateRegion(c *gin.Context) {
+ doRegionUpdate(c, func(r *model.Region) error {
+ return regionSVC.CreateOrUpdate(r)
+ })
+}
+
+// DeleteRegion delete rule
+// @Summary delete rule
+// @Description delete rule
+// @Tags TrafficRegion
+// @Accept json
+// @Produce json
+// @Param region body model.Region true "rule"
+// @Success 200 {bool} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/region [delete]
+func DeleteRegion(c *gin.Context) {
+ doRegionUpdate(c, func(r *model.Region) error {
+ return regionSVC.Delete(r)
+ })
+}
+
+// SearchRegion get rule list
+// @Summary get rule list
+// @Description get rule list
+// @Tags TrafficRegion
+// @Accept json
+// @Produce json
+// @Param region body model.Region true "rule"
+// @Success 200 {object} []model.Region
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/region [get]
+func SearchRegion(c *gin.Context) {
+ var r *model.Region
+ if err := c.ShouldBindJSON(&r); err != nil {
+ logger.Errorf("Error parsing rule input when trying to create override rule, err msg is %s.", err.Error())
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error: err.Error()})
+ return
+ }
+
+ result, err := regionSVC.Search(r)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, model.HTTPError{Error: err.Error()})
+ }
+
+ c.JSON(http.StatusOK, result)
+}
+
+func doRegionUpdate(c *gin.Context, handle func(r *model.Region) error) {
+ var r *model.Region
+ if err := c.ShouldBindJSON(&r); err != nil {
+ logger.Errorf("Error parsing rule input when trying to create override rule, err msg is %s.", err.Error())
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error: err.Error()})
+ return
+ }
+
+ err := handle(r)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, model.HTTPError{Error: err.Error()})
+ }
+
+ c.JSON(http.StatusOK, true)
+}
diff --git a/pkg/admin/handlers/traffic/retry.go b/pkg/admin/handlers/traffic/retry.go
new file mode 100644
index 00000000..1f1c2681
--- /dev/null
+++ b/pkg/admin/handlers/traffic/retry.go
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+package traffic
+
+import (
+ "net/http"
+
+ "github.com/apache/dubbo-admin/pkg/admin/model"
+ "github.com/apache/dubbo-admin/pkg/admin/services/traffic"
+ "github.com/apache/dubbo-admin/pkg/logger"
+ "github.com/gin-gonic/gin"
+)
+
+var retrySvc = &traffic.RetryService{}
+
+// CreateRetry create rule
+// @Summary create rule
+// @Description create rule
+// @Tags TrafficRetry
+// @Accept json
+// @Produce json
+// @Param retry body model.Retry true "rule"
+// @Success 200 {bool} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/retry [post]
+func CreateRetry(c *gin.Context) {
+ doRetryUpdate(c, func(r *model.Retry) error {
+ return retrySvc.CreateOrUpdate(r)
+ })
+}
+
+// UpdateRetry update rule
+// @Summary update rule
+// @Description update rule
+// @Tags TrafficRetry
+// @Accept json
+// @Produce json
+// @Param retry body model.Retry true "rule"
+// @Success 200 {bool} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/retry [put]
+func UpdateRetry(c *gin.Context) {
+ doRetryUpdate(c, func(r *model.Retry) error {
+ return retrySvc.CreateOrUpdate(r)
+ })
+}
+
+// DeleteRetry delete rule
+// @Summary delete rule
+// @Description delete rule
+// @Tags TrafficRetry
+// @Accept json
+// @Produce json
+// @Param retry body model.Retry true "rule"
+// @Success 200 {bool} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/retry [delete]
+func DeleteRetry(c *gin.Context) {
+ doRetryUpdate(c, func(r *model.Retry) error {
+ return retrySvc.Delete(r)
+ })
+}
+
+// SearchRetry get rule list
+// @Summary get rule list
+// @Description get rule list
+// @Tags TrafficRetry
+// @Accept json
+// @Produce json
+// @Param retry body model.Retry true "rule"
+// @Success 200 {object} []model.Retry
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/retry [get]
+func SearchRetry(c *gin.Context) {
+ var r *model.Retry
+ if err := c.ShouldBindJSON(&r); err != nil {
+ logger.Errorf("Error parsing rule input when trying to create override rule, err msg is %s.", err.Error())
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error: err.Error()})
+ return
+ }
+
+ result, err := retrySvc.Search(r)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, model.HTTPError{Error: err.Error()})
+ }
+
+ c.JSON(http.StatusOK, result)
+}
+
+func doRetryUpdate(c *gin.Context, handle func(r *model.Retry) error) {
+ var r *model.Retry
+ if err := c.ShouldBindJSON(&r); err != nil {
+ logger.Errorf("Error parsing rule input when trying to create override rule, err msg is %s.", err.Error())
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error: err.Error()})
+ return
+ }
+
+ err := handle(r)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, model.HTTPError{Error: err.Error()})
+ }
+
+ c.JSON(http.StatusOK, true)
+}
diff --git a/pkg/admin/handlers/traffic/timeout.go b/pkg/admin/handlers/traffic/timeout.go
new file mode 100644
index 00000000..d4ec6cc7
--- /dev/null
+++ b/pkg/admin/handlers/traffic/timeout.go
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+package traffic
+
+import (
+ "net/http"
+
+ "github.com/apache/dubbo-admin/pkg/admin/model"
+ "github.com/apache/dubbo-admin/pkg/admin/services/traffic"
+ "github.com/apache/dubbo-admin/pkg/logger"
+ "github.com/gin-gonic/gin"
+)
+
+var timeoutSvc = &traffic.TimeoutService{}
+
+// CreateTimeout create a new timeout rule
+// @Summary Create a new timeout rule
+// @Description Create a new timeout rule
+// @Tags TrafficTimeout
+// @Accept json
+// @Produce json
+// @Param timeout body model.Timeout true "timeout rule"
+// @Success 200 {boolean} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/timeout [post]
+func CreateTimeout(c *gin.Context) {
+ doTimeoutUpdate(c, func(t *model.Timeout) error {
+ return timeoutSvc.CreateOrUpdate(t)
+ })
+}
+
+// UpdateTimeout update a new timeout rule
+// @Summary update a new timeout rule
+// @Description update a new timeout rule
+// @Tags TrafficTimeout
+// @Accept json
+// @Produce json
+// @Param timeout body model.Timeout true "timeout rule"
+// @Success 200 {boolean} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/timeout [put]
+func UpdateTimeout(c *gin.Context) {
+ doTimeoutUpdate(c, func(t *model.Timeout) error {
+ return timeoutSvc.CreateOrUpdate(t)
+ })
+}
+
+// DeleteTimeout delete a new timeout rule
+// @Summary delete a new timeout rule
+// @Description delete a new timeout rule
+// @Tags TrafficTimeout
+// @Accept json
+// @Produce json
+// @Param timeout body model.Timeout true "timeout rule"
+// @Success 200 {boolean} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/timeout [delete]
+func DeleteTimeout(c *gin.Context) {
+ doTimeoutUpdate(c, func(t *model.Timeout) error {
+ return timeoutSvc.Delete(t)
+ })
+}
+
+// SearchTimeout get timeout rule list
+// @Summary get timeout rule list
+// @Description get timeout rule list
+// @Tags TrafficTimeout
+// @Accept json
+// @Produce json
+// @Param timeout body model.Timeout true "timeout rule"
+// @Success 200 {object} []model.Timeout
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/timeout [get]
+func SearchTimeout(c *gin.Context) {
+ var t *model.Timeout
+ if err := c.ShouldBindJSON(&t); err != nil {
+ logger.Errorf("Error parsing rule input when trying to create override rule, err msg is %s.", err.Error())
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error: err.Error()})
+ return
+ }
+
+ result, err := timeoutSvc.Search(t)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, model.HTTPError{Error: err.Error()})
+ }
+
+ c.JSON(http.StatusOK, result)
+}
+
+func doTimeoutUpdate(c *gin.Context, handle func(t *model.Timeout) error) {
+ var t *model.Timeout
+ if err := c.ShouldBindJSON(&t); err != nil {
+ logger.Errorf("Error parsing rule input when trying to create override rule, err msg is %s.", err.Error())
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error: err.Error()})
+ return
+ }
+
+ err := handle(t)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, model.HTTPError{Error: err.Error()})
+ }
+
+ c.JSON(http.StatusOK, true)
+}
diff --git a/pkg/admin/handlers/traffic/weight.go b/pkg/admin/handlers/traffic/weight.go
new file mode 100644
index 00000000..5c435b3c
--- /dev/null
+++ b/pkg/admin/handlers/traffic/weight.go
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+package traffic
+
+import (
+ "net/http"
+
+ "github.com/apache/dubbo-admin/pkg/admin/model"
+ "github.com/apache/dubbo-admin/pkg/admin/services/traffic"
+ "github.com/apache/dubbo-admin/pkg/logger"
+ "github.com/gin-gonic/gin"
+)
+
+var weightSvc = &traffic.WeightService{}
+
+// CreateWeight create rule
+// @Summary create rule
+// @Description create rule
+// @Tags TrafficWeight
+// @Accept json
+// @Produce json
+// @Param weight body model.Weight true "rule"
+// @Success 200 {bool} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/weight [post]
+func CreateWeight(c *gin.Context) {
+ doWeightUpdate(c, func(p *model.Percentage) error {
+ return weightSvc.CreateOrUpdate(p)
+ })
+}
+
+// UpdateWeight update rule
+// @Summary update rule
+// @Description update rule
+// @Tags TrafficWeight
+// @Accept json
+// @Produce json
+// @Param weight body model.Weight true "rule"
+// @Success 200 {bool} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/weight [put]
+func UpdateWeight(c *gin.Context) {
+ doWeightUpdate(c, func(p *model.Percentage) error {
+ return weightSvc.CreateOrUpdate(p)
+ })
+}
+
+// DeleteWeight delete rule
+// @Summary delete rule
+// @Description delete rule
+// @Tags TrafficWeight
+// @Accept json
+// @Produce json
+// @Param weight body model.Weight true "rule"
+// @Success 200 {bool} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/weight [delete]
+func DeleteWeight(c *gin.Context) {
+ doWeightUpdate(c, func(p *model.Percentage) error {
+ return weightSvc.Delete(p)
+ })
+}
+
+// SearchWeight get rule list
+// @Summary get rule list
+// @Description get rule list
+// @Tags TrafficWeight
+// @Accept json
+// @Produce json
+// @Param weight body model.Weight true "rule"
+// @Success 200 {object} []model.Weight
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/traffic/weight [get]
+func SearchWeight(c *gin.Context) {
+ var p *model.Percentage
+ if err := c.ShouldBindJSON(&p); err != nil {
+ logger.Errorf("Error parsing rule input when trying to create override rule, err msg is %s.", err.Error())
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error: err.Error()})
+ return
+ }
+
+ result, err := weightSvc.Search(p)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, model.HTTPError{Error: err.Error()})
+ }
+
+ c.JSON(http.StatusOK, result)
+}
+
+func doWeightUpdate(c *gin.Context, handle func(p *model.Percentage) error) {
+ var p *model.Percentage
+ if err := c.ShouldBindJSON(&p); err != nil {
+ logger.Errorf("Error parsing rule input when trying to create override rule, err msg is %s.", err.Error())
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error: err.Error()})
+ return
+ }
+
+ err := handle(p)
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, model.HTTPError{Error: err.Error()})
+ }
+
+ c.JSON(http.StatusOK, true)
+}
diff --git a/pkg/admin/model/condition_route.go b/pkg/admin/model/condition_route.go
index f18f2a2a..bb70fea0 100644
--- a/pkg/admin/model/condition_route.go
+++ b/pkg/admin/model/condition_route.go
@@ -30,7 +30,7 @@ type ConditionRouteDto struct {
}
type ConditionRoute struct {
- Priority int `json:"priority" yaml:"priority"`
+ Priority int `json:"priority" yaml:"priority,omitempty"`
Enabled bool `json:"enabled" yaml:"enabled"`
Force bool `json:"force" yaml:"force"`
Runtime bool `json:"runtime" yaml:"runtime"`
diff --git a/pkg/admin/model/match.go b/pkg/admin/model/match.go
index f190bbea..4e1a5236 100644
--- a/pkg/admin/model/match.go
+++ b/pkg/admin/model/match.go
@@ -24,10 +24,10 @@ import (
)
type ConditionMatch struct {
- Address AddressMatch `json:"address" yaml:"address"`
- Service ListStringMatch `json:"service" yaml:"service"`
- Application ListStringMatch `json:"application" yaml:"application"`
- Param []ParamMatch `json:"param" yaml:"param"`
+ Address AddressMatch `json:"address" yaml:"address,omitempty"`
+ Service ListStringMatch `json:"service" yaml:"service,omitempty"`
+ Application ListStringMatch `json:"application" yaml:"application,omitempty"`
+ Param []ParamMatch `json:"param" yaml:"param,omitempty"`
}
type AddressMatch struct {
diff --git a/pkg/admin/model/override.go b/pkg/admin/model/override.go
index 9823a4e0..5ce1e456 100644
--- a/pkg/admin/model/override.go
+++ b/pkg/admin/model/override.go
@@ -16,6 +16,7 @@
package model
import (
+ "fmt"
"strings"
"github.com/apache/dubbo-admin/pkg/admin/constant"
@@ -30,15 +31,15 @@ type Override struct {
}
type OverrideConfig struct {
- Side string `json:"side" yaml:"side"`
- Addresses []string `json:"addresses" yaml:"addresses"`
- ProviderAddresses []string `json:"providerAddresses" yaml:"providerAddresses"`
- Parameters map[string]string `json:"parameters" yaml:"parameters"`
- Applications []string `json:"applications" yaml:"applications"`
- Services []string `json:"services" yaml:"services"`
- Type string `json:"type" yaml:"type"`
- Enabled bool `json:"enabled" yaml:"enabled"`
- Match ConditionMatch `json:"match" yaml:"match"`
+ Side string `json:"side" yaml:"side"`
+ Addresses []string `json:"addresses" yaml:"addresses,omitempty"`
+ ProviderAddresses []string `json:"providerAddresses" yaml:"providerAddresses,omitempty"`
+ Parameters map[string]interface{} `json:"parameters" yaml:"parameters"`
+ Applications []string `json:"applications" yaml:"applications,omitempty"`
+ Services []string `json:"services" yaml:"services,omitempty"`
+ Type string `json:"type" yaml:"type,omitempty"`
+ Enabled bool `json:"enabled" yaml:"enabled,omitempty"`
+ Match ConditionMatch `json:"match" yaml:"match,omitempty"`
}
func (o *Override) ToDynamicConfig() *DynamicConfig {
@@ -82,7 +83,7 @@ func (o *OldOverride) SetParamsByOverrideConfig(config OverrideConfig) {
var params strings.Builder
for key, value := range parameters {
- param := key + "=" + value
+ param := key + "=" + fmt.Sprintf("%f", value)
params.WriteString(param)
params.WriteString("&")
}
diff --git a/pkg/admin/model/tag_route.go b/pkg/admin/model/tag_route.go
index 4884abdd..2760281f 100644
--- a/pkg/admin/model/tag_route.go
+++ b/pkg/admin/model/tag_route.go
@@ -30,7 +30,7 @@ type TagRouteDto struct {
}
type TagRoute struct {
- Priority int `json:"priority" yaml:"priority"`
+ Priority int `json:"priority" yaml:"priority,omitempty"`
Enabled bool `json:"enabled" yaml:"enabled"`
Force bool `json:"force" yaml:"force"`
Runtime bool `json:"runtime" yaml:"runtime"`
@@ -41,6 +41,6 @@ type TagRoute struct {
type Tag struct {
Name string `json:"name" yaml:"name" binding:"required"`
- Match []ParamMatch `json:"match" yaml:"match" binding:"required"`
- Addresses []string `json:"addresses" yaml:"addresses"`
+ Match []ParamMatch `json:"match" yaml:"match" binding:"required,omitempty"`
+ Addresses []string `json:"addresses" yaml:"addresses,omitempty"`
}
diff --git a/pkg/admin/model/traffic.go b/pkg/admin/model/traffic.go
new file mode 100644
index 00000000..6ba5aa92
--- /dev/null
+++ b/pkg/admin/model/traffic.go
@@ -0,0 +1,191 @@
+/*
+ * 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.
+ */
+
+package model
+
+import (
+ "github.com/apache/dubbo-admin/pkg/admin/util"
+)
+
+const AdminIdentifier string = "& admin_rule!=false"
+
+type Timeout struct {
+ Service string `json:"service" binding:"required"`
+ Group string `json:"group"`
+ Version string `json:"version"`
+ Timeout int `json:"timeout" binding:"required"`
+}
+
+func (t Timeout) ToRule() Override {
+ return Override{
+ Key: util.ServiceKey(t.Service, t.Group, t.Version),
+ Scope: "service",
+ ConfigVersion: "v3.0",
+ Enabled: true,
+ Configs: []OverrideConfig{{
+ Side: "consumer",
+ Enabled: true,
+ Parameters: map[string]interface{}{"timeout": t.Timeout},
+ }},
+ }
+}
+
+type Retry struct {
+ Service string `json:"service" binding:"required"`
+ Group string `json:"group"`
+ Version string `json:"version"`
+ Retry int `json:"retry" binding:"required"`
+}
+
+func (t Retry) ToRule() Override {
+ return Override{
+ Key: t.Service,
+ Scope: "service",
+ ConfigVersion: "v3.0",
+ Enabled: true,
+ Configs: []OverrideConfig{{
+ Side: "consumer",
+ Parameters: map[string]interface{}{"retries": t.Retry},
+ }},
+ }
+}
+
+type Accesslog struct {
+ Application string `json:"application" binding:"required"`
+ Accesslog string `json:"accesslog" binding:"required"`
+}
+
+func (t Accesslog) ToRule() Override {
+ return Override{
+ Key: t.Application,
+ Scope: "application",
+ ConfigVersion: "v3.0",
+ Enabled: true,
+ Configs: []OverrideConfig{{
+ Side: "provider",
+ Parameters: map[string]interface{}{"accesslog": t.Accesslog},
+ }},
+ }
+}
+
+type Region struct {
+ Service string `json:"service" binding:"required"`
+ Group string `json:"group"`
+ Version string `json:"version"`
+ Rule string `json:"rule" binding:"required"`
+}
+
+func (r Region) ToRule() ConditionRoute {
+ return ConditionRoute{
+ Enabled: true,
+ Force: false,
+ Runtime: true,
+ Key: r.Service,
+ Scope: "service",
+ ConfigVersion: "v3.0",
+ Conditions: []string{r.Rule + AdminIdentifier},
+ }
+}
+
+type Gray struct {
+ Application string `json:"application" binding:"required"`
+ Tags []Tag `json:"tags" binding:"required"`
+}
+
+func (g Gray) ToRule() TagRoute {
+ return TagRoute{
+ Enabled: true,
+ Force: true,
+ Runtime: true,
+ Key: g.Application,
+ ConfigVersion: "v3.0",
+ Tags: g.Tags,
+ }
+}
+
+type Argument struct {
+ Service string `json:"application" binding:"required"`
+ Group string `json:"group"`
+ Version string `json:"version"`
+ Rule string `json:"rule" binding:"required"`
+}
+
+func (r Argument) ToRule() ConditionRoute {
+ return ConditionRoute{
+ Enabled: true,
+ Force: true,
+ Runtime: true,
+ Key: r.Service,
+ Scope: "service",
+ ConfigVersion: "v3.0",
+ Conditions: []string{r.Rule + AdminIdentifier},
+ }
+}
+
+type Percentage struct {
+ Service string `json:"service" binding:"required"`
+ Group string `json:"group"`
+ Version string `json:"version"`
+ Weights []Weight `json:"weights" binding:"required"`
+}
+type Weight struct {
+ Weight int `json:"weight" binding:"required"`
+ Match ConditionMatch `json:"match" binding:"required"`
+}
+
+func (p Percentage) ToRule() Override {
+ configs := make([]OverrideConfig, len(p.Weights))
+ for _, weight := range p.Weights {
+ configs = append(configs, OverrideConfig{
+ Side: "provider",
+ Match: weight.Match,
+ Parameters: map[string]interface{}{"weight": weight.Weight},
+ })
+ }
+ return Override{
+ Key: p.Service,
+ Scope: "service",
+ ConfigVersion: "v3.0",
+ Enabled: true,
+ Configs: configs,
+ }
+}
+
+type Mock struct {
+ Service string `json:"service" binding:"required"`
+ Group string `json:"group"`
+ Version string `json:"version"`
+ Mock string `json:"mock" binding:"required"`
+}
+
+func (t Mock) ToRule() Override {
+ return Override{
+ Key: t.Service,
+ Scope: "service",
+ ConfigVersion: "v3.0",
+ Enabled: true,
+ Configs: []OverrideConfig{{
+ Side: "consumer",
+ Parameters: map[string]interface{}{"mock": t.Mock},
+ }},
+ }
+}
+
+type Host struct {
+ Condition string `json:"condition" binding:"required"`
+ Host string `json:"host" binding:"required"`
+}
diff --git a/pkg/admin/util/override_utils.go b/pkg/admin/model/util/override_utils.go
similarity index 91%
rename from pkg/admin/util/override_utils.go
rename to pkg/admin/model/util/override_utils.go
index 90e0736d..21038205 100644
--- a/pkg/admin/util/override_utils.go
+++ b/pkg/admin/model/util/override_utils.go
@@ -23,12 +23,14 @@ import (
"dubbo.apache.org/dubbo-go/v3/common"
"github.com/apache/dubbo-admin/pkg/admin/constant"
"github.com/apache/dubbo-admin/pkg/admin/model"
+
+ "github.com/apache/dubbo-admin/pkg/admin/util"
)
func OldOverride2URL(o *model.OldOverride) (*common.URL, error) {
- group := GetGroup(o.Service)
- version := GetVersion(o.Service)
- interfaceName := GetInterface(o.Service)
+ group := util.GetGroup(o.Service)
+ version := util.GetVersion(o.Service)
+ interfaceName := util.GetInterface(o.Service)
var sb strings.Builder
sb.WriteString(constant.OverrideProtocol)
sb.WriteString("://")
diff --git a/pkg/admin/util/override_utils_test.go b/pkg/admin/model/util/override_utils_test.go
similarity index 100%
rename from pkg/admin/util/override_utils_test.go
rename to pkg/admin/model/util/override_utils_test.go
diff --git a/pkg/admin/util/sync_utils.go b/pkg/admin/model/util/sync_utils.go
similarity index 97%
rename from pkg/admin/util/sync_utils.go
rename to pkg/admin/model/util/sync_utils.go
index 7e531a4b..cfd99bf1 100644
--- a/pkg/admin/util/sync_utils.go
+++ b/pkg/admin/model/util/sync_utils.go
@@ -25,6 +25,7 @@ import (
"github.com/apache/dubbo-admin/pkg/admin/cache"
"github.com/apache/dubbo-admin/pkg/admin/constant"
"github.com/apache/dubbo-admin/pkg/admin/model"
+ "github.com/apache/dubbo-admin/pkg/admin/util"
)
const (
@@ -199,8 +200,8 @@ func Providers2DTO(providers []*model.Provider) []*model.ServiceDTO {
serviceDTOs[i] = &model.ServiceDTO{
Service: providers[i].Service,
AppName: providers[i].Application,
- Group: GetGroup(providers[i].Service),
- Version: GetVersion(providers[i].Service),
+ Group: util.GetGroup(providers[i].Service),
+ Version: util.GetVersion(providers[i].Service),
RegistrySource: providers[i].RegistrySource,
}
}
diff --git a/pkg/admin/util/sync_utils_test.go b/pkg/admin/model/util/sync_utils_test.go
similarity index 100%
rename from pkg/admin/util/sync_utils_test.go
rename to pkg/admin/model/util/sync_utils_test.go
diff --git a/pkg/admin/router/router.go b/pkg/admin/router/router.go
index 69e71fb2..4eff69bb 100644
--- a/pkg/admin/router/router.go
+++ b/pkg/admin/router/router.go
@@ -22,6 +22,7 @@ import (
"github.com/apache/dubbo-admin/cmd/ui"
"github.com/apache/dubbo-admin/pkg/admin/handlers"
+ "github.com/apache/dubbo-admin/pkg/admin/handlers/traffic"
"github.com/gin-gonic/gin"
)
@@ -81,6 +82,70 @@ func InitRouter() *gin.Engine {
mockRoute.GET("/list", handlers.ListMockRulesByPage)
}
+ trafficTimeout := router.Group("/api/:env/traffic/timeout")
+ {
+ trafficTimeout.POST("/", traffic.CreateTimeout)
+ trafficTimeout.PUT("/", traffic.UpdateTimeout)
+ trafficTimeout.DELETE("/", traffic.DeleteTimeout)
+ trafficTimeout.GET("/", traffic.SearchTimeout)
+ }
+
+ trafficRetry := router.Group("/api/:env/traffic/retry")
+ {
+ trafficRetry.POST("/", traffic.CreateRetry)
+ trafficRetry.PUT("/", traffic.UpdateRetry)
+ trafficRetry.DELETE("/", traffic.DeleteRetry)
+ trafficRetry.GET("/", traffic.SearchRetry)
+ }
+
+ trafficAccesslog := router.Group("/api/:env/traffic/accesslog")
+ {
+ trafficAccesslog.POST("/", traffic.CreateAccesslog)
+ trafficAccesslog.PUT("/", traffic.UpdateAccesslog)
+ trafficAccesslog.DELETE("/", traffic.DeleteAccesslog)
+ trafficAccesslog.GET("/", traffic.SearchAccesslog)
+ }
+
+ trafficMock := router.Group("/api/:env/traffic/mock")
+ {
+ trafficMock.POST("/", traffic.CreateMock)
+ trafficMock.PUT("/", traffic.UpdateMock)
+ trafficMock.DELETE("/", traffic.DeleteMock)
+ trafficMock.GET("/", traffic.SearchMock)
+ }
+
+ trafficWeight := router.Group("/api/:env/traffic/weight")
+ {
+ trafficWeight.POST("/", traffic.CreateWeight)
+ trafficWeight.PUT("/", traffic.UpdateWeight)
+ trafficWeight.DELETE("/", traffic.DeleteWeight)
+ trafficWeight.GET("/", traffic.SearchWeight)
+ }
+
+ trafficArgument := router.Group("/api/:env/traffic/argument")
+ {
+ trafficArgument.POST("/", traffic.CreateArgument)
+ trafficArgument.PUT("/", traffic.UpdateArgument)
+ trafficArgument.DELETE("/", traffic.DeleteArgument)
+ trafficArgument.GET("/", traffic.SearchArgument)
+ }
+
+ trafficGray := router.Group("/api/:env/traffic/gray")
+ {
+ trafficGray.POST("/", traffic.CreateGray)
+ trafficGray.PUT("/", traffic.UpdateGray)
+ trafficGray.DELETE("/", traffic.DeleteGray)
+ trafficGray.GET("/", traffic.SearchGray)
+ }
+
+ trafficRegion := router.Group("/api/:env/traffic/region")
+ {
+ trafficRegion.POST("/", traffic.CreateRegion)
+ trafficRegion.PUT("/", traffic.UpdateRegion)
+ trafficRegion.DELETE("/", traffic.DeleteRegion)
+ trafficRegion.GET("/", traffic.SearchRegion)
+ }
+
// Admin UI
router.StaticFS("/admin", http.FS(ui.FS()))
diff --git a/pkg/admin/services/consumer_service_impl.go b/pkg/admin/services/consumer_service_impl.go
index d6e0f869..01e4c6e8 100644
--- a/pkg/admin/services/consumer_service_impl.go
+++ b/pkg/admin/services/consumer_service_impl.go
@@ -18,7 +18,7 @@ package services
import (
"github.com/apache/dubbo-admin/pkg/admin/constant"
"github.com/apache/dubbo-admin/pkg/admin/model"
- "github.com/apache/dubbo-admin/pkg/admin/util"
+ "github.com/apache/dubbo-admin/pkg/admin/model/util"
)
type ConsumerServiceImpl struct{}
diff --git a/pkg/admin/services/override_service_impl.go b/pkg/admin/services/override_service_impl.go
index 59bdb4ed..123f865b 100644
--- a/pkg/admin/services/override_service_impl.go
+++ b/pkg/admin/services/override_service_impl.go
@@ -23,15 +23,16 @@ import (
"github.com/apache/dubbo-admin/pkg/admin/config"
"github.com/apache/dubbo-admin/pkg/admin/constant"
"github.com/apache/dubbo-admin/pkg/admin/model"
- "github.com/apache/dubbo-admin/pkg/admin/util"
+ "github.com/apache/dubbo-admin/pkg/admin/model/util"
+ util2 "github.com/apache/dubbo-admin/pkg/admin/util"
"github.com/apache/dubbo-admin/pkg/logger"
)
type OverrideServiceImpl struct{}
func (s *OverrideServiceImpl) SaveOverride(dynamicConfig *model.DynamicConfig) error {
- id := util.BuildServiceKey(dynamicConfig.Base)
- path := getOverridePath(id)
+ id := util2.BuildServiceKey(dynamicConfig.Base.Application, dynamicConfig.Base.Service, dynamicConfig.Base.ServiceVersion, dynamicConfig.Base.ServiceGroup)
+ path := GetOverridePath(id)
existConfig, err := config.Governance.GetConfig(path)
if err != nil {
if _, ok := err.(*config.RuleNotFound); !ok {
@@ -91,8 +92,8 @@ func (s *OverrideServiceImpl) SaveOverride(dynamicConfig *model.DynamicConfig) e
}
func (s *OverrideServiceImpl) UpdateOverride(update *model.DynamicConfig) error {
- id := util.BuildServiceKey(update.Base)
- path := getOverridePath(id)
+ id := util2.BuildServiceKey(update.Base.Application, update.Base.Service, update.Base.ServiceVersion, update.Base.ServiceGroup)
+ path := GetOverridePath(id)
existConfig, err := config.Governance.GetConfig(path)
if err != nil {
logger.Logger().Error(err.Error())
@@ -153,7 +154,7 @@ func (s *OverrideServiceImpl) UpdateOverride(update *model.DynamicConfig) error
}
func (s *OverrideServiceImpl) DisableOverride(id string) error {
- path := getOverridePath(id)
+ path := GetOverridePath(id)
conf, err := config.Governance.GetConfig(path)
if err != nil {
@@ -206,7 +207,7 @@ func (s *OverrideServiceImpl) DisableOverride(id string) error {
}
func (s *OverrideServiceImpl) FindOverride(id string) (*model.DynamicConfig, error) {
- path := getOverridePath(id)
+ path := GetOverridePath(id)
conf, err := config.Governance.GetConfig(path)
if err != nil {
logger.Logger().Error(err.Error())
@@ -225,9 +226,9 @@ func (s *OverrideServiceImpl) FindOverride(id string) (*model.DynamicConfig, err
if dynamicConfig != nil {
dynamicConfig.ID = id
if constant.Service == override.Scope {
- dynamicConfig.Service = util.GetInterface(id)
- dynamicConfig.ServiceGroup = util.GetGroup(id)
- dynamicConfig.ServiceVersion = util.GetVersion(id)
+ dynamicConfig.Service = util2.GetInterface(id)
+ dynamicConfig.ServiceGroup = util2.GetGroup(id)
+ dynamicConfig.ServiceVersion = util2.GetVersion(id)
}
}
return dynamicConfig, nil
@@ -237,7 +238,7 @@ func (s *OverrideServiceImpl) FindOverride(id string) (*model.DynamicConfig, err
}
func (s *OverrideServiceImpl) EnableOverride(id string) error {
- path := getOverridePath(id)
+ path := GetOverridePath(id)
conf, err := config.Governance.GetConfig(path)
if err != nil {
logger.Logger().Error(err.Error())
@@ -288,7 +289,7 @@ func (s *OverrideServiceImpl) EnableOverride(id string) error {
}
func (s *OverrideServiceImpl) DeleteOverride(id string) error {
- path := getOverridePath(id)
+ path := GetOverridePath(id)
conf, err := config.Governance.GetConfig(path)
if err != nil {
logger.Logger().Error(err.Error())
@@ -353,7 +354,7 @@ func (s *OverrideServiceImpl) DeleteOverride(id string) error {
return nil
}
-func getOverridePath(key string) string {
+func GetOverridePath(key string) string {
key = strings.Replace(key, "/", "*", -1)
return key + constant.ConfiguratorRuleSuffix
}
diff --git a/pkg/admin/services/override_service_impl_test.go b/pkg/admin/services/override_service_impl_test.go
index bef58668..15f0b46b 100644
--- a/pkg/admin/services/override_service_impl_test.go
+++ b/pkg/admin/services/override_service_impl_test.go
@@ -21,6 +21,8 @@ import (
"reflect"
"testing"
+ "github.com/apache/dubbo-admin/pkg/admin/config/mock_config"
+
"github.com/apache/dubbo-admin/pkg/admin/config"
"github.com/apache/dubbo-admin/pkg/admin/constant"
"github.com/apache/dubbo-admin/pkg/admin/model"
@@ -29,7 +31,7 @@ import (
func TestOverrideServiceImpl_SaveOverride(t *testing.T) {
ctrl := gomock.NewController(t)
- mockGovernanceConfig := config.NewMockGovernanceConfig(ctrl)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
mockGovernanceConfig.EXPECT().SetConfig(gomock.Any(), gomock.Any()).Return(nil)
mockGovernanceConfig.EXPECT().GetConfig(gomock.Any()).Return("", nil)
mockGovernanceConfig.EXPECT().Register(gomock.Any()).Return(nil)
@@ -60,7 +62,7 @@ func TestOverrideServiceImpl_SaveOverride(t *testing.T) {
Configs: []model.OverrideConfig{
{
Addresses: []string{"0.0.0.0"},
- Parameters: map[string]string{
+ Parameters: map[string]interface{}{
"timeout": "1000",
},
Side: "consumer",
@@ -82,9 +84,9 @@ func TestOverrideServiceImpl_SaveOverride(t *testing.T) {
func TestOverrideServiceImpl_UpdateOverride(t *testing.T) {
ctrl := gomock.NewController(t)
- mockGovernanceConfig := config.NewMockGovernanceConfig(ctrl)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
mockGovernanceConfig.EXPECT().SetConfig(gomock.Any(), gomock.Any()).Return(nil)
- mockGovernanceConfig.EXPECT().GetConfig(getOverridePath("testService:testVersion:testGroup")).Return("configVersion: v2.7\nconfigs:\n- addresses:\n - 0.0.0.0\n enabled: false\n parameters:\n timeout: 6000\n side: consumer\nenabled: true\nkey: testService\nscope: service\n", nil)
+ mockGovernanceConfig.EXPECT().GetConfig(GetOverridePath("testService:testVersion:testGroup")).Return("configVersion: v2.7\nconfigs:\n- addresses:\n - 0.0.0.0\n enabled: false\n parameters:\n timeout: 6000\n side: consumer\nenabled: true\nkey: testService\nscope: service\n", nil)
mockGovernanceConfig.EXPECT().Register(gomock.Any()).Return(nil)
mockGovernanceConfig.EXPECT().UnRegister(gomock.Any()).Return(nil)
config.Governance = mockGovernanceConfig
@@ -114,7 +116,7 @@ func TestOverrideServiceImpl_UpdateOverride(t *testing.T) {
Configs: []model.OverrideConfig{
{
Addresses: []string{"0.0.0.0"},
- Parameters: map[string]string{
+ Parameters: map[string]interface{}{
"timeout": "1000",
},
Side: "consumer",
@@ -136,8 +138,8 @@ func TestOverrideServiceImpl_UpdateOverride(t *testing.T) {
func TestOverrideServiceImpl_FindOverride(t *testing.T) {
ctrl := gomock.NewController(t)
- mockGovernanceConfig := config.NewMockGovernanceConfig(ctrl)
- mockGovernanceConfig.EXPECT().GetConfig(getOverridePath("testGroup/testService:testVersion")).Return("configVersion: v2.7\nconfigs:\n- addresses:\n - 0.0.0.0\n enabled: false\n parameters:\n timeout: 6000\n side: consumer\nenabled: true\nkey: testService\nscope: service\n", nil)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
+ mockGovernanceConfig.EXPECT().GetConfig(GetOverridePath("testGroup/testService:testVersion")).Return("configVersion: v2.7\nconfigs:\n- addresses:\n - 0.0.0.0\n enabled: false\n parameters:\n timeout: 6000\n side: consumer\nenabled: true\nkey: testService\nscope: service\n", nil)
config.Governance = mockGovernanceConfig
type args struct {
@@ -168,8 +170,8 @@ func TestOverrideServiceImpl_FindOverride(t *testing.T) {
Configs: []model.OverrideConfig{
{
Addresses: []string{"0.0.0.0"},
- Parameters: map[string]string{
- "timeout": "6000",
+ Parameters: map[string]interface{}{
+ "timeout": 6000,
},
Enabled: false,
Side: "consumer",
@@ -194,9 +196,9 @@ func TestOverrideServiceImpl_FindOverride(t *testing.T) {
func TestOverrideServiceImpl_DeleteOverride(t *testing.T) {
ctrl := gomock.NewController(t)
- mockGovernanceConfig := config.NewMockGovernanceConfig(ctrl)
- mockGovernanceConfig.EXPECT().GetConfig(getOverridePath("testGroup/testService:testVersion")).Return("configVersion: v2.7\nconfigs:\n- addresses:\n - 0.0.0.0\n enabled: false\n parameters:\n timeout: 6000\n side: consumer\nenabled: true\nkey: testService\nscope: service\n", nil)
- mockGovernanceConfig.EXPECT().DeleteConfig(getOverridePath("testGroup/testService:testVersion")).Return(nil)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
+ mockGovernanceConfig.EXPECT().GetConfig(GetOverridePath("testGroup/testService:testVersion")).Return("configVersion: v2.7\nconfigs:\n- addresses:\n - 0.0.0.0\n enabled: false\n parameters:\n timeout: 6000\n side: consumer\nenabled: true\nkey: testService\nscope: service\n", nil)
+ mockGovernanceConfig.EXPECT().DeleteConfig(GetOverridePath("testGroup/testService:testVersion")).Return(nil)
mockGovernanceConfig.EXPECT().UnRegister(gomock.Any()).Return(nil)
config.Governance = mockGovernanceConfig
@@ -229,9 +231,9 @@ func TestOverrideServiceImpl_DeleteOverride(t *testing.T) {
func TestOverrideServiceImpl_EnableOverride(t *testing.T) {
ctrl := gomock.NewController(t)
- mockGovernanceConfig := config.NewMockGovernanceConfig(ctrl)
- mockGovernanceConfig.EXPECT().GetConfig(getOverridePath("testGroup/testService:testVersion")).Return("configVersion: v2.7\nconfigs:\n- addresses:\n - 0.0.0.0\n enabled: false\n parameters:\n timeout: 6000\n side: consumer\nenabled: true\nkey: testService\nscope: service\n", nil)
- mockGovernanceConfig.EXPECT().SetConfig(getOverridePath("testGroup/testService:testVersion"), gomock.Any()).Return(nil)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
+ mockGovernanceConfig.EXPECT().GetConfig(GetOverridePath("testGroup/testService:testVersion")).Return("configVersion: v2.7\nconfigs:\n- addresses:\n - 0.0.0.0\n enabled: false\n parameters:\n timeout: 6000\n side: consumer\nenabled: true\nkey: testService\nscope: service\n", nil)
+ mockGovernanceConfig.EXPECT().SetConfig(GetOverridePath("testGroup/testService:testVersion"), gomock.Any()).Return(nil)
mockGovernanceConfig.EXPECT().Register(gomock.Any()).Return(nil)
mockGovernanceConfig.EXPECT().UnRegister(gomock.Any()).Return(nil)
config.Governance = mockGovernanceConfig
@@ -265,9 +267,9 @@ func TestOverrideServiceImpl_EnableOverride(t *testing.T) {
func TestOverrideServiceImpl_DisableOverride(t *testing.T) {
ctrl := gomock.NewController(t)
- mockGovernanceConfig := config.NewMockGovernanceConfig(ctrl)
- mockGovernanceConfig.EXPECT().GetConfig(getOverridePath("testGroup/testService:testVersion")).Return("configVersion: v2.7\nconfigs:\n- addresses:\n - 0.0.0.0\n enabled: false\n parameters:\n timeout: 6000\n side: consumer\nenabled: true\nkey: testService\nscope: service\n", nil)
- mockGovernanceConfig.EXPECT().SetConfig(getOverridePath("testGroup/testService:testVersion"), gomock.Any()).Return(nil)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
+ mockGovernanceConfig.EXPECT().GetConfig(GetOverridePath("testGroup/testService:testVersion")).Return("configVersion: v2.7\nconfigs:\n- addresses:\n - 0.0.0.0\n enabled: false\n parameters:\n timeout: 6000\n side: consumer\nenabled: true\nkey: testService\nscope: service\n", nil)
+ mockGovernanceConfig.EXPECT().SetConfig(GetOverridePath("testGroup/testService:testVersion"), gomock.Any()).Return(nil)
mockGovernanceConfig.EXPECT().Register(gomock.Any()).Return(nil)
mockGovernanceConfig.EXPECT().UnRegister(gomock.Any()).Return(nil)
config.Governance = mockGovernanceConfig
@@ -318,7 +320,7 @@ func Test_getPath(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- if got := getOverridePath(tt.args.key); got != tt.want {
+ if got := GetOverridePath(tt.args.key); got != tt.want {
t.Errorf("getPath() = %v, want %v", got, tt.want)
}
})
diff --git a/pkg/admin/services/prometheus_service_impl.go b/pkg/admin/services/prometheus_service_impl.go
index 4b034945..3b5b546b 100644
--- a/pkg/admin/services/prometheus_service_impl.go
+++ b/pkg/admin/services/prometheus_service_impl.go
@@ -29,7 +29,8 @@ import (
"github.com/apache/dubbo-admin/pkg/admin/config"
"github.com/apache/dubbo-admin/pkg/admin/constant"
"github.com/apache/dubbo-admin/pkg/admin/model"
- "github.com/apache/dubbo-admin/pkg/admin/util"
+ "github.com/apache/dubbo-admin/pkg/admin/model/util"
+ util2 "github.com/apache/dubbo-admin/pkg/admin/util"
"github.com/apache/dubbo-admin/pkg/logger"
"github.com/apache/dubbo-admin/pkg/monitor/prometheus"
)
@@ -52,7 +53,7 @@ func (p *PrometheusServiceImpl) PromDiscovery(w http.ResponseWriter) error {
}
var targets []string
for i := 0; i < len(proAddr); i++ {
- targets = append(targets, util.GetDiscoveryPath(proAddr[i]))
+ targets = append(targets, util2.GetDiscoveryPath(proAddr[i]))
}
filterCon := make(map[string]string)
filterCon[constant.CategoryKey] = constant.ConsumersCategory
@@ -62,7 +63,7 @@ func (p *PrometheusServiceImpl) PromDiscovery(w http.ResponseWriter) error {
return err
}
for _, url := range servicesMap {
- targets = append(targets, util.GetDiscoveryPath(url.Location))
+ targets = append(targets, util2.GetDiscoveryPath(url.Location))
}
target := []model.Target{
{
diff --git a/pkg/admin/services/provider_service_impl.go b/pkg/admin/services/provider_service_impl.go
index eecd76f7..ff5df233 100644
--- a/pkg/admin/services/provider_service_impl.go
+++ b/pkg/admin/services/provider_service_impl.go
@@ -25,7 +25,7 @@ import (
"github.com/apache/dubbo-admin/pkg/admin/cache"
"github.com/apache/dubbo-admin/pkg/admin/constant"
"github.com/apache/dubbo-admin/pkg/admin/model"
- "github.com/apache/dubbo-admin/pkg/admin/util"
+ "github.com/apache/dubbo-admin/pkg/admin/model/util"
)
type ProviderServiceImpl struct{}
diff --git a/pkg/admin/services/provider_service_impl_test.go b/pkg/admin/services/provider_service_impl_test.go
index 2594fa58..cffa0e00 100644
--- a/pkg/admin/services/provider_service_impl_test.go
+++ b/pkg/admin/services/provider_service_impl_test.go
@@ -24,7 +24,7 @@ import (
"github.com/stretchr/testify/assert"
- "github.com/apache/dubbo-admin/pkg/admin/util"
+ "github.com/apache/dubbo-admin/pkg/admin/model/util"
"github.com/apache/dubbo-admin/pkg/admin/constant"
diff --git a/pkg/admin/services/route_service_impl.go b/pkg/admin/services/route_service_impl.go
index 2dd55425..49814ef8 100644
--- a/pkg/admin/services/route_service_impl.go
+++ b/pkg/admin/services/route_service_impl.go
@@ -30,16 +30,16 @@ import (
type RouteServiceImpl struct{}
func (t *RouteServiceImpl) CreateTagRoute(tagRoute model.TagRouteDto) error {
- id := util.BuildServiceKey(tagRoute.Base)
- path := getRoutePath(id, constant.TagRoute)
+ id := util.BuildServiceKey(tagRoute.Base.Application, tagRoute.Base.Service, tagRoute.Base.ServiceVersion, tagRoute.Base.ServiceGroup)
+ path := GetRoutePath(id, constant.TagRoute)
store := convertTagRouteToStore(tagRoute)
obj, _ := util.DumpObject(store)
return config.Governance.SetConfig(path, obj)
}
func (t *RouteServiceImpl) UpdateTagRoute(tagRoute model.TagRouteDto) error {
- id := util.BuildServiceKey(tagRoute.Base)
- path := getRoutePath(id, constant.TagRoute)
+ id := util.BuildServiceKey(tagRoute.Base.Application, tagRoute.Base.Service, tagRoute.Base.ServiceVersion, tagRoute.Base.ServiceGroup)
+ path := GetRoutePath(id, constant.TagRoute)
cfg, _ := config.Governance.GetConfig(path)
if cfg == "" {
return fmt.Errorf("tag route %s not found", id)
@@ -50,12 +50,12 @@ func (t *RouteServiceImpl) UpdateTagRoute(tagRoute model.TagRouteDto) error {
}
func (t *RouteServiceImpl) DeleteTagRoute(id string) error {
- path := getRoutePath(id, constant.TagRoute)
+ path := GetRoutePath(id, constant.TagRoute)
return config.Governance.DeleteConfig(path)
}
func (t *RouteServiceImpl) FindTagRoute(id string) (model.TagRouteDto, error) {
- path := getRoutePath(id, constant.TagRoute)
+ path := GetRoutePath(id, constant.TagRoute)
cfg, err := config.Governance.GetConfig(path)
if cfg != "" {
var tagRoute model.TagRoute
@@ -66,7 +66,7 @@ func (t *RouteServiceImpl) FindTagRoute(id string) (model.TagRouteDto, error) {
}
func (t *RouteServiceImpl) EnableTagRoute(id string) error {
- path := getRoutePath(id, constant.TagRoute)
+ path := GetRoutePath(id, constant.TagRoute)
cfg, err := config.Governance.GetConfig(path)
if cfg != "" {
var tagRoute model.TagRoute
@@ -79,7 +79,7 @@ func (t *RouteServiceImpl) EnableTagRoute(id string) error {
}
func (t *RouteServiceImpl) DisableTagRoute(id string) error {
- path := getRoutePath(id, constant.TagRoute)
+ path := GetRoutePath(id, constant.TagRoute)
cfg, err := config.Governance.GetConfig(path)
if cfg != "" {
var tagRoute model.TagRoute
@@ -92,8 +92,8 @@ func (t *RouteServiceImpl) DisableTagRoute(id string) error {
}
func (t *RouteServiceImpl) CreateConditionRoute(conditionRouteDto model.ConditionRouteDto) error {
- id := util.BuildServiceKey(conditionRouteDto.Base)
- path := getRoutePath(id, constant.ConditionRoute)
+ id := util.BuildServiceKey(conditionRouteDto.Base.Application, conditionRouteDto.Base.Service, conditionRouteDto.Base.ServiceVersion, conditionRouteDto.Base.ServiceGroup)
+ path := GetRoutePath(id, constant.ConditionRoute)
existConfig, _ := config.Governance.GetConfig(path)
var existRule model.ConditionRoute
@@ -107,8 +107,8 @@ func (t *RouteServiceImpl) CreateConditionRoute(conditionRouteDto model.Conditio
}
func (t *RouteServiceImpl) UpdateConditionRoute(conditionRouteDto model.ConditionRouteDto) error {
- id := util.BuildServiceKey(conditionRouteDto.Base)
- path := getRoutePath(id, constant.ConditionRoute)
+ id := util.BuildServiceKey(conditionRouteDto.Base.Application, conditionRouteDto.Base.Service, conditionRouteDto.Base.ServiceVersion, conditionRouteDto.Base.ServiceGroup)
+ path := GetRoutePath(id, constant.ConditionRoute)
cfg, err := config.Governance.GetConfig(path)
if err != nil {
return err
@@ -126,12 +126,12 @@ func (t *RouteServiceImpl) UpdateConditionRoute(conditionRouteDto model.Conditio
}
func (t *RouteServiceImpl) DeleteConditionRoute(id string) error {
- path := getRoutePath(id, constant.ConditionRoute)
+ path := GetRoutePath(id, constant.ConditionRoute)
return config.Governance.DeleteConfig(path)
}
func (t *RouteServiceImpl) FindConditionRouteById(id string) (model.ConditionRouteDto, error) {
- path := getRoutePath(id, constant.ConditionRoute)
+ path := GetRoutePath(id, constant.ConditionRoute)
cfg, err := config.Governance.GetConfig(path)
if err != nil {
return model.ConditionRouteDto{}, err
@@ -156,12 +156,12 @@ func (t *RouteServiceImpl) FindConditionRouteById(id string) (model.ConditionRou
return model.ConditionRouteDto{}, nil
}
-func (t *RouteServiceImpl) FindConditionRoute(dto model.ConditionRouteDto) (model.ConditionRouteDto, error) {
- return t.FindConditionRouteById(util.BuildServiceKey(dto.Base))
+func (t *RouteServiceImpl) FindConditionRoute(conditionRouteDto model.ConditionRouteDto) (model.ConditionRouteDto, error) {
+ return t.FindConditionRouteById(util.BuildServiceKey(conditionRouteDto.Base.Application, conditionRouteDto.Base.Service, conditionRouteDto.Base.ServiceVersion, conditionRouteDto.Base.ServiceGroup))
}
func (t *RouteServiceImpl) EnableConditionRoute(id string) error {
- path := getRoutePath(id, constant.ConditionRoute)
+ path := GetRoutePath(id, constant.ConditionRoute)
cfg, err := config.Governance.GetConfig(path)
if err != nil {
return err
@@ -177,7 +177,7 @@ func (t *RouteServiceImpl) EnableConditionRoute(id string) error {
}
func (t *RouteServiceImpl) DisableConditionRoute(id string) error {
- path := getRoutePath(id, constant.ConditionRoute)
+ path := GetRoutePath(id, constant.ConditionRoute)
cfg, err := config.Governance.GetConfig(path)
if err != nil {
return err
@@ -192,7 +192,7 @@ func (t *RouteServiceImpl) DisableConditionRoute(id string) error {
return fmt.Errorf("no existing condition route for path: %s", path)
}
-func getRoutePath(key string, routeType string) string {
+func GetRoutePath(key string, routeType string) string {
key = strings.ReplaceAll(key, "/", "*")
if routeType == constant.ConditionRoute {
return key + constant.ConditionRuleSuffix
diff --git a/pkg/admin/services/route_service_impl_test.go b/pkg/admin/services/route_service_impl_test.go
index d281f036..1a91c03d 100644
--- a/pkg/admin/services/route_service_impl_test.go
+++ b/pkg/admin/services/route_service_impl_test.go
@@ -21,6 +21,8 @@ import (
"reflect"
"testing"
+ "github.com/apache/dubbo-admin/pkg/admin/config/mock_config"
+
"github.com/apache/dubbo-admin/pkg/admin/config"
"github.com/apache/dubbo-admin/pkg/admin/constant"
"github.com/apache/dubbo-admin/pkg/admin/model"
@@ -30,7 +32,7 @@ import (
func TestRouteServiceImpl_CreateTagRoute(t *testing.T) {
ctrl := gomock.NewController(t)
- mockGovernanceConfig := config.NewMockGovernanceConfig(ctrl)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
mockGovernanceConfig.EXPECT().SetConfig(gomock.Any(), gomock.Any()).Return(nil)
config.Governance = mockGovernanceConfig
@@ -87,14 +89,9 @@ func TestRouteServiceImpl_CreateTagRoute(t *testing.T) {
func TestRouteServiceImpl_UpdateTagRoute(t *testing.T) {
ctrl := gomock.NewController(t)
- mockGovernanceConfig := config.NewMockGovernanceConfig(ctrl)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
mockGovernanceConfig.EXPECT().SetConfig(gomock.Any(), gomock.Any()).Return(nil)
- mockGovernanceConfig.EXPECT().GetConfig(getRoutePath(util.BuildServiceKey(model.Base{
- Application: "",
- Service: "testService",
- ServiceVersion: "testVersion",
- ServiceGroup: "testGroup",
- }), constant.TagRoute)).Return(`{"enabled":true,"force":true,"key":"testService:testVersion:testGroup","tags":[{"name":"gray","match":[{"key":"env","value":{"exact":"gray"}}]}]}`, nil)
+ mockGovernanceConfig.EXPECT().GetConfig(GetRoutePath(util.BuildServiceKey("", "testService", "testVersion", "testGroup"), constant.TagRoute)).Return(`{"enabled":true,"force":true,"key":"testService:testVersion:testGroup","tags":[{"name":"gray","match":[{"key":"env","value":{"exact":"gray"}}]}]}`, nil)
config.Governance = mockGovernanceConfig
type args struct {
@@ -150,13 +147,8 @@ func TestRouteServiceImpl_UpdateTagRoute(t *testing.T) {
func TestRouteServiceImpl_DeleteTagRoute(t *testing.T) {
ctrl := gomock.NewController(t)
- mockGovernanceConfig := config.NewMockGovernanceConfig(ctrl)
- mockGovernanceConfig.EXPECT().DeleteConfig(getRoutePath(util.BuildServiceKey(model.Base{
- Application: "",
- Service: "testService",
- ServiceVersion: "testVersion",
- ServiceGroup: "testGroup",
- }), constant.TagRoute)).Return(nil)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
+ mockGovernanceConfig.EXPECT().DeleteConfig(GetRoutePath(util.BuildServiceKey("", "testService", "testVersion", "testGroup"), constant.TagRoute)).Return(nil)
config.Governance = mockGovernanceConfig
type args struct {
@@ -189,13 +181,8 @@ func TestRouteServiceImpl_DeleteTagRoute(t *testing.T) {
func TestRouteServiceImpl_FindTagRoute(t *testing.T) {
ctrl := gomock.NewController(t)
- mockGovernanceConfig := config.NewMockGovernanceConfig(ctrl)
- mockGovernanceConfig.EXPECT().GetConfig(getRoutePath(util.BuildServiceKey(model.Base{
- Application: "",
- Service: "testService",
- ServiceVersion: "testVersion",
- ServiceGroup: "testGroup",
- }), constant.TagRoute)).Return(`{"enabled":true,"force":true,"key":"testService:testVersion:testGroup","tags":[{"name":"gray","match":[{"key":"env","value":{"exact":"gray"}}]}]}`, nil)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
+ mockGovernanceConfig.EXPECT().GetConfig(GetRoutePath(util.BuildServiceKey("", "testService", "testVersion", "testGroup"), constant.TagRoute)).Return(`{"enabled":true,"force":true,"key":"testService:testVersion:testGroup","tags":[{"name":"gray","match":[{"key":"env","value":{"exact":"gray"}}]}]}`, nil)
config.Governance = mockGovernanceConfig
type args struct {
@@ -253,14 +240,9 @@ func TestRouteServiceImpl_FindTagRoute(t *testing.T) {
func TestRouteServiceImpl_EnableTagRoute(t *testing.T) {
ctrl := gomock.NewController(t)
- mockGovernanceConfig := config.NewMockGovernanceConfig(ctrl)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
mockGovernanceConfig.EXPECT().SetConfig(gomock.Any(), gomock.Any()).Return(nil)
- mockGovernanceConfig.EXPECT().GetConfig(getRoutePath(util.BuildServiceKey(model.Base{
- Application: "",
- Service: "testService",
- ServiceVersion: "testVersion",
- ServiceGroup: "testGroup",
- }), constant.TagRoute)).Return(`{"enabled":true,"force":true,"key":"testService:testVersion:testGroup","tags":[{"name":"gray","match":[{"key":"env","value":{"exact":"gray"}}]}]}`, nil)
+ mockGovernanceConfig.EXPECT().GetConfig(GetRoutePath(util.BuildServiceKey("", "testService", "testVersion", "testGroup"), constant.TagRoute)).Return(`{"enabled":true,"force":true,"key":"testService:testVersion:testGroup","tags":[{"name":"gray","match":[{"key":"env","value":{"exact":"gray"}}]}]}`, nil)
config.Governance = mockGovernanceConfig
type args struct {
@@ -293,14 +275,9 @@ func TestRouteServiceImpl_EnableTagRoute(t *testing.T) {
func TestRouteServiceImpl_DisableTagRoute(t *testing.T) {
ctrl := gomock.NewController(t)
- mockGovernanceConfig := config.NewMockGovernanceConfig(ctrl)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
mockGovernanceConfig.EXPECT().SetConfig(gomock.Any(), gomock.Any()).Return(nil)
- mockGovernanceConfig.EXPECT().GetConfig(getRoutePath(util.BuildServiceKey(model.Base{
- Application: "",
- Service: "testService",
- ServiceVersion: "testVersion",
- ServiceGroup: "testGroup",
- }), constant.TagRoute)).Return(`{"enabled":false,"force":true,"key":"testService:testVersion:testGroup","tags":[{"name":"gray","match":[{"key":"env","value":{"exact":"gray"}}]}]}`, nil)
+ mockGovernanceConfig.EXPECT().GetConfig(GetRoutePath(util.BuildServiceKey("", "testService", "testVersion", "testGroup"), constant.TagRoute)).Return(`{"enabled":false,"force":true,"key":"testService:testVersion:testGroup","tags":[{"name":"gray","match":[{"key":"env","value":{"exact":"gray"}}]}]}`, nil)
config.Governance = mockGovernanceConfig
type args struct {
@@ -333,14 +310,9 @@ func TestRouteServiceImpl_DisableTagRoute(t *testing.T) {
func TestRouteServiceImpl_CreateConditionRoute(t *testing.T) {
ctrl := gomock.NewController(t)
- mockGovernanceConfig := config.NewMockGovernanceConfig(ctrl)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
mockGovernanceConfig.EXPECT().SetConfig(gomock.Any(), gomock.Any()).Return(nil)
- mockGovernanceConfig.EXPECT().GetConfig(getRoutePath(util.BuildServiceKey(model.Base{
- Application: "",
- Service: "testService",
- ServiceVersion: "testVersion",
- ServiceGroup: "testGroup",
- }), constant.ConditionRoute)).Return("", nil)
+ mockGovernanceConfig.EXPECT().GetConfig(GetRoutePath(util.BuildServiceKey("", "testService", "testVersion", "testGroup"), constant.ConditionRoute)).Return("", nil)
config.Governance = mockGovernanceConfig
type args struct {
@@ -384,14 +356,9 @@ func TestRouteServiceImpl_CreateConditionRoute(t *testing.T) {
func TestRouteServiceImpl_UpdateConditionRoute(t *testing.T) {
ctrl := gomock.NewController(t)
- mockGovernanceConfig := config.NewMockGovernanceConfig(ctrl)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
mockGovernanceConfig.EXPECT().SetConfig(gomock.Any(), gomock.Any()).Return(nil)
- mockGovernanceConfig.EXPECT().GetConfig(getRoutePath(util.BuildServiceKey(model.Base{
- Application: "",
- Service: "testService",
- ServiceVersion: "testVersion",
- ServiceGroup: "testGroup",
- }), constant.ConditionRoute)).Return(`{"enabled":true,"force":false,"runtime":true,"key":"testService:testVersion:testGroup","conditions":["method=getComment => region=Hangzhou"]}`, nil)
+ mockGovernanceConfig.EXPECT().GetConfig(GetRoutePath(util.BuildServiceKey("", "testService", "testVersion", "testGroup"), constant.ConditionRoute)).Return(`{"enabled":true,"force":false,"runtime":true,"key":"testService:testVersion:testGroup","conditions":["method=getComment => region=Hangzhou"]}`, nil)
config.Governance = mockGovernanceConfig
type args struct {
@@ -435,7 +402,7 @@ func TestRouteServiceImpl_UpdateConditionRoute(t *testing.T) {
func TestRouteServiceImpl_DeleteConditionRoute(t *testing.T) {
ctrl := gomock.NewController(t)
- mockGovernanceConfig := config.NewMockGovernanceConfig(ctrl)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
mockGovernanceConfig.EXPECT().DeleteConfig(gomock.Any()).Return(nil)
config.Governance = mockGovernanceConfig
@@ -469,13 +436,8 @@ func TestRouteServiceImpl_DeleteConditionRoute(t *testing.T) {
func TestRouteServiceImpl_FindConditionRouteById(t *testing.T) {
ctrl := gomock.NewController(t)
- mockGovernanceConfig := config.NewMockGovernanceConfig(ctrl)
- mockGovernanceConfig.EXPECT().GetConfig(getRoutePath(util.BuildServiceKey(model.Base{
- Application: "",
- Service: "testService",
- ServiceVersion: "testVersion",
- ServiceGroup: "testGroup",
- }), constant.ConditionRoute)).Return(`{"enabled":true,"force":true,"runtime":true,"key":"testService:testVersion:testGroup","conditions":["method=getComment => region=Hangzhou"]}`, nil)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
+ mockGovernanceConfig.EXPECT().GetConfig(GetRoutePath(util.BuildServiceKey("", "testService", "testVersion", "testGroup"), constant.ConditionRoute)).Return(`{"enabled":true,"force":true,"runtime":true,"key":"testService:testVersion:testGroup","conditions":["method=getComment => region=Hangzhou"]}`, nil)
config.Governance = mockGovernanceConfig
type args struct {
@@ -526,14 +488,9 @@ func TestRouteServiceImpl_FindConditionRouteById(t *testing.T) {
func TestRouteServiceImpl_EnableConditionRoute(t *testing.T) {
ctrl := gomock.NewController(t)
- mockGovernanceConfig := config.NewMockGovernanceConfig(ctrl)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
mockGovernanceConfig.EXPECT().SetConfig(gomock.Any(), gomock.Any()).Return(nil)
- mockGovernanceConfig.EXPECT().GetConfig(getRoutePath(util.BuildServiceKey(model.Base{
- Application: "",
- Service: "testService",
- ServiceVersion: "testVersion",
- ServiceGroup: "testGroup",
- }), constant.ConditionRoute)).Return(`{"enabled":false,"force":true,"runtime":true,"key":"testService:testVersion:testGroup","conditions":["method=getComment => region=Hangzhou"]}`, nil)
+ mockGovernanceConfig.EXPECT().GetConfig(GetRoutePath(util.BuildServiceKey("", "testService", "testVersion", "testGroup"), constant.ConditionRoute)).Return(`{"enabled":false,"force":true,"runtime":true,"key":"testService:testVersion:testGroup","conditions":["method=getComment => region=Hangzhou"]}`, nil)
config.Governance = mockGovernanceConfig
type args struct {
@@ -566,14 +523,9 @@ func TestRouteServiceImpl_EnableConditionRoute(t *testing.T) {
func TestRouteServiceImpl_DisableConditionRoute(t *testing.T) {
ctrl := gomock.NewController(t)
- mockGovernanceConfig := config.NewMockGovernanceConfig(ctrl)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
mockGovernanceConfig.EXPECT().SetConfig(gomock.Any(), gomock.Any()).Return(nil)
- mockGovernanceConfig.EXPECT().GetConfig(getRoutePath(util.BuildServiceKey(model.Base{
- Application: "",
- Service: "testService",
- ServiceVersion: "testVersion",
- ServiceGroup: "testGroup",
- }), constant.ConditionRoute)).Return(`{"enabled":true,"force":true,"runtime":true,"key":"testService:testVersion:testGroup","conditions":["method=getComment => region=Hangzhou"]}`, nil)
+ mockGovernanceConfig.EXPECT().GetConfig(GetRoutePath(util.BuildServiceKey("", "testService", "testVersion", "testGroup"), constant.ConditionRoute)).Return(`{"enabled":true,"force":true,"runtime":true,"key":"testService:testVersion:testGroup","conditions":["method=getComment => region=Hangzhou"]}`, nil)
config.Governance = mockGovernanceConfig
type args struct {
@@ -628,8 +580,8 @@ func TestRouteServiceImpl_getRoutePath(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- if got := getRoutePath(tt.args.key, tt.args.routeType); got != tt.want {
- t.Errorf("RouteServiceImpl.getRoutePath() = %v, want %v", got, tt.want)
+ if got := GetRoutePath(tt.args.key, tt.args.routeType); got != tt.want {
+ t.Errorf("RouteServiceImpl.GetRoutePath() = %v, want %v", got, tt.want)
}
})
}
diff --git a/pkg/admin/services/traffic/accesslog.go b/pkg/admin/services/traffic/accesslog.go
new file mode 100644
index 00000000..7360b125
--- /dev/null
+++ b/pkg/admin/services/traffic/accesslog.go
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+package traffic
+
+import (
+ "github.com/apache/dubbo-admin/pkg/admin/model"
+ "github.com/apache/dubbo-admin/pkg/admin/services"
+)
+
+type AccesslogService struct{}
+
+// CreateOrUpdate create or update timeout rule
+func (tm *AccesslogService) CreateOrUpdate(a *model.Accesslog) error {
+ key := services.GetOverridePath(a.Application)
+ newRule := a.ToRule()
+
+ err := createOrUpdateOverride(key, "provider", "accesslog", newRule)
+ return err
+}
+
+func (tm *AccesslogService) Delete(a *model.Accesslog) error {
+ key := services.GetOverridePath(a.Application)
+ err2 := removeFromOverride(key, "provider", "accesslog")
+ if err2 != nil {
+ return err2
+ }
+ return nil
+}
+
+func (tm *AccesslogService) Search(a *model.Accesslog) ([]*model.Accesslog, error) {
+ result := make([]*model.Accesslog, 0)
+
+ list, err := getRules(a.Application)
+ if err != nil {
+ return result, err
+ }
+
+ for _, v := range list {
+ accesslog := &model.Accesslog{
+ Application: a.Application,
+ }
+ alv, err2 := getValue(v, "provider", "accesslog")
+ if err2 != nil {
+ return result, err2
+ }
+ accesslog.Accesslog = alv.(string)
+ result = append(result, accesslog)
+ }
+
+ return result, nil
+}
diff --git a/pkg/admin/services/traffic/argument.go b/pkg/admin/services/traffic/argument.go
new file mode 100644
index 00000000..2b605e81
--- /dev/null
+++ b/pkg/admin/services/traffic/argument.go
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+package traffic
+
+import (
+ "strings"
+
+ "github.com/apache/dubbo-admin/pkg/admin/constant"
+ "github.com/apache/dubbo-admin/pkg/admin/model"
+ "github.com/apache/dubbo-admin/pkg/admin/services"
+ "github.com/apache/dubbo-admin/pkg/admin/util"
+ "gopkg.in/yaml.v2"
+)
+
+type ArgumentService struct{}
+
+// CreateOrUpdate create or update timeout rule
+func (tm *ArgumentService) CreateOrUpdate(a *model.Argument) error {
+ key := services.GetRoutePath(util.ColonSeparatedKey(a.Service, a.Group, a.Version), constant.ConditionRoute)
+ newRule := a.ToRule()
+
+ err := createOrUpdateCondition(key, newRule)
+ return err
+}
+
+func (tm *ArgumentService) Delete(a *model.Argument) error {
+ key := services.GetRoutePath(util.ColonSeparatedKey(a.Service, a.Group, a.Version), constant.ConditionRoute)
+ err2 := removeCondition(key, a.Rule)
+ if err2 != nil {
+ return err2
+ }
+ return nil
+}
+
+func (tm *ArgumentService) Search(a *model.Argument) ([]*model.Argument, error) {
+ result := make([]*model.Argument, 0)
+
+ var con string
+ if a.Service != "" {
+ con = util.ColonSeparatedKey(a.Service, a.Group, a.Version)
+ }
+
+ list, err := getRules(con)
+ if err != nil {
+ return result, err
+ }
+
+ for k, v := range list {
+ k, _ = strings.CutSuffix(k, constant.ConditionRuleSuffix)
+ split := strings.Split(k, ":")
+ argument := &model.Argument{
+ Service: split[0],
+ Group: split[1],
+ Version: split[2],
+ }
+
+ route := &model.ConditionRoute{}
+ err = yaml.Unmarshal([]byte(v), route)
+ if err != nil {
+ return result, err
+ }
+ for _, c := range route.Conditions {
+ // fixme, regex match
+ if strings.Contains(c, model.AdminIdentifier) {
+ argument.Rule = c
+ break
+ }
+ }
+
+ result = append(result, argument)
+ }
+
+ return result, nil
+}
diff --git a/pkg/admin/services/traffic/generic_rule_operation.go b/pkg/admin/services/traffic/generic_rule_operation.go
new file mode 100644
index 00000000..51050e5b
--- /dev/null
+++ b/pkg/admin/services/traffic/generic_rule_operation.go
@@ -0,0 +1,332 @@
+/*
+ * 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.
+ */
+
+package traffic
+
+import (
+ "github.com/apache/dubbo-admin/pkg/admin/config"
+ "github.com/apache/dubbo-admin/pkg/admin/model"
+ "github.com/apache/dubbo-admin/pkg/admin/services"
+ "github.com/apache/dubbo-admin/pkg/logger"
+ perrors "github.com/pkg/errors"
+ "gopkg.in/yaml.v2"
+)
+
+func removeFromOverride(key, side, param string) error {
+ oldRule, err := config.Governance.GetConfig(key)
+ if err != nil {
+ return err
+ }
+
+ if oldRule == "" {
+ return perrors.Errorf("Override rule does not exist!")
+ }
+
+ override := &model.Override{}
+ err = yaml.Unmarshal([]byte(oldRule), override)
+ if err != nil {
+ logger.Error("Unrecognized override rule!")
+ return err
+ }
+ for i, c := range override.Configs {
+ if c.Side == side && c.Parameters[param] != "" {
+ if len(c.Parameters) == 1 {
+ override.Configs = append(override.Configs[:i], override.Configs[i+1:]...)
+ } else {
+ delete(c.Parameters, param)
+ }
+ }
+ }
+
+ if len(override.Configs) == 0 {
+ err = config.Governance.DeleteConfig(key)
+ if err != nil {
+ logger.Error("Failed to delete override rule!")
+ return err
+ }
+ } else {
+ bytes, _ := yaml.Marshal(override)
+ err = config.Governance.SetConfig(key, string(bytes))
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func createOrUpdateOverride(key string, side, param string, newRule model.Override) error {
+ var mergedRule string
+ newRuleByte, _ := yaml.Marshal(newRule)
+
+ oldRule, err := config.Governance.GetConfig(key)
+ if err != nil {
+ if _, ok := err.(*config.RuleNotFound); ok {
+ logger.Infof("No existing configuration found, will create a new one directly!")
+ err := config.Governance.SetConfig(key, string(newRuleByte))
+ if err != nil {
+ logger.Errorf("Failed to save configuration status, please try again!", err)
+ return err
+ }
+ return nil
+ } else {
+ logger.Errorf("Failed to check previous configuration status, please try again!", err)
+ }
+ return err
+ }
+
+ if oldRule != "" {
+ //oJsonByte, err := yaml2.YAMLToJSON([]byte(oldRule))
+ //if err != nil {
+ // logger.Errorf("Failed to convert yaml to json!", err)
+ //}
+ //nJsonByte, err := yaml2.YAMLToJSON(newRuleByte)
+ //if err != nil {
+ // logger.Errorf("Failed to convert yaml to json!", err)
+ //}
+ //patch, err := jsonpatch.CreateMergePatch(nJsonByte, oJsonByte)
+ //fmt.Printf(string(patch))
+ //testConsumer := `[ { "op": "test", "path": "/side", "value": "consumer" } ]`
+ //testTimeout := `[ { "op": "test", "path": "/parameters/timeout", "value": null } ]`
+ //consumerPatch, _ := jsonpatch.DecodePatch(testConsumer)
+ //timeoutPatch, _ := jsonpatch.DecodePatch(testTimeout)
+
+ override := &model.Override{}
+ _ = yaml.Unmarshal([]byte(oldRule), override)
+
+ if param == "weight" {
+ mergeWeight(override, side, param, newRule)
+ } else {
+ mergeOverride(override, side, param, newRule)
+ }
+ mergedRuleByte, err := yaml.Marshal(override)
+ if err != nil {
+ return err
+ }
+ mergedRule = string(mergedRuleByte)
+ } else {
+ mergedRule = string(newRuleByte)
+ }
+
+ err = config.Governance.SetConfig(key, mergedRule)
+ if err != nil {
+ logger.Errorf("Failed to save timeout yaml rule!", err)
+ }
+ return nil
+}
+
+// mergeOverride applies to keys like 'timeout', 'accesslog' and 'mock'
+func mergeOverride(override *model.Override, side string, param string, newRule model.Override) {
+ updated := false
+ for _, c := range override.Configs {
+ if c.Side == side && c.Parameters[param] != "" {
+ c.Parameters[param] = newRule.Configs[0].Parameters[param]
+ c.Enabled = newRule.Enabled
+ updated = true
+ break
+ }
+ }
+ if !updated {
+ override.Configs = append(override.Configs, newRule.Configs[0])
+ }
+
+ override.Enabled = newRule.Enabled
+}
+
+// mergeWeight applies to key 'weight'
+func mergeWeight(override *model.Override, side string, param string, newRule model.Override) {
+ for i, c := range override.Configs {
+ if c.Side == side && c.Parameters[param] != "" {
+ // todo, add warning promote
+ override.Configs = append(override.Configs[:i], override.Configs[i+1:]...)
+ }
+ }
+ override.Configs = append(override.Configs, newRule.Configs...)
+
+ override.Enabled = newRule.Enabled
+}
+
+func getValue(rawRule, side, param string) (interface{}, error) {
+ override := &model.Override{}
+ err := yaml.Unmarshal([]byte(rawRule), override)
+ if err != nil {
+ return "", err
+ }
+ for _, c := range override.Configs {
+ if c.Side == side && c.Parameters[param] != "" {
+ return c.Parameters[param], nil
+ }
+ }
+
+ return "", nil
+}
+
+func getRules(con string) (map[string]string, error) {
+ list := make(map[string]string)
+ if con == "" {
+ rules, err := config.Governance.GetList("dubbo")
+ if err != nil {
+ return nil, err
+ }
+ list = rules
+ } else {
+ key := services.GetOverridePath(con)
+ rule, err := config.Governance.GetConfig(key)
+ if err != nil {
+ return nil, err
+ }
+ list[key] = rule
+ }
+ return list, nil
+}
+
+func createOrUpdateCondition(key string, newRule model.ConditionRoute) error {
+ var mergedRule string
+ newRuleByte, _ := yaml.Marshal(newRule)
+
+ oldRule, err := config.Governance.GetConfig(key)
+ if err != nil {
+ if _, ok := err.(*config.RuleNotFound); ok {
+ logger.Infof("No existing configuration found, will create a new one directly!")
+ err := config.Governance.SetConfig(key, string(newRuleByte))
+ if err != nil {
+ logger.Errorf("Failed to save configuration status, please try again!", err)
+ return err
+ }
+ return nil
+ } else {
+ logger.Errorf("Failed to check previous configuration status, please try again!", err)
+ }
+ return err
+ }
+
+ if oldRule != "" {
+ route := &model.ConditionRoute{}
+ _ = yaml.Unmarshal([]byte(oldRule), route)
+
+ exist := false
+ for _, c := range route.Conditions {
+ if c == newRule.Conditions[0] {
+ exist = true
+ }
+ }
+ if !exist {
+ route.Conditions = append(route.Conditions, newRule.Conditions[0])
+ }
+
+ route.Force = newRule.Force
+ route.Enabled = newRule.Enabled
+ route.Runtime = newRule.Runtime
+ mergedRuleByte, err := yaml.Marshal(route)
+ if err != nil {
+ return err
+ }
+ mergedRule = string(mergedRuleByte)
+ } else {
+ mergedRule = string(newRuleByte)
+ }
+
+ err = config.Governance.SetConfig(key, mergedRule)
+ if err != nil {
+ logger.Errorf("Failed to save region condition rule!", err)
+ }
+ return nil
+}
+
+func removeCondition(key, rule string) error {
+ oldRule, err := config.Governance.GetConfig(key)
+ if err != nil {
+ return err
+ }
+
+ if oldRule == "" {
+ return perrors.Errorf("Condition rule does not exist!")
+ }
+
+ route := &model.ConditionRoute{}
+ err = yaml.Unmarshal([]byte(oldRule), route)
+ if err != nil {
+ logger.Error("Unrecognized condition rule!")
+ return err
+ }
+ for i, c := range route.Conditions {
+ if c == rule {
+ route.Conditions = append(route.Conditions[:i], route.Conditions[i+1:]...)
+ break
+ }
+ }
+
+ if len(route.Conditions) == 0 {
+ err = config.Governance.DeleteConfig(key)
+ if err != nil {
+ logger.Error("Failed to delete override rule!")
+ return err
+ }
+ } else {
+ bytes, _ := yaml.Marshal(route)
+ err = config.Governance.SetConfig(key, string(bytes))
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func createOrUpdateTag(key string, newRule model.TagRoute) error {
+ var mergedRule string
+ newRuleByte, _ := yaml.Marshal(newRule)
+
+ oldRule, err := config.Governance.GetConfig(key)
+ if err != nil {
+ if _, ok := err.(*config.RuleNotFound); ok {
+ logger.Infof("No existing configuration found, will create a new one directly!")
+ err := config.Governance.SetConfig(key, string(newRuleByte))
+ if err != nil {
+ logger.Errorf("Failed to save configuration status, please try again!", err)
+ return err
+ }
+ return nil
+ } else {
+ logger.Errorf("Failed to check previous configuration status, please try again!", err)
+ }
+ return err
+ }
+
+ if oldRule != "" {
+ logger.Warn("Will override the existing tag rule with the new one!")
+ }
+ mergedRule = string(newRuleByte)
+
+ err = config.Governance.SetConfig(key, mergedRule)
+ if err != nil {
+ logger.Errorf("Failed to save region condition rule!", err)
+ }
+ return nil
+}
+
+func deleteTag(key string) error {
+ oldRule, err := config.Governance.GetConfig(key)
+ if err != nil {
+ return err
+ }
+
+ if oldRule == "" {
+ logger.Errorf("Tag rule does not exist!")
+ return nil
+ }
+
+ return config.Governance.DeleteConfig(key)
+}
diff --git a/pkg/admin/services/traffic/gray.go b/pkg/admin/services/traffic/gray.go
new file mode 100644
index 00000000..4e77424f
--- /dev/null
+++ b/pkg/admin/services/traffic/gray.go
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+package traffic
+
+import (
+ "github.com/apache/dubbo-admin/pkg/admin/constant"
+ "github.com/apache/dubbo-admin/pkg/admin/model"
+ "github.com/apache/dubbo-admin/pkg/admin/services"
+ "gopkg.in/yaml.v2"
+)
+
+type GrayService struct{}
+
+// CreateOrUpdate create or update timeout rule
+func (tm *GrayService) CreateOrUpdate(g *model.Gray) error {
+ key := services.GetRoutePath(g.Application, constant.TagRuleSuffix)
+ newRule := g.ToRule()
+
+ err := createOrUpdateTag(key, newRule)
+ return err
+}
+
+func (tm *GrayService) Delete(g *model.Gray) error {
+ key := services.GetRoutePath(g.Application, constant.TagRuleSuffix)
+ err2 := deleteTag(key)
+ if err2 != nil {
+ return err2
+ }
+ return nil
+}
+
+func (tm *GrayService) Search(g *model.Gray) ([]*model.Gray, error) {
+ result := make([]*model.Gray, 0)
+
+ list, err := getRules(g.Application)
+ if err != nil {
+ return result, err
+ }
+
+ for _, v := range list {
+ gray := &model.Gray{
+ Application: g.Application,
+ }
+
+ route := &model.TagRoute{}
+ err = yaml.Unmarshal([]byte(v), route)
+ if err != nil {
+ return result, err
+ }
+ gray.Tags = route.Tags
+ result = append(result, gray)
+ }
+
+ return result, nil
+}
diff --git a/pkg/admin/services/traffic/mock.go b/pkg/admin/services/traffic/mock.go
new file mode 100644
index 00000000..a7dc5069
--- /dev/null
+++ b/pkg/admin/services/traffic/mock.go
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+package traffic
+
+import (
+ "strings"
+
+ "github.com/apache/dubbo-admin/pkg/admin/constant"
+ "github.com/apache/dubbo-admin/pkg/admin/model"
+ "github.com/apache/dubbo-admin/pkg/admin/services"
+ "github.com/apache/dubbo-admin/pkg/admin/util"
+)
+
+type MockService struct{}
+
+// CreateOrUpdate create or update timeout rule
+func (tm *MockService) CreateOrUpdate(m *model.Mock) error {
+ key := services.GetOverridePath(util.ColonSeparatedKey(m.Service, m.Group, m.Version))
+ newRule := m.ToRule()
+
+ err := createOrUpdateOverride(key, "consumer", "mock", newRule)
+ return err
+}
+
+func (tm *MockService) Delete(m *model.Mock) error {
+ key := services.GetOverridePath(util.ColonSeparatedKey(m.Service, m.Group, m.Version))
+ err2 := removeFromOverride(key, "consumer", "mock")
+ if err2 != nil {
+ return err2
+ }
+ return nil
+}
+
+func (tm *MockService) Search(m *model.Mock) ([]*model.Mock, error) {
+ result := make([]*model.Mock, 0)
+
+ var con string
+ if m.Service != "" {
+ con = util.ColonSeparatedKey(m.Service, m.Group, m.Version)
+ }
+ list, err := getRules(con)
+ if err != nil {
+ return result, err
+ }
+
+ for k, v := range list {
+ k, _ = strings.CutSuffix(k, constant.ConfiguratorRuleSuffix)
+ split := strings.Split(k, ":")
+ mock := &model.Mock{
+ Service: split[0],
+ Group: split[1],
+ Version: split[2],
+ }
+ mv, err2 := getValue(v, "consumer", "mock")
+ if err2 != nil {
+ return result, err2
+ }
+ mock.Mock = mv.(string)
+ result = append(result, mock)
+ }
+
+ return result, nil
+}
diff --git a/pkg/admin/services/traffic/region.go b/pkg/admin/services/traffic/region.go
new file mode 100644
index 00000000..d2ee324a
--- /dev/null
+++ b/pkg/admin/services/traffic/region.go
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+package traffic
+
+import (
+ "strings"
+
+ "github.com/apache/dubbo-admin/pkg/admin/constant"
+ "github.com/apache/dubbo-admin/pkg/admin/model"
+ "github.com/apache/dubbo-admin/pkg/admin/services"
+ "github.com/apache/dubbo-admin/pkg/admin/util"
+ "gopkg.in/yaml.v2"
+)
+
+type RegionService struct{}
+
+// CreateOrUpdate create or update timeout rule
+func (tm *RegionService) CreateOrUpdate(r *model.Region) error {
+ key := services.GetRoutePath(util.ColonSeparatedKey(r.Service, r.Group, r.Version), constant.ConditionRoute)
+ newRule := r.ToRule()
+
+ err := createOrUpdateCondition(key, newRule)
+ return err
+}
+
+func (tm *RegionService) Delete(r *model.Region) error {
+ key := services.GetRoutePath(util.ColonSeparatedKey(r.Service, r.Group, r.Version), constant.ConditionRoute)
+ err2 := removeCondition(key, r.Rule)
+ if err2 != nil {
+ return err2
+ }
+ return nil
+}
+
+func (tm *RegionService) Search(r *model.Region) ([]*model.Region, error) {
+ result := make([]*model.Region, 0)
+
+ var con string
+ if r.Service != "" {
+ con = util.ColonSeparatedKey(r.Service, r.Group, r.Version)
+ }
+
+ list, err := getRules(con)
+ if err != nil {
+ return result, err
+ }
+
+ for k, v := range list {
+ k, _ = strings.CutSuffix(k, constant.ConditionRuleSuffix)
+ split := strings.Split(k, ":")
+ region := &model.Region{
+ Service: split[0],
+ Group: split[1],
+ Version: split[2],
+ }
+
+ route := &model.ConditionRoute{}
+ err = yaml.Unmarshal([]byte(v), route)
+ if err != nil {
+ return result, err
+ }
+ for _, c := range route.Conditions {
+ // fixme, regex match
+ if strings.Contains(c, model.AdminIdentifier) {
+ region.Rule = c
+ break
+ }
+ }
+
+ result = append(result, region)
+ }
+
+ return result, nil
+}
diff --git a/pkg/admin/services/traffic/retry.go b/pkg/admin/services/traffic/retry.go
new file mode 100644
index 00000000..0909f6ee
--- /dev/null
+++ b/pkg/admin/services/traffic/retry.go
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+package traffic
+
+import (
+ "strings"
+
+ "github.com/apache/dubbo-admin/pkg/admin/constant"
+ "github.com/apache/dubbo-admin/pkg/admin/model"
+ "github.com/apache/dubbo-admin/pkg/admin/services"
+ "github.com/apache/dubbo-admin/pkg/admin/util"
+)
+
+type RetryService struct{}
+
+// CreateOrUpdate create or update timeout rule
+func (tm *RetryService) CreateOrUpdate(r *model.Retry) error {
+ key := services.GetOverridePath(util.ColonSeparatedKey(r.Service, r.Group, r.Version))
+ newRule := r.ToRule()
+
+ err := createOrUpdateOverride(key, "consumer", "retries", newRule)
+ return err
+}
+
+func (tm *RetryService) Delete(r *model.Retry) error {
+ key := services.GetOverridePath(util.ColonSeparatedKey(r.Service, r.Group, r.Version))
+ err2 := removeFromOverride(key, "consumer", "retries")
+ if err2 != nil {
+ return err2
+ }
+ return nil
+}
+
+func (tm *RetryService) Search(r *model.Retry) ([]*model.Retry, error) {
+ result := make([]*model.Retry, 0)
+
+ var con string
+ if r.Service != "" {
+ con = util.ColonSeparatedKey(r.Service, r.Group, r.Version)
+ }
+
+ list, err := getRules(con)
+ if err != nil {
+ return result, err
+ }
+
+ for k, v := range list {
+ k, _ = strings.CutSuffix(k, constant.ConfiguratorRuleSuffix)
+ split := strings.Split(k, ":")
+ retry := &model.Retry{
+ Service: split[0],
+ Group: split[1],
+ Version: split[2],
+ }
+ rv, err2 := getValue(v, "consumer", "retries")
+ if err2 != nil {
+ return result, err2
+ }
+ retry.Retry = rv.(int)
+ result = append(result, retry)
+ }
+
+ return result, nil
+}
diff --git a/pkg/admin/services/traffic/timeout.go b/pkg/admin/services/traffic/timeout.go
new file mode 100644
index 00000000..eeca1ef4
--- /dev/null
+++ b/pkg/admin/services/traffic/timeout.go
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+package traffic
+
+import (
+ "strings"
+
+ "github.com/apache/dubbo-admin/pkg/admin/constant"
+ "github.com/apache/dubbo-admin/pkg/admin/model"
+ "github.com/apache/dubbo-admin/pkg/admin/services"
+ "github.com/apache/dubbo-admin/pkg/admin/util"
+)
+
+type TimeoutService struct{}
+
+// CreateOrUpdate create or update timeout rule
+func (tm *TimeoutService) CreateOrUpdate(t *model.Timeout) error {
+ key := services.GetOverridePath(util.ColonSeparatedKey(t.Service, t.Group, t.Version))
+ newRule := t.ToRule()
+
+ err := createOrUpdateOverride(key, "consumer", "timeout", newRule)
+ return err
+}
+
+func (tm *TimeoutService) Delete(t *model.Timeout) error {
+ key := services.GetOverridePath(util.ColonSeparatedKey(t.Service, t.Group, t.Version))
+ err2 := removeFromOverride(key, "consumer", "timeout")
+ if err2 != nil {
+ return err2
+ }
+ return nil
+}
+
+func (tm *TimeoutService) Search(t *model.Timeout) ([]*model.Timeout, error) {
+ result := make([]*model.Timeout, 0)
+
+ var con string
+ if t.Service != "" {
+ con = util.ColonSeparatedKey(t.Service, t.Group, t.Version)
+ }
+
+ list, err := getRules(con)
+ if err != nil {
+ return result, err
+ }
+
+ for k, v := range list {
+ k, _ = strings.CutSuffix(k, constant.ConfiguratorRuleSuffix)
+ split := strings.Split(k, ":")
+ t := &model.Timeout{
+ Service: split[0],
+ Group: split[1],
+ Version: split[2],
+ }
+ tv, err2 := getValue(v, "consumer", "timeout")
+ if err2 != nil {
+ return result, err2
+ }
+ t.Timeout = tv.(int)
+ result = append(result, t)
+ }
+
+ return result, nil
+}
diff --git a/pkg/admin/services/traffic/timeout_test.go b/pkg/admin/services/traffic/timeout_test.go
new file mode 100644
index 00000000..33957a6d
--- /dev/null
+++ b/pkg/admin/services/traffic/timeout_test.go
@@ -0,0 +1,313 @@
+/*
+ * 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.
+ */
+
+package traffic
+
+import (
+ "fmt"
+ "reflect"
+ "testing"
+
+ "github.com/apache/dubbo-admin/pkg/admin/config"
+ "github.com/apache/dubbo-admin/pkg/admin/config/mock_config"
+ "github.com/apache/dubbo-admin/pkg/admin/model"
+ jsonpatch "github.com/evanphx/json-patch/v5"
+ "github.com/golang/mock/gomock"
+
+ "sigs.k8s.io/yaml"
+)
+
+func TestCreateTimeout(t *testing.T) {
+ var capturedRule string
+
+ ctrl := gomock.NewController(t)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
+ mockGovernanceConfig.EXPECT().SetConfig(gomock.Any(), gomock.Any()).Do(func(key, rule string) {
+ capturedRule = rule
+ })
+ mockGovernanceConfig.EXPECT().GetConfig(gomock.Any()).Return("", nil)
+ config.Governance = mockGovernanceConfig
+
+ tests := []struct {
+ name string
+ args *model.Timeout
+ want string
+ wantErr bool
+ }{
+ {
+ name: "create_timeout",
+ args: &model.Timeout{
+ Service: "DemoService",
+ Group: "",
+ Version: "",
+ Timeout: 5000,
+ },
+ want: "configVersion: v3.0\nscope: service\nenabled: true\nkey: DemoService\nconfigs:\n - side: consumer\n enabled: true\n parameters:\n timeout: 5000",
+ wantErr: false,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ timeoutSvc := &TimeoutService{}
+
+ if err := timeoutSvc.CreateOrUpdate(tt.args); err != nil && !tt.wantErr {
+ t.Errorf("TimeoutService.CreateOrUpdate() error = %v, wantErr %v", err, tt.wantErr)
+ }
+
+ actualJson, _ := yaml.YAMLToJSON([]byte(capturedRule))
+ wantedJson, _ := yaml.YAMLToJSON([]byte(tt.want))
+ if !jsonpatch.Equal(actualJson, wantedJson) {
+ t.Errorf("TimeoutService.CreateOrUpdate() error \n, expected:\n %v \n, got:\n %v \n", tt.want, capturedRule)
+ }
+ })
+ }
+}
+
+func TestUpdateTimeout(t *testing.T) {
+ var capturedRule string
+
+ tests := []struct {
+ name string
+ args *model.Timeout
+ want string
+ existingRule string
+ wantErr bool
+ }{
+ {
+ name: "update_timeout_multi_configs",
+ args: &model.Timeout{
+ Service: "DemoService",
+ Group: "",
+ Version: "",
+ Timeout: 6000,
+ },
+ existingRule: "configVersion: v3.0\nscope: service\nenabled: true\nkey: DemoService\nconfigs:\n - side: consumer\n enabled: true\n parameters:\n timeout: 5000\n test: \"value\"\n - side: provider\n enabled: true\n parameters:\n accesslog: true",
+ want: "configVersion: v3.0\nscope: service\nenabled: true\nkey: DemoService\nconfigs:\n - side: consumer\n enabled: true\n parameters:\n timeout: 6000\n test: \"value\"\n - side: provider\n enabled: true\n parameters:\n accesslog: true",
+ wantErr: false,
+ },
+ {
+ name: "update_timeout_single_config_single_item",
+ args: &model.Timeout{
+ Service: "DemoService",
+ Group: "",
+ Version: "",
+ Timeout: 6000,
+ },
+ existingRule: "configVersion: v3.0\nscope: service\nenabled: true\nkey: DemoService\nconfigs:\n - side: consumer\n enabled: true\n parameters:\n timeout: 5000",
+ want: "configVersion: v3.0\nscope: service\nenabled: true\nkey: DemoService\nconfigs:\n - side: consumer\n enabled: true\n parameters:\n timeout: 6000",
+ wantErr: false,
+ },
+ {
+ name: "update_timeout_single_config_multi_items",
+ args: &model.Timeout{
+ Service: "DemoService",
+ Group: "",
+ Version: "",
+ Timeout: 6000,
+ },
+ existingRule: "configVersion: v3.0\nscope: service\nenabled: true\nkey: DemoService\nconfigs:\n - side: consumer\n enabled: true\n parameters:\n timeout: 5000\n test: \"value\"",
+ want: "configVersion: v3.0\nscope: service\nenabled: true\nkey: DemoService\nconfigs:\n - side: consumer\n enabled: true\n parameters:\n timeout: 6000\n test: \"value\"",
+ wantErr: false,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ timeoutSvc := &TimeoutService{}
+
+ ctrl := gomock.NewController(t)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
+ mockGovernanceConfig.EXPECT().SetConfig(gomock.Any(), gomock.Any()).Do(func(key, rule string) {
+ capturedRule = rule
+ })
+ mockGovernanceConfig.EXPECT().GetConfig(gomock.Any()).Return(tt.existingRule, nil)
+ config.Governance = mockGovernanceConfig
+
+ if err := timeoutSvc.CreateOrUpdate(tt.args); err != nil && !tt.wantErr {
+ t.Errorf("TimeoutService.CreateOrUpdate() error = %v, wantErr %v", err, tt.wantErr)
+ }
+
+ actualJson, _ := yaml.YAMLToJSON([]byte(capturedRule))
+ wantedJson, _ := yaml.YAMLToJSON([]byte(tt.want))
+ if !jsonpatch.Equal(actualJson, wantedJson) {
+ t.Errorf("TimeoutService.CreateOrUpdate() error \n, expected:\n %v \n, got:\n %v \n", tt.want, capturedRule)
+ }
+ })
+ }
+}
+
+func TestDeleteTimeout(t *testing.T) {
+ var capturedRule string
+
+ tests := []struct {
+ name string
+ args *model.Timeout
+ want string
+ existingRule string
+ wantDelete bool
+ wantErr bool
+ }{
+ {
+ name: "delete_timeout_multi_configs",
+ args: &model.Timeout{
+ Service: "DemoService",
+ Group: "",
+ Version: "",
+ Timeout: 5000,
+ },
+ existingRule: "configVersion: v3.0\nscope: service\nenabled: true\nkey: DemoService\nconfigs:\n - side: consumer\n enabled: true\n parameters:\n timeout: 5000\n test: \"value\"\n - side: provider\n enabled: true\n parameters:\n accesslog: true",
+ want: "configVersion: v3.0\nscope: service\nenabled: true\nkey: DemoService\nconfigs:\n - side: consumer\n enabled: true\n parameters:\n test: \"value\"\n - side: provider\n enabled: true\n parameters:\n accesslog: true",
+ wantErr: false,
+ },
+ {
+ name: "delete_timeout_single_config_single_item",
+ args: &model.Timeout{
+ Service: "DemoService",
+ Group: "",
+ Version: "",
+ Timeout: 6000,
+ },
+ existingRule: "configVersion: v3.0\nscope: service\nenabled: true\nkey: DemoService\nconfigs:\n - side: consumer\n enabled: true\n parameters:\n timeout: 5000",
+ want: "",
+ wantDelete: true,
+ wantErr: false,
+ },
+ {
+ name: "delete_timeout_single_config_multi_items",
+ args: &model.Timeout{
+ Service: "DemoService",
+ Group: "",
+ Version: "",
+ Timeout: 6000,
+ },
+ existingRule: "configVersion: v3.0\nscope: service\nenabled: true\nkey: DemoService\nconfigs:\n - side: consumer\n enabled: true\n parameters:\n timeout: 5000\n test: \"value\"",
+ want: "configVersion: v3.0\nscope: service\nenabled: true\nkey: DemoService\nconfigs:\n - side: consumer\n enabled: true\n parameters:\n test: \"value\"",
+ wantErr: false,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ timeoutSvc := &TimeoutService{}
+
+ ctrl := gomock.NewController(t)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
+ if tt.wantDelete {
+ mockGovernanceConfig.EXPECT().DeleteConfig(gomock.Any()).Times(1)
+ } else {
+ mockGovernanceConfig.EXPECT().SetConfig(gomock.Any(), gomock.Any()).Do(func(key, rule string) {
+ capturedRule = rule
+ })
+ }
+ mockGovernanceConfig.EXPECT().GetConfig(gomock.Any()).Return(tt.existingRule, nil)
+ config.Governance = mockGovernanceConfig
+
+ if err := timeoutSvc.Delete(tt.args); err != nil && !tt.wantErr {
+ t.Errorf("TimeoutService.Delete() error = %v, wantErr %v", err, tt.wantErr)
+ }
+
+ if !tt.wantDelete {
+ actualJson, _ := yaml.YAMLToJSON([]byte(capturedRule))
+ wantedJson, _ := yaml.YAMLToJSON([]byte(tt.want))
+ if !jsonpatch.Equal(actualJson, wantedJson) {
+ t.Errorf("TimeoutService.CreateOrUpdate() error \n, expected:\n %v \n, got:\n %v \n", tt.want, capturedRule)
+ }
+ }
+ })
+ }
+}
+
+func TestSearchTimeout(t *testing.T) {
+ tests := []struct {
+ name string
+ args *model.Timeout
+ want []*model.Timeout
+ existingRule string
+ wantErr bool
+ }{
+ {
+ name: "search_timeout_multi_configs",
+ args: &model.Timeout{
+ Service: "DemoService",
+ Group: "",
+ Version: "",
+ Timeout: 5000,
+ },
+ existingRule: "configVersion: v3.0\nscope: service\nenabled: true\nkey: DemoService\nconfigs:\n - side: consumer\n enabled: true\n parameters:\n timeout: 5000\n test: \"value\"\n - side: provider\n enabled: true\n parameters:\n accesslog: true",
+ want: []*model.Timeout{{
+ Service: "DemoService",
+ Timeout: 5000,
+ }},
+ wantErr: false,
+ },
+ {
+ name: "search_timeout_single_config_single_item",
+ args: &model.Timeout{
+ Service: "DemoService",
+ Group: "",
+ Version: "",
+ Timeout: 6000,
+ },
+ existingRule: "configVersion: v3.0\nscope: service\nenabled: true\nkey: DemoService\nconfigs:\n - side: consumer\n enabled: true\n parameters:\n timeout: 5000",
+ want: []*model.Timeout{{
+ Service: "DemoService",
+ Timeout: 5000,
+ }},
+ wantErr: false,
+ },
+ {
+ name: "search_timeout_single_config_multi_items",
+ args: &model.Timeout{
+ Service: "DemoService",
+ Group: "",
+ Version: "",
+ Timeout: 6000,
+ },
+ existingRule: "configVersion: v3.0\nscope: service\nenabled: true\nkey: DemoService\nconfigs:\n - side: consumer\n enabled: true\n parameters:\n timeout: 5000\n test: \"value\"",
+ want: []*model.Timeout{{
+ Service: "DemoService",
+ Timeout: 5000,
+ }},
+ wantErr: false,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ timeoutSvc := &TimeoutService{}
+
+ var capturedRule string
+ ctrl := gomock.NewController(t)
+ mockGovernanceConfig := mock_config.NewMockGovernanceConfig(ctrl)
+ mockGovernanceConfig.EXPECT().GetConfig(gomock.Any()).DoAndReturn(func(key string) (string, error) {
+ capturedRule = tt.existingRule
+ return tt.existingRule, nil
+ })
+ fmt.Print(capturedRule)
+ config.Governance = mockGovernanceConfig
+
+ if timeouts, err := timeoutSvc.Search(tt.args); err != nil && !tt.wantErr {
+ t.Errorf("TimeoutService.Search() error = %v, wantErr %v", err, tt.wantErr)
+ } else {
+ if !reflect.DeepEqual(timeouts, tt.want) {
+ t.Errorf("TimeoutService.Search() got = %v, want %v", timeouts, tt.want)
+ }
+ }
+ })
+ }
+}
diff --git a/pkg/admin/services/traffic/weight.go b/pkg/admin/services/traffic/weight.go
new file mode 100644
index 00000000..e2f933fc
--- /dev/null
+++ b/pkg/admin/services/traffic/weight.go
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+package traffic
+
+import (
+ "strings"
+
+ "github.com/apache/dubbo-admin/pkg/admin/constant"
+ "github.com/apache/dubbo-admin/pkg/admin/model"
+ "github.com/apache/dubbo-admin/pkg/admin/services"
+ "github.com/apache/dubbo-admin/pkg/admin/util"
+ "gopkg.in/yaml.v2"
+)
+
+type WeightService struct{}
+
+// CreateOrUpdate create or update timeout rule
+func (tm *WeightService) CreateOrUpdate(p *model.Percentage) error {
+ key := services.GetOverridePath(util.ColonSeparatedKey(p.Service, p.Group, p.Version))
+ newRule := p.ToRule()
+
+ err := createOrUpdateOverride(key, "provider", "weight", newRule)
+ return err
+}
+
+func (tm *WeightService) Delete(p *model.Percentage) error {
+ key := services.GetOverridePath(util.ColonSeparatedKey(p.Service, p.Group, p.Version))
+ err := removeFromOverride(key, "provider", "weight")
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (tm *WeightService) Search(p *model.Percentage) ([]*model.Percentage, error) {
+ result := make([]*model.Percentage, 0)
+
+ var con string
+ if p.Service != "" {
+ con = util.ColonSeparatedKey(p.Service, p.Group, p.Version)
+ }
+
+ list, err := getRules(con)
+ if err != nil {
+ return result, err
+ }
+
+ for k, v := range list {
+ k, _ = strings.CutSuffix(k, constant.ConfiguratorRuleSuffix)
+ split := strings.Split(k, ":")
+ percentage := &model.Percentage{
+ Service: split[0],
+ Group: split[1],
+ Version: split[2],
+ Weights: make([]model.Weight, 0),
+ }
+
+ override := &model.Override{}
+ err = yaml.Unmarshal([]byte(v), override)
+ if err != nil {
+ return result, err
+ }
+ for _, c := range override.Configs {
+ if c.Side == "provider" && c.Parameters["weight"] != "" {
+ percentage.Weights = append(percentage.Weights, model.Weight{
+ Weight: c.Parameters["weight"].(int),
+ Match: c.Match,
+ })
+ }
+ }
+
+ result = append(result, percentage)
+ }
+
+ return result, nil
+}
diff --git a/pkg/admin/util/base_service_metadata.go b/pkg/admin/util/base_service_metadata.go
index 3bfb4f3f..959ee17a 100644
--- a/pkg/admin/util/base_service_metadata.go
+++ b/pkg/admin/util/base_service_metadata.go
@@ -18,14 +18,53 @@
package util
import (
+ "bytes"
+ "strings"
+
"github.com/apache/dubbo-admin/pkg/admin/constant"
- "github.com/apache/dubbo-admin/pkg/admin/model"
)
-func BuildServiceKey(baseDto model.Base) string {
- if baseDto.Application != "" {
- return baseDto.Application
+func BuildServiceKey(app, service, version, group string) string {
+ if app != "" {
+ return app
}
// id format: "${class}:${version}:${group}"
- return baseDto.Service + constant.Colon + baseDto.ServiceVersion + constant.Colon + baseDto.ServiceGroup
+ return service + constant.Colon + version + constant.Colon + group
+}
+
+func ServiceKey(intf string, group string, version string) string {
+ if intf == "" {
+ return ""
+ }
+ buf := &bytes.Buffer{}
+ if group != "" {
+ buf.WriteString(group)
+ buf.WriteString("/")
+ }
+
+ buf.WriteString(intf)
+
+ if version != "" && version != "0.0.0" {
+ buf.WriteString(":")
+ buf.WriteString(version)
+ }
+
+ return buf.String()
+}
+
+func ColonSeparatedKey(intf string, group string, version string) string {
+ if intf == "" {
+ return ""
+ }
+ var buf strings.Builder
+ buf.WriteString(intf)
+ buf.WriteString(":")
+ if version != "" && version != "0.0.0" {
+ buf.WriteString(version)
+ }
+ buf.WriteString(":")
+ if group != "" {
+ buf.WriteString(group)
+ }
+ return buf.String()
}