From 3f89dea5a9baef66598c30061c2bef974c803fc2 Mon Sep 17 00:00:00 2001 From: Gaius Date: Fri, 19 Nov 2021 10:58:14 +0800 Subject: [PATCH] feat: add security rule (#806) Signed-off-by: Gaius --- api/manager/docs.go | 380 +++++++++++++++++++++- api/manager/swagger.json | 380 +++++++++++++++++++++- api/manager/swagger.yaml | 253 +++++++++++++- docs/en/api-reference/api-reference.md | 341 ++++++++++++++++++- docs/zh-CN/api-reference/api-reference.md | 341 ++++++++++++++++++- manager/database/database.go | 1 + manager/handlers/cdn_cluster.go | 22 -- manager/handlers/scheduler_cluster.go | 22 -- manager/handlers/security_group.go | 56 ++++ manager/handlers/security_rule.go | 171 ++++++++++ manager/model/security_group.go | 3 +- manager/model/security_rule.go | 26 ++ manager/router/router.go | 10 + manager/searcher/searcher.go | 143 +++++--- manager/searcher/searcher_test.go | 258 +++++++-------- manager/service/cdn_cluster.go | 53 --- manager/service/scheduler_cluster.go | 90 ----- manager/service/security_group.go | 55 +++- manager/service/security_rule.go | 87 +++++ manager/service/service.go | 12 +- manager/service/service_grpc.go | 20 +- manager/types/cdn_cluster.go | 14 +- manager/types/scheduler_cluster.go | 30 +- manager/types/security_group.go | 20 +- manager/types/security_rule.go | 43 +++ 25 files changed, 2366 insertions(+), 465 deletions(-) create mode 100644 manager/handlers/security_rule.go create mode 100644 manager/model/security_rule.go create mode 100644 manager/service/security_rule.go create mode 100644 manager/types/security_rule.go diff --git a/api/manager/docs.go b/api/manager/docs.go index 3a8c11197..6a70588e7 100644 --- a/api/manager/docs.go +++ b/api/manager/docs.go @@ -2342,6 +2342,279 @@ var doc = `{ } } }, + "/security-groups/{id}/security-rules/{security_rule_id}": { + "put": { + "description": "Add SecurityRule to SecurityGroup", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SecurityGroup" + ], + "summary": "Add SecurityRule to SecurityGroup", + "parameters": [ + { + "type": "string", + "description": "id", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "security rule id", + "name": "security_rule_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "" + }, + "400": { + "description": "" + }, + "404": { + "description": "" + }, + "500": { + "description": "" + } + } + }, + "delete": { + "description": "Destroy SecurityRule to SecurityGroup", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SecurityGroup" + ], + "summary": "Destroy SecurityRule to SecurityGroup", + "parameters": [ + { + "type": "string", + "description": "id", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "security rule id", + "name": "security_rule_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "" + }, + "400": { + "description": "" + }, + "404": { + "description": "" + }, + "500": { + "description": "" + } + } + } + }, + "/security-rules": { + "get": { + "description": "Get SecurityRules", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SecurityRule" + ], + "summary": "Get SecurityRules", + "parameters": [ + { + "type": "integer", + "default": 0, + "description": "current page", + "name": "page", + "in": "query", + "required": true + }, + { + "maximum": 50, + "minimum": 2, + "type": "integer", + "default": 10, + "description": "return max item count, default 10, max 50", + "name": "per_page", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/model.SecurityRule" + } + } + }, + "400": { + "description": "" + }, + "404": { + "description": "" + }, + "500": { + "description": "" + } + } + }, + "post": { + "description": "create by json config", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SecurityRule" + ], + "summary": "Create SecurityRule", + "parameters": [ + { + "description": "SecurityRule", + "name": "SecurityRule", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.CreateSecurityRuleRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.SecurityRule" + } + }, + "400": { + "description": "" + }, + "404": { + "description": "" + }, + "500": { + "description": "" + } + } + } + }, + "/security-rules/{id}": { + "get": { + "description": "Get SecurityRule by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SecurityRule" + ], + "summary": "Get SecurityRule", + "parameters": [ + { + "type": "string", + "description": "id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.SecurityRule" + } + }, + "400": { + "description": "" + }, + "404": { + "description": "" + }, + "500": { + "description": "" + } + } + }, + "patch": { + "description": "Update by json config", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SecurityRule" + ], + "summary": "Update SecurityRule", + "parameters": [ + { + "type": "string", + "description": "id", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "SecurityRule", + "name": "SecurityRule", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.UpdateSecurityRuleRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.SecurityRule" + } + }, + "400": { + "description": "" + }, + "404": { + "description": "" + }, + "500": { + "description": "" + } + } + } + }, "/securityGroups/{id}": { "delete": { "description": "Destroy by id", @@ -2380,6 +2653,44 @@ var doc = `{ } } }, + "/securityRules/{id}": { + "delete": { + "description": "Destroy by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SecurityRule" + ], + "summary": "Destroy SecurityRule", + "parameters": [ + { + "type": "string", + "description": "id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "" + }, + "400": { + "description": "" + }, + "404": { + "description": "" + }, + "500": { + "description": "" + } + } + } + }, "/user/signin/{name}": { "get": { "description": "oauth signin by json config", @@ -3026,6 +3337,32 @@ var doc = `{ } }, "model.SecurityGroup": { + "type": "object", + "properties": { + "bio": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "security_rules": { + "type": "array", + "items": { + "$ref": "#/definitions/model.SecurityRule" + } + }, + "updated_at": { + "type": "string" + } + } + }, + "model.SecurityRule": { "type": "object", "properties": { "bio": { @@ -3046,6 +3383,12 @@ var doc = `{ "proxy_domain": { "type": "string" }, + "security_groups": { + "type": "array", + "items": { + "$ref": "#/definitions/model.SecurityGroup" + } + }, "updated_at": { "type": "string" } @@ -3142,9 +3485,6 @@ var doc = `{ }, "name": { "type": "string" - }, - "security_group_domain": { - "type": "string" } } }, @@ -3312,9 +3652,6 @@ var doc = `{ }, "scopes": { "$ref": "#/definitions/types.SchedulerClusterScopes" - }, - "security_group_domain": { - "type": "string" } } }, @@ -3356,6 +3693,20 @@ var doc = `{ } }, "types.CreateSecurityGroupRequest": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "bio": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "types.CreateSecurityRuleRequest": { "type": "object", "required": [ "domain", @@ -3511,9 +3862,6 @@ var doc = `{ }, "name": { "type": "string" - }, - "security_group_domain": { - "type": "string" } } }, @@ -3611,9 +3959,6 @@ var doc = `{ }, "scopes": { "$ref": "#/definitions/types.SchedulerClusterScopes" - }, - "security_group_domain": { - "type": "string" } } }, @@ -3648,6 +3993,17 @@ var doc = `{ } }, "types.UpdateSecurityGroupRequest": { + "type": "object", + "properties": { + "bio": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "types.UpdateSecurityRuleRequest": { "type": "object", "properties": { "bio": { diff --git a/api/manager/swagger.json b/api/manager/swagger.json index 9e55e8f5d..c885d652e 100644 --- a/api/manager/swagger.json +++ b/api/manager/swagger.json @@ -2328,6 +2328,279 @@ } } }, + "/security-groups/{id}/security-rules/{security_rule_id}": { + "put": { + "description": "Add SecurityRule to SecurityGroup", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SecurityGroup" + ], + "summary": "Add SecurityRule to SecurityGroup", + "parameters": [ + { + "type": "string", + "description": "id", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "security rule id", + "name": "security_rule_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "" + }, + "400": { + "description": "" + }, + "404": { + "description": "" + }, + "500": { + "description": "" + } + } + }, + "delete": { + "description": "Destroy SecurityRule to SecurityGroup", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SecurityGroup" + ], + "summary": "Destroy SecurityRule to SecurityGroup", + "parameters": [ + { + "type": "string", + "description": "id", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "security rule id", + "name": "security_rule_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "" + }, + "400": { + "description": "" + }, + "404": { + "description": "" + }, + "500": { + "description": "" + } + } + } + }, + "/security-rules": { + "get": { + "description": "Get SecurityRules", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SecurityRule" + ], + "summary": "Get SecurityRules", + "parameters": [ + { + "type": "integer", + "default": 0, + "description": "current page", + "name": "page", + "in": "query", + "required": true + }, + { + "maximum": 50, + "minimum": 2, + "type": "integer", + "default": 10, + "description": "return max item count, default 10, max 50", + "name": "per_page", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/model.SecurityRule" + } + } + }, + "400": { + "description": "" + }, + "404": { + "description": "" + }, + "500": { + "description": "" + } + } + }, + "post": { + "description": "create by json config", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SecurityRule" + ], + "summary": "Create SecurityRule", + "parameters": [ + { + "description": "SecurityRule", + "name": "SecurityRule", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.CreateSecurityRuleRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.SecurityRule" + } + }, + "400": { + "description": "" + }, + "404": { + "description": "" + }, + "500": { + "description": "" + } + } + } + }, + "/security-rules/{id}": { + "get": { + "description": "Get SecurityRule by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SecurityRule" + ], + "summary": "Get SecurityRule", + "parameters": [ + { + "type": "string", + "description": "id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.SecurityRule" + } + }, + "400": { + "description": "" + }, + "404": { + "description": "" + }, + "500": { + "description": "" + } + } + }, + "patch": { + "description": "Update by json config", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SecurityRule" + ], + "summary": "Update SecurityRule", + "parameters": [ + { + "type": "string", + "description": "id", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "SecurityRule", + "name": "SecurityRule", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.UpdateSecurityRuleRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.SecurityRule" + } + }, + "400": { + "description": "" + }, + "404": { + "description": "" + }, + "500": { + "description": "" + } + } + } + }, "/securityGroups/{id}": { "delete": { "description": "Destroy by id", @@ -2366,6 +2639,44 @@ } } }, + "/securityRules/{id}": { + "delete": { + "description": "Destroy by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SecurityRule" + ], + "summary": "Destroy SecurityRule", + "parameters": [ + { + "type": "string", + "description": "id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "" + }, + "400": { + "description": "" + }, + "404": { + "description": "" + }, + "500": { + "description": "" + } + } + } + }, "/user/signin/{name}": { "get": { "description": "oauth signin by json config", @@ -3012,6 +3323,32 @@ } }, "model.SecurityGroup": { + "type": "object", + "properties": { + "bio": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "security_rules": { + "type": "array", + "items": { + "$ref": "#/definitions/model.SecurityRule" + } + }, + "updated_at": { + "type": "string" + } + } + }, + "model.SecurityRule": { "type": "object", "properties": { "bio": { @@ -3032,6 +3369,12 @@ "proxy_domain": { "type": "string" }, + "security_groups": { + "type": "array", + "items": { + "$ref": "#/definitions/model.SecurityGroup" + } + }, "updated_at": { "type": "string" } @@ -3128,9 +3471,6 @@ }, "name": { "type": "string" - }, - "security_group_domain": { - "type": "string" } } }, @@ -3298,9 +3638,6 @@ }, "scopes": { "$ref": "#/definitions/types.SchedulerClusterScopes" - }, - "security_group_domain": { - "type": "string" } } }, @@ -3342,6 +3679,20 @@ } }, "types.CreateSecurityGroupRequest": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "bio": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "types.CreateSecurityRuleRequest": { "type": "object", "required": [ "domain", @@ -3497,9 +3848,6 @@ }, "name": { "type": "string" - }, - "security_group_domain": { - "type": "string" } } }, @@ -3597,9 +3945,6 @@ }, "scopes": { "$ref": "#/definitions/types.SchedulerClusterScopes" - }, - "security_group_domain": { - "type": "string" } } }, @@ -3634,6 +3979,17 @@ } }, "types.UpdateSecurityGroupRequest": { + "type": "object", + "properties": { + "bio": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "types.UpdateSecurityRuleRequest": { "type": "object", "properties": { "bio": { diff --git a/api/manager/swagger.yaml b/api/manager/swagger.yaml index f8402300e..1ea6ddacc 100644 --- a/api/manager/swagger.yaml +++ b/api/manager/swagger.yaml @@ -181,6 +181,23 @@ definitions: type: string type: object model.SecurityGroup: + properties: + bio: + type: string + created_at: + type: string + id: + type: integer + name: + type: string + security_rules: + items: + $ref: '#/definitions/model.SecurityRule' + type: array + updated_at: + type: string + type: object + model.SecurityRule: properties: bio: type: string @@ -194,6 +211,10 @@ definitions: type: string proxy_domain: type: string + security_groups: + items: + $ref: '#/definitions/model.SecurityGroup' + type: array updated_at: type: string type: object @@ -255,8 +276,6 @@ definitions: $ref: '#/definitions/types.CDNClusterConfig' name: type: string - security_group_domain: - type: string required: - config - name @@ -370,8 +389,6 @@ definitions: type: string scopes: $ref: '#/definitions/types.SchedulerClusterScopes' - security_group_domain: - type: string required: - client_config - config @@ -404,6 +421,15 @@ definitions: - scheduler_cluster_id type: object types.CreateSecurityGroupRequest: + properties: + bio: + type: string + name: + type: string + required: + - name + type: object + types.CreateSecurityRuleRequest: properties: bio: type: string @@ -507,8 +533,6 @@ definitions: $ref: '#/definitions/types.CDNClusterConfig' name: type: string - security_group_domain: - type: string type: object types.UpdateCDNRequest: properties: @@ -572,8 +596,6 @@ definitions: type: string scopes: $ref: '#/definitions/types.SchedulerClusterScopes' - security_group_domain: - type: string type: object types.UpdateSchedulerRequest: properties: @@ -596,6 +618,13 @@ definitions: type: string type: object types.UpdateSecurityGroupRequest: + properties: + bio: + type: string + name: + type: string + type: object + types.UpdateSecurityRuleRequest: properties: bio: type: string @@ -2161,6 +2190,189 @@ paths: summary: Add Scheduler to SecurityGroup tags: - SecurityGroup + /security-groups/{id}/security-rules/{security_rule_id}: + delete: + consumes: + - application/json + description: Destroy SecurityRule to SecurityGroup + parameters: + - description: id + in: path + name: id + required: true + type: string + - description: security rule id + in: path + name: security_rule_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: "" + "400": + description: "" + "404": + description: "" + "500": + description: "" + summary: Destroy SecurityRule to SecurityGroup + tags: + - SecurityGroup + put: + consumes: + - application/json + description: Add SecurityRule to SecurityGroup + parameters: + - description: id + in: path + name: id + required: true + type: string + - description: security rule id + in: path + name: security_rule_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: "" + "400": + description: "" + "404": + description: "" + "500": + description: "" + summary: Add SecurityRule to SecurityGroup + tags: + - SecurityGroup + /security-rules: + get: + consumes: + - application/json + description: Get SecurityRules + parameters: + - default: 0 + description: current page + in: query + name: page + required: true + type: integer + - default: 10 + description: return max item count, default 10, max 50 + in: query + maximum: 50 + minimum: 2 + name: per_page + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/model.SecurityRule' + type: array + "400": + description: "" + "404": + description: "" + "500": + description: "" + summary: Get SecurityRules + tags: + - SecurityRule + post: + consumes: + - application/json + description: create by json config + parameters: + - description: SecurityRule + in: body + name: SecurityRule + required: true + schema: + $ref: '#/definitions/types.CreateSecurityRuleRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.SecurityRule' + "400": + description: "" + "404": + description: "" + "500": + description: "" + summary: Create SecurityRule + tags: + - SecurityRule + /security-rules/{id}: + get: + consumes: + - application/json + description: Get SecurityRule by id + parameters: + - description: id + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.SecurityRule' + "400": + description: "" + "404": + description: "" + "500": + description: "" + summary: Get SecurityRule + tags: + - SecurityRule + patch: + consumes: + - application/json + description: Update by json config + parameters: + - description: id + in: path + name: id + required: true + type: string + - description: SecurityRule + in: body + name: SecurityRule + required: true + schema: + $ref: '#/definitions/types.UpdateSecurityRuleRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.SecurityRule' + "400": + description: "" + "404": + description: "" + "500": + description: "" + summary: Update SecurityRule + tags: + - SecurityRule /securityGroups/{id}: delete: consumes: @@ -2186,6 +2398,31 @@ paths: summary: Destroy SecurityGroup tags: - SecurityGroup + /securityRules/{id}: + delete: + consumes: + - application/json + description: Destroy by id + parameters: + - description: id + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: "" + "400": + description: "" + "404": + description: "" + "500": + description: "" + summary: Destroy SecurityRule + tags: + - SecurityRule /user/signin/{name}: get: consumes: diff --git a/docs/en/api-reference/api-reference.md b/docs/en/api-reference/api-reference.md index 05382599e..386a78f7f 100644 --- a/docs/en/api-reference/api-reference.md +++ b/docs/en/api-reference/api-reference.md @@ -2337,6 +2337,268 @@ Add Scheduler to SecurityGroup * SecurityGroup + +### Add SecurityRule to SecurityGroup +``` +PUT /api/v1/security-groups/{id}/security-rules/{security_rule_id} +``` + + +#### Description +Add SecurityRule to SecurityGroup + + +#### Parameters + +|Type|Name|Description|Schema| +|---|---|---|---| +|**Path**|**id**
*required*|id|string| +|**Path**|**security_rule_id**
*required*|security rule id|string| + + +#### Responses + +|HTTP Code|Schema| +|---|---| +|**200**|No Content| +|**400**|No Content| +|**404**|No Content| +|**500**|No Content| + + +#### Consumes + +* `application/json` + + +#### Produces + +* `application/json` + + +#### Tags + +* SecurityGroup + + + +### Destroy SecurityRule to SecurityGroup +``` +DELETE /api/v1/security-groups/{id}/security-rules/{security_rule_id} +``` + + +#### Description +Destroy SecurityRule to SecurityGroup + + +#### Parameters + +|Type|Name|Description|Schema| +|---|---|---|---| +|**Path**|**id**
*required*|id|string| +|**Path**|**security_rule_id**
*required*|security rule id|string| + + +#### Responses + +|HTTP Code|Schema| +|---|---| +|**200**|No Content| +|**400**|No Content| +|**404**|No Content| +|**500**|No Content| + + +#### Consumes + +* `application/json` + + +#### Produces + +* `application/json` + + +#### Tags + +* SecurityGroup + + + +### Create SecurityRule +``` +POST /api/v1/security-rules +``` + + +#### Description +create by json config + + +#### Parameters + +|Type|Name|Description|Schema| +|---|---|---|---| +|**Body**|**SecurityRule**
*required*|SecurityRule|[types.CreateSecurityRuleRequest](#types-createsecurityrulerequest)| + + +#### Responses + +|HTTP Code|Description|Schema| +|---|---|---| +|**200**|OK|[model.SecurityRule](#model-securityrule)| +|**400**||No Content| +|**404**||No Content| +|**500**||No Content| + + +#### Consumes + +* `application/json` + + +#### Produces + +* `application/json` + + +#### Tags + +* SecurityRule + + + +### Get SecurityRules +``` +GET /api/v1/security-rules +``` + + +#### Description +Get SecurityRules + + +#### Parameters + +|Type|Name|Description|Schema|Default| +|---|---|---|---|---| +|**Query**|**page**
*required*|current page|integer|`0`| +|**Query**|**per_page**
*required*|return max item count, default 10, max 50|integer|`10`| + + +#### Responses + +|HTTP Code|Description|Schema| +|---|---|---| +|**200**|OK|< [model.SecurityRule](#model-securityrule) > array| +|**400**||No Content| +|**404**||No Content| +|**500**||No Content| + + +#### Consumes + +* `application/json` + + +#### Produces + +* `application/json` + + +#### Tags + +* SecurityRule + + + +### Get SecurityRule +``` +GET /api/v1/security-rules/{id} +``` + + +#### Description +Get SecurityRule by id + + +#### Parameters + +|Type|Name|Description|Schema| +|---|---|---|---| +|**Path**|**id**
*required*|id|string| + + +#### Responses + +|HTTP Code|Description|Schema| +|---|---|---| +|**200**|OK|[model.SecurityRule](#model-securityrule)| +|**400**||No Content| +|**404**||No Content| +|**500**||No Content| + + +#### Consumes + +* `application/json` + + +#### Produces + +* `application/json` + + +#### Tags + +* SecurityRule + + + +### Update SecurityRule +``` +PATCH /api/v1/security-rules/{id} +``` + + +#### Description +Update by json config + + +#### Parameters + +|Type|Name|Description|Schema| +|---|---|---|---| +|**Path**|**id**
*required*|id|string| +|**Body**|**SecurityRule**
*required*|SecurityRule|[types.UpdateSecurityRuleRequest](#types-updatesecurityrulerequest)| + + +#### Responses + +|HTTP Code|Description|Schema| +|---|---|---| +|**200**|OK|[model.SecurityRule](#model-securityrule)| +|**400**||No Content| +|**404**||No Content| +|**500**||No Content| + + +#### Consumes + +* `application/json` + + +#### Produces + +* `application/json` + + +#### Tags + +* SecurityRule + + ### Destroy SecurityGroup ``` @@ -2380,6 +2642,49 @@ Destroy by id * SecurityGroup + +### Destroy SecurityRule +``` +DELETE /api/v1/securityRules/{id} +``` + + +#### Description +Destroy by id + + +#### Parameters + +|Type|Name|Description|Schema| +|---|---|---|---| +|**Path**|**id**
*required*|id|string| + + +#### Responses + +|HTTP Code|Schema| +|---|---| +|**200**|No Content| +|**400**|No Content| +|**404**|No Content| +|**500**|No Content| + + +#### Consumes + +* `application/json` + + +#### Produces + +* `application/json` + + +#### Tags + +* SecurityRule + + ### Oauth Signin ``` @@ -2885,6 +3190,19 @@ Get User by id ### model.SecurityGroup +|Name|Schema| +|---|---| +|**bio**
*optional*|string| +|**created_at**
*optional*|string| +|**id**
*optional*|integer| +|**name**
*optional*|string| +|**security_rules**
*optional*|< [model.SecurityRule](#model-securityrule) > array| +|**updated_at**
*optional*|string| + + + +### model.SecurityRule + |Name|Schema| |---|---| |**bio**
*optional*|string| @@ -2893,6 +3211,7 @@ Get User by id |**id**
*optional*|integer| |**name**
*optional*|string| |**proxy_domain**
*optional*|string| +|**security_groups**
*optional*|< [model.SecurityGroup](#model-securitygroup) > array| |**updated_at**
*optional*|string| @@ -2948,7 +3267,6 @@ Get User by id |**bio**
*optional*|string| |**config**
*required*|[types.CDNClusterConfig](#types-cdnclusterconfig)| |**name**
*required*|string| -|**security_group_domain**
*optional*|string| @@ -3023,7 +3341,6 @@ Get User by id |**is_default**
*optional*|boolean| |**name**
*required*|string| |**scopes**
*optional*|[types.SchedulerClusterScopes](#types-schedulerclusterscopes)| -|**security_group_domain**
*optional*|string| @@ -3044,6 +3361,15 @@ Get User by id ### types.CreateSecurityGroupRequest +|Name|Schema| +|---|---| +|**bio**
*optional*|string| +|**name**
*required*|string| + + + +### types.CreateSecurityRuleRequest + |Name|Schema| |---|---| |**bio**
*optional*|string| @@ -3140,7 +3466,6 @@ Get User by id |**bio**
*optional*|string| |**config**
*optional*|[types.CDNClusterConfig](#types-cdnclusterconfig)| |**name**
*optional*|string| -|**security_group_domain**
*optional*|string| @@ -3200,7 +3525,6 @@ Get User by id |**is_default**
*optional*|boolean| |**name**
*optional*|string| |**scopes**
*optional*|[types.SchedulerClusterScopes](#types-schedulerclusterscopes)| -|**security_group_domain**
*optional*|string| @@ -3221,6 +3545,15 @@ Get User by id ### types.UpdateSecurityGroupRequest +|Name|Schema| +|---|---| +|**bio**
*optional*|string| +|**name**
*optional*|string| + + + +### types.UpdateSecurityRuleRequest + |Name|Schema| |---|---| |**bio**
*optional*|string| diff --git a/docs/zh-CN/api-reference/api-reference.md b/docs/zh-CN/api-reference/api-reference.md index 9e53def36..4b8b3aeae 100644 --- a/docs/zh-CN/api-reference/api-reference.md +++ b/docs/zh-CN/api-reference/api-reference.md @@ -2337,6 +2337,268 @@ Add Scheduler to SecurityGroup * SecurityGroup + +### Add SecurityRule to SecurityGroup +``` +PUT /api/v1/security-groups/{id}/security-rules/{security_rule_id} +``` + + +#### 说明 +Add SecurityRule to SecurityGroup + + +#### 参数 + +|类型|名称|说明|类型| +|---|---|---|---| +|**Path**|**id**
*必填*|id|string| +|**Path**|**security_rule_id**
*必填*|security rule id|string| + + +#### 响应 + +|HTTP代码|类型| +|---|---| +|**200**|无内容| +|**400**|无内容| +|**404**|无内容| +|**500**|无内容| + + +#### 消耗 + +* `application/json` + + +#### 生成 + +* `application/json` + + +#### 标签 + +* SecurityGroup + + + +### Destroy SecurityRule to SecurityGroup +``` +DELETE /api/v1/security-groups/{id}/security-rules/{security_rule_id} +``` + + +#### 说明 +Destroy SecurityRule to SecurityGroup + + +#### 参数 + +|类型|名称|说明|类型| +|---|---|---|---| +|**Path**|**id**
*必填*|id|string| +|**Path**|**security_rule_id**
*必填*|security rule id|string| + + +#### 响应 + +|HTTP代码|类型| +|---|---| +|**200**|无内容| +|**400**|无内容| +|**404**|无内容| +|**500**|无内容| + + +#### 消耗 + +* `application/json` + + +#### 生成 + +* `application/json` + + +#### 标签 + +* SecurityGroup + + + +### Create SecurityRule +``` +POST /api/v1/security-rules +``` + + +#### 说明 +create by json config + + +#### 参数 + +|类型|名称|说明|类型| +|---|---|---|---| +|**Body**|**SecurityRule**
*必填*|SecurityRule|[types.CreateSecurityRuleRequest](#types-createsecurityrulerequest)| + + +#### 响应 + +|HTTP代码|说明|类型| +|---|---|---| +|**200**|OK|[model.SecurityRule](#model-securityrule)| +|**400**||无内容| +|**404**||无内容| +|**500**||无内容| + + +#### 消耗 + +* `application/json` + + +#### 生成 + +* `application/json` + + +#### 标签 + +* SecurityRule + + + +### Get SecurityRules +``` +GET /api/v1/security-rules +``` + + +#### 说明 +Get SecurityRules + + +#### 参数 + +|类型|名称|说明|类型|默认值| +|---|---|---|---|---| +|**Query**|**page**
*必填*|current page|integer|`0`| +|**Query**|**per_page**
*必填*|return max item count, default 10, max 50|integer|`10`| + + +#### 响应 + +|HTTP代码|说明|类型| +|---|---|---| +|**200**|OK|< [model.SecurityRule](#model-securityrule) > array| +|**400**||无内容| +|**404**||无内容| +|**500**||无内容| + + +#### 消耗 + +* `application/json` + + +#### 生成 + +* `application/json` + + +#### 标签 + +* SecurityRule + + + +### Get SecurityRule +``` +GET /api/v1/security-rules/{id} +``` + + +#### 说明 +Get SecurityRule by id + + +#### 参数 + +|类型|名称|说明|类型| +|---|---|---|---| +|**Path**|**id**
*必填*|id|string| + + +#### 响应 + +|HTTP代码|说明|类型| +|---|---|---| +|**200**|OK|[model.SecurityRule](#model-securityrule)| +|**400**||无内容| +|**404**||无内容| +|**500**||无内容| + + +#### 消耗 + +* `application/json` + + +#### 生成 + +* `application/json` + + +#### 标签 + +* SecurityRule + + + +### Update SecurityRule +``` +PATCH /api/v1/security-rules/{id} +``` + + +#### 说明 +Update by json config + + +#### 参数 + +|类型|名称|说明|类型| +|---|---|---|---| +|**Path**|**id**
*必填*|id|string| +|**Body**|**SecurityRule**
*必填*|SecurityRule|[types.UpdateSecurityRuleRequest](#types-updatesecurityrulerequest)| + + +#### 响应 + +|HTTP代码|说明|类型| +|---|---|---| +|**200**|OK|[model.SecurityRule](#model-securityrule)| +|**400**||无内容| +|**404**||无内容| +|**500**||无内容| + + +#### 消耗 + +* `application/json` + + +#### 生成 + +* `application/json` + + +#### 标签 + +* SecurityRule + + ### Destroy SecurityGroup ``` @@ -2380,6 +2642,49 @@ Destroy by id * SecurityGroup + +### Destroy SecurityRule +``` +DELETE /api/v1/securityRules/{id} +``` + + +#### 说明 +Destroy by id + + +#### 参数 + +|类型|名称|说明|类型| +|---|---|---|---| +|**Path**|**id**
*必填*|id|string| + + +#### 响应 + +|HTTP代码|类型| +|---|---| +|**200**|无内容| +|**400**|无内容| +|**404**|无内容| +|**500**|无内容| + + +#### 消耗 + +* `application/json` + + +#### 生成 + +* `application/json` + + +#### 标签 + +* SecurityRule + + ### Oauth Signin ``` @@ -2885,6 +3190,19 @@ Get User by id ### model.SecurityGroup +|名称|类型| +|---|---| +|**bio**
*可选*|string| +|**created_at**
*可选*|string| +|**id**
*可选*|integer| +|**name**
*可选*|string| +|**security_rules**
*可选*|< [model.SecurityRule](#model-securityrule) > array| +|**updated_at**
*可选*|string| + + + +### model.SecurityRule + |名称|类型| |---|---| |**bio**
*可选*|string| @@ -2893,6 +3211,7 @@ Get User by id |**id**
*可选*|integer| |**name**
*可选*|string| |**proxy_domain**
*可选*|string| +|**security_groups**
*可选*|< [model.SecurityGroup](#model-securitygroup) > array| |**updated_at**
*可选*|string| @@ -2948,7 +3267,6 @@ Get User by id |**bio**
*可选*|string| |**config**
*必填*|[types.CDNClusterConfig](#types-cdnclusterconfig)| |**name**
*必填*|string| -|**security_group_domain**
*可选*|string| @@ -3023,7 +3341,6 @@ Get User by id |**is_default**
*可选*|boolean| |**name**
*必填*|string| |**scopes**
*可选*|[types.SchedulerClusterScopes](#types-schedulerclusterscopes)| -|**security_group_domain**
*可选*|string| @@ -3044,6 +3361,15 @@ Get User by id ### types.CreateSecurityGroupRequest +|名称|类型| +|---|---| +|**bio**
*可选*|string| +|**name**
*必填*|string| + + + +### types.CreateSecurityRuleRequest + |名称|类型| |---|---| |**bio**
*可选*|string| @@ -3140,7 +3466,6 @@ Get User by id |**bio**
*可选*|string| |**config**
*可选*|[types.CDNClusterConfig](#types-cdnclusterconfig)| |**name**
*可选*|string| -|**security_group_domain**
*可选*|string| @@ -3200,7 +3525,6 @@ Get User by id |**is_default**
*可选*|boolean| |**name**
*可选*|string| |**scopes**
*可选*|[types.SchedulerClusterScopes](#types-schedulerclusterscopes)| -|**security_group_domain**
*可选*|string| @@ -3221,6 +3545,15 @@ Get User by id ### types.UpdateSecurityGroupRequest +|名称|类型| +|---|---| +|**bio**
*可选*|string| +|**name**
*可选*|string| + + + +### types.UpdateSecurityRuleRequest + |名称|类型| |---|---| |**bio**
*可选*|string| diff --git a/manager/database/database.go b/manager/database/database.go index f409af27f..8c0072271 100644 --- a/manager/database/database.go +++ b/manager/database/database.go @@ -112,6 +112,7 @@ func migrate(db *gorm.DB) error { &model.CDN{}, &model.SchedulerCluster{}, &model.Scheduler{}, + &model.SecurityRule{}, &model.SecurityGroup{}, &model.User{}, &model.Oauth{}, diff --git a/manager/handlers/cdn_cluster.go b/manager/handlers/cdn_cluster.go index 459003243..222a3ee30 100644 --- a/manager/handlers/cdn_cluster.go +++ b/manager/handlers/cdn_cluster.go @@ -44,17 +44,6 @@ func (h *Handlers) CreateCDNCluster(ctx *gin.Context) { return } - if json.SecurityGroupDomain != "" { - cdn, err := h.service.CreateCDNClusterWithSecurityGroupDomain(ctx.Request.Context(), json) - if err != nil { - ctx.Error(err) // nolint: errcheck - return - } - - ctx.JSON(http.StatusOK, cdn) - return - } - cdnCluster, err := h.service.CreateCDNCluster(ctx.Request.Context(), json) if err != nil { ctx.Error(err) // nolint: errcheck @@ -115,17 +104,6 @@ func (h *Handlers) UpdateCDNCluster(ctx *gin.Context) { return } - if json.SecurityGroupDomain != "" { - cdn, err := h.service.UpdateCDNClusterWithSecurityGroupDomain(ctx.Request.Context(), params.ID, json) - if err != nil { - ctx.Error(err) // nolint: errcheck - return - } - - ctx.JSON(http.StatusOK, cdn) - return - } - cdnCluster, err := h.service.UpdateCDNCluster(ctx.Request.Context(), params.ID, json) if err != nil { ctx.Error(err) // nolint: errcheck diff --git a/manager/handlers/scheduler_cluster.go b/manager/handlers/scheduler_cluster.go index d55829ce7..c56c1efc1 100644 --- a/manager/handlers/scheduler_cluster.go +++ b/manager/handlers/scheduler_cluster.go @@ -44,17 +44,6 @@ func (h *Handlers) CreateSchedulerCluster(ctx *gin.Context) { return } - if json.SecurityGroupDomain != "" { - scheduler, err := h.service.CreateSchedulerClusterWithSecurityGroupDomain(ctx.Request.Context(), json) - if err != nil { - ctx.Error(err) // nolint: errcheck - return - } - - ctx.JSON(http.StatusOK, scheduler) - return - } - schedulerCluster, err := h.service.CreateSchedulerCluster(ctx.Request.Context(), json) if err != nil { ctx.Error(err) // nolint: errcheck @@ -115,17 +104,6 @@ func (h *Handlers) UpdateSchedulerCluster(ctx *gin.Context) { return } - if json.SecurityGroupDomain != "" { - scheduler, err := h.service.UpdateSchedulerClusterWithSecurityGroupDomain(ctx.Request.Context(), params.ID, json) - if err != nil { - ctx.Error(err) // nolint: errcheck - return - } - - ctx.JSON(http.StatusOK, scheduler) - return - } - schedulerCluster, err := h.service.UpdateSchedulerCluster(ctx.Request.Context(), params.ID, json) if err != nil { ctx.Error(err) // nolint: errcheck diff --git a/manager/handlers/security_group.go b/manager/handlers/security_group.go index 99db28a86..4daa3ced3 100644 --- a/manager/handlers/security_group.go +++ b/manager/handlers/security_group.go @@ -225,3 +225,59 @@ func (h *Handlers) AddCDNClusterToSecurityGroup(ctx *gin.Context) { ctx.Status(http.StatusOK) } + +// @Summary Add SecurityRule to SecurityGroup +// @Description Add SecurityRule to SecurityGroup +// @Tags SecurityGroup +// @Accept json +// @Produce json +// @Param id path string true "id" +// @Param security_rule_id path string true "security rule id" +// @Success 200 +// @Failure 400 +// @Failure 404 +// @Failure 500 +// @Router /security-groups/{id}/security-rules/{security_rule_id} [put] +func (h *Handlers) AddSecurityRuleToSecurityGroup(ctx *gin.Context) { + var params types.AddSecurityRuleToSecurityGroupParams + if err := ctx.ShouldBindUri(¶ms); err != nil { + ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()}) + return + } + + err := h.service.AddSecurityRuleToSecurityGroup(ctx.Request.Context(), params.ID, params.SecurityRuleID) + if err != nil { + ctx.Error(err) // nolint: errcheck + return + } + + ctx.Status(http.StatusOK) +} + +// @Summary Destroy SecurityRule to SecurityGroup +// @Description Destroy SecurityRule to SecurityGroup +// @Tags SecurityGroup +// @Accept json +// @Produce json +// @Param id path string true "id" +// @Param security_rule_id path string true "security rule id" +// @Success 200 +// @Failure 400 +// @Failure 404 +// @Failure 500 +// @Router /security-groups/{id}/security-rules/{security_rule_id} [delete] +func (h *Handlers) DestroySecurityRuleToSecurityGroup(ctx *gin.Context) { + var params types.AddSecurityRuleToSecurityGroupParams + if err := ctx.ShouldBindUri(¶ms); err != nil { + ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()}) + return + } + + err := h.service.DestroySecurityRuleToSecurityGroup(ctx.Request.Context(), params.ID, params.SecurityRuleID) + if err != nil { + ctx.Error(err) // nolint: errcheck + return + } + + ctx.Status(http.StatusOK) +} diff --git a/manager/handlers/security_rule.go b/manager/handlers/security_rule.go new file mode 100644 index 000000000..706999de2 --- /dev/null +++ b/manager/handlers/security_rule.go @@ -0,0 +1,171 @@ +/* + * Copyright 2020 The Dragonfly Authors + * + * Licensed 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 handlers + +import ( + "net/http" + + "github.com/gin-gonic/gin" + + // nolint + _ "d7y.io/dragonfly/v2/manager/model" + "d7y.io/dragonfly/v2/manager/types" +) + +// @Summary Create SecurityRule +// @Description create by json config +// @Tags SecurityRule +// @Accept json +// @Produce json +// @Param SecurityRule body types.CreateSecurityRuleRequest true "SecurityRule" +// @Success 200 {object} model.SecurityRule +// @Failure 400 +// @Failure 404 +// @Failure 500 +// @Router /security-rules [post] +func (h *Handlers) CreateSecurityRule(ctx *gin.Context) { + var json types.CreateSecurityRuleRequest + if err := ctx.ShouldBindJSON(&json); err != nil { + ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()}) + return + } + + securityRule, err := h.service.CreateSecurityRule(ctx.Request.Context(), json) + if err != nil { + ctx.Error(err) // nolint: errcheck + return + } + + ctx.JSON(http.StatusOK, securityRule) +} + +// @Summary Destroy SecurityRule +// @Description Destroy by id +// @Tags SecurityRule +// @Accept json +// @Produce json +// @Param id path string true "id" +// @Success 200 +// @Failure 400 +// @Failure 404 +// @Failure 500 +// @Router /securityRules/{id} [delete] +func (h *Handlers) DestroySecurityRule(ctx *gin.Context) { + var params types.SecurityRuleParams + if err := ctx.ShouldBindUri(¶ms); err != nil { + ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()}) + return + } + + if err := h.service.DestroySecurityRule(ctx.Request.Context(), params.ID); err != nil { + ctx.Error(err) // nolint: errcheck + return + } + + ctx.Status(http.StatusOK) +} + +// @Summary Update SecurityRule +// @Description Update by json config +// @Tags SecurityRule +// @Accept json +// @Produce json +// @Param id path string true "id" +// @Param SecurityRule body types.UpdateSecurityRuleRequest true "SecurityRule" +// @Success 200 {object} model.SecurityRule +// @Failure 400 +// @Failure 404 +// @Failure 500 +// @Router /security-rules/{id} [patch] +func (h *Handlers) UpdateSecurityRule(ctx *gin.Context) { + var params types.SecurityRuleParams + if err := ctx.ShouldBindUri(¶ms); err != nil { + ctx.Error(err) // nolint: errcheck + return + } + + var json types.UpdateSecurityRuleRequest + if err := ctx.ShouldBindJSON(&json); err != nil { + ctx.Error(err) // nolint: errcheck + return + } + + securityRule, err := h.service.UpdateSecurityRule(ctx.Request.Context(), params.ID, json) + if err != nil { + ctx.Error(err) // nolint: errcheck + return + } + + ctx.JSON(http.StatusOK, securityRule) +} + +// @Summary Get SecurityRule +// @Description Get SecurityRule by id +// @Tags SecurityRule +// @Accept json +// @Produce json +// @Param id path string true "id" +// @Success 200 {object} model.SecurityRule +// @Failure 400 +// @Failure 404 +// @Failure 500 +// @Router /security-rules/{id} [get] +func (h *Handlers) GetSecurityRule(ctx *gin.Context) { + var params types.SecurityRuleParams + if err := ctx.ShouldBindUri(¶ms); err != nil { + ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()}) + return + } + + securityRule, err := h.service.GetSecurityRule(ctx.Request.Context(), params.ID) + if err != nil { + ctx.Error(err) // nolint: errcheck + return + } + + ctx.JSON(http.StatusOK, securityRule) +} + +// @Summary Get SecurityRules +// @Description Get SecurityRules +// @Tags SecurityRule +// @Accept json +// @Produce json +// @Param page query int true "current page" default(0) +// @Param per_page query int true "return max item count, default 10, max 50" default(10) minimum(2) maximum(50) +// @Success 200 {object} []model.SecurityRule +// @Failure 400 +// @Failure 404 +// @Failure 500 +// @Router /security-rules [get] +func (h *Handlers) GetSecurityRules(ctx *gin.Context) { + var query types.GetSecurityRulesQuery + if err := ctx.ShouldBindQuery(&query); err != nil { + ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()}) + return + } + + h.setPaginationDefault(&query.Page, &query.PerPage) + securityRules, count, err := h.service.GetSecurityRules(ctx.Request.Context(), query) + if err != nil { + ctx.Error(err) // nolint: errcheck + return + } + + h.setPaginationLinkHeader(ctx, query.Page, query.PerPage, int(count)) + ctx.JSON(http.StatusOK, securityRules) +} diff --git a/manager/model/security_group.go b/manager/model/security_group.go index fb9269475..bca3d3830 100644 --- a/manager/model/security_group.go +++ b/manager/model/security_group.go @@ -20,8 +20,7 @@ type SecurityGroup struct { Model Name string `gorm:"column:name;type:varchar(256);index:uk_security_group_name,unique;not null;comment:name" json:"name"` BIO string `gorm:"column:bio;type:varchar(1024);comment:biography" json:"bio"` - Domain string `gorm:"column:domain;type:varchar(256);index:uk_security_group_domain,unique;not null;comment:domain" json:"domain"` - ProxyDomain string `gorm:"column:proxy_domain;type:varchar(1024);comment:proxy domain" json:"proxy_domain"` + SecurityRules []SecurityRule `gorm:"many2many:security_group_security_rule;" json:"security_rules"` SchedulerClusters []SchedulerCluster `json:"-"` CDNClusters []CDNCluster `json:"-"` } diff --git a/manager/model/security_rule.go b/manager/model/security_rule.go new file mode 100644 index 000000000..256d46a30 --- /dev/null +++ b/manager/model/security_rule.go @@ -0,0 +1,26 @@ +/* + * Copyright 2020 The Dragonfly Authors + * + * Licensed 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 + +type SecurityRule struct { + Model + Name string `gorm:"column:name;type:varchar(256);index:uk_security_rule_name,unique;not null;comment:name" json:"name"` + BIO string `gorm:"column:bio;type:varchar(1024);comment:biography" json:"bio"` + Domain string `gorm:"column:domain;type:varchar(256);index:uk_security_rule_domain,unique;not null;comment:domain" json:"domain"` + ProxyDomain string `gorm:"column:proxy_domain;type:varchar(1024);comment:proxy domain" json:"proxy_domain"` + SecurityGroups []SecurityGroup `gorm:"many2many:security_group_security_rule;" json:"security_groups"` +} diff --git a/manager/router/router.go b/manager/router/router.go index 12d506bf3..7f273aea6 100644 --- a/manager/router/router.go +++ b/manager/router/router.go @@ -165,6 +165,14 @@ func Init(cfg *config.Config, service service.REST, enforcer *casbin.Enforcer) ( c.GET(":id", h.GetCDN) c.GET("", h.GetCDNs) + // Security Rule + sr := apiv1.Group("/security-rules", jwt.MiddlewareFunc(), rbac) + sr.POST("", h.CreateSecurityRule) + sr.DELETE(":id", h.DestroySecurityRule) + sr.PATCH(":id", h.UpdateSecurityRule) + sr.GET(":id", h.GetSecurityRule) + sr.GET("", h.GetSecurityRules) + // Security Group sg := apiv1.Group("/security-groups", jwt.MiddlewareFunc(), rbac) sg.POST("", h.CreateSecurityGroup) @@ -174,6 +182,8 @@ func Init(cfg *config.Config, service service.REST, enforcer *casbin.Enforcer) ( sg.GET("", h.GetSecurityGroups) sg.PUT(":id/scheduler-clusters/:scheduler_cluster_id", h.AddSchedulerClusterToSecurityGroup) sg.PUT(":id/cdn-clusters/:cdn_cluster_id", h.AddCDNClusterToSecurityGroup) + sg.PUT(":id/security-rules/:security_rule_id", h.AddSecurityRuleToSecurityGroup) + sg.DELETE(":id/security-rules/:security_rule_id", h.DestroySecurityRuleToSecurityGroup) // Config config := apiv1.Group("/configs") diff --git a/manager/searcher/searcher.go b/manager/searcher/searcher.go index 8deeec52d..50e954541 100644 --- a/manager/searcher/searcher.go +++ b/manager/searcher/searcher.go @@ -17,28 +17,56 @@ package searcher import ( - "sort" + "strings" "github.com/mitchellh/mapstructure" - "gonum.org/v1/gonum/stat" "d7y.io/dragonfly/v2/manager/model" + "d7y.io/dragonfly/v2/pkg/util/mathutils" ) const ( + // Condition IDC key + conditionIDC = "idc" + + // Condition location key + conditionLocation = "location" + + // Condition netTopology key + conditionNetTopology = "net_topology" + + // Condition security domain key conditionSecurityDomain = "security_domain" - conditionLocation = "location" - conditionIDC = "idc" ) const ( - conditionLocationWeight = 0.7 - conditionIDCWeight = 0.3 + // IDC affinity weight + idcAffinityWeight float64 = 0.5 + + // NetTopology affinity weight + netTopologyAffinityWeight = 0.3 + + // Location affinity weight + locationAffinityWeight = 0.2 +) + +const ( + // Maximum score + maxScore float64 = 1.0 + + // Minimum score + minScore = 0 +) + +const ( + // Maximum number of elements + maxElementLen = 5 ) type Scopes struct { - Location []string `mapstructure:"location"` - IDC []string `mapstructure:"idc"` + IDC string `mapstructure:"idc"` + Location string `mapstructure:"location"` + NetTopology string `mapstructure:"net_topology"` } type Searcher interface { @@ -62,63 +90,96 @@ func (s *searcher) FindSchedulerCluster(schedulerClusters []model.SchedulerClust } // If there are security domain conditions, match clusters of the same security domain. - // If the security domain condition does not exist, it matches clusters that does not have a security domain. + // If the security domain condition does not exist, it will match all scheduler security domains. // Then use clusters sets to score according to scopes. - securityDomain := conditions[conditionSecurityDomain] var clusters []model.SchedulerCluster - for _, v := range schedulerClusters { - if v.SecurityGroup.Domain == securityDomain { - clusters = append(clusters, v) + securityDomain := conditions[conditionSecurityDomain] + for _, schedulerCluster := range schedulerClusters { + if len(schedulerCluster.Schedulers) > 0 { + if securityDomain == "" { + clusters = append(clusters, schedulerCluster) + } else { + for _, securityRule := range schedulerCluster.SecurityGroup.SecurityRules { + if strings.Compare(securityRule.Domain, securityDomain) == 0 { + clusters = append(clusters, schedulerCluster) + } + } + } } } switch len(clusters) { case 0: + // If the security domain does not match, there is no cluster available return model.SchedulerCluster{}, false case 1: + // If only one cluster matches the security domain, return the cluster directly return clusters[0], true default: - var maxMean float64 = 0 - cluster := clusters[0] - for _, v := range clusters { - mean := calculateSchedulerClusterMean(conditions, v.Scopes) - if mean > maxMean { - maxMean = mean - cluster = v + // If there are multiple clusters matching the security domain, + // select the schuelder cluster with a higher score + var maxScore float64 = 0 + result := clusters[0] + for _, cluster := range clusters { + var scopes Scopes + if err := mapstructure.Decode(cluster.Scopes, &scopes); err != nil { + // Scopes parse failed to skip this evaluation + continue + } + + score := evaluate(conditions, scopes) + if score > maxScore { + maxScore = score + result = cluster } } - return cluster, true + return result, true } } -func calculateSchedulerClusterMean(conditions map[string]string, rawScopes map[string]interface{}) float64 { - var scopes Scopes - if err := mapstructure.Decode(rawScopes, &scopes); err != nil { - return 0 - } - - location := conditions[conditionLocation] - lx := calculateConditionScore(location, scopes.Location) +// Evaluate the degree of matching between scheduler cluster and dfdaemon +func evaluate(conditions map[string]string, scopes Scopes) float64 { + return idcAffinityWeight*calculateIDCAffinityScore(conditions[conditionIDC], scopes.IDC) + + locationAffinityWeight*calculateMultiElementAffinityScore(conditions[conditionLocation], scopes.Location) + + netTopologyAffinityWeight*calculateMultiElementAffinityScore(conditions[conditionNetTopology], scopes.NetTopology) +} - idc := conditions[conditionIDC] - ix := calculateConditionScore(idc, scopes.IDC) +// calculateIDCAffinityScore 0.0~1.0 larger and better +func calculateIDCAffinityScore(dst, src string) float64 { + if dst != "" && src != "" && strings.Compare(dst, src) == 0 { + return maxScore + } - return stat.Mean([]float64{lx, ix}, []float64{conditionLocationWeight, conditionIDCWeight}) + return minScore } -func calculateConditionScore(value string, scope []string) float64 { - if value == "" { - return 0 +// calculateMultiElementAffinityScore 0.0~1.0 larger and better +func calculateMultiElementAffinityScore(dst, src string) float64 { + if dst == "" || src == "" { + return minScore + } + + if strings.Compare(dst, src) == 0 { + return maxScore } - if len(scope) <= 0 { - return 0 + // Calculate the number of multi-element matches divided by "|" + var score, elementLen int + dstElements := strings.Split(dst, "|") + srcElements := strings.Split(src, "|") + elementLen = mathutils.MaxInt(len(dstElements), len(srcElements)) + + // Maximum element length is 5 + if elementLen > maxElementLen { + elementLen = maxElementLen } - i := sort.SearchStrings(scope, value) - if i < 0 { - return 0 + for i := 0; i < elementLen; i++ { + if strings.Compare(dstElements[i], srcElements[i]) != 0 { + break + } + score++ } - return 1 + return float64(score) / float64(maxElementLen) } diff --git a/manager/searcher/searcher_test.go b/manager/searcher/searcher_test.go index a4c9e0709..b9c67e430 100644 --- a/manager/searcher/searcher_test.go +++ b/manager/searcher/searcher_test.go @@ -55,7 +55,17 @@ func TestSchedulerCluster(t *testing.T) { { Name: "foo", SecurityGroup: model.SecurityGroup{ - Domain: "domain-1", + SecurityRules: []model.SecurityRule{ + { + Domain: "domain-1", + }, + }, + }, + Schedulers: []model.Scheduler{ + { + HostName: "foo", + Status: "active", + }, }, }, { @@ -77,9 +87,21 @@ func TestSchedulerCluster(t *testing.T) { Scopes: map[string]interface{}{ "location": []string{"location-1"}, }, + Schedulers: []model.Scheduler{ + { + HostName: "foo", + Status: "active", + }, + }, }, { Name: "bar", + Schedulers: []model.Scheduler{ + { + HostName: "bar", + Status: "active", + }, + }, }, }, conditions: map[string]string{"location": "location-1"}, @@ -97,9 +119,21 @@ func TestSchedulerCluster(t *testing.T) { Scopes: map[string]interface{}{ "idc": []string{"idc-1"}, }, + Schedulers: []model.Scheduler{ + { + HostName: "foo", + Status: "active", + }, + }, }, { Name: "bar", + Schedulers: []model.Scheduler{ + { + HostName: "bar", + Status: "active", + }, + }, }, }, conditions: map[string]string{"idc": "idc-1"}, @@ -109,6 +143,38 @@ func TestSchedulerCluster(t *testing.T) { assert.Equal(ok, true) }, }, + { + name: "match according to net topology condition", + schedulerClusters: []model.SchedulerCluster{ + { + Name: "foo", + Scopes: map[string]interface{}{ + "net_topology": []string{"net-topology-1"}, + }, + Schedulers: []model.Scheduler{ + { + HostName: "foo", + Status: "active", + }, + }, + }, + { + Name: "bar", + Schedulers: []model.Scheduler{ + { + HostName: "bar", + Status: "active", + }, + }, + }, + }, + conditions: map[string]string{"net_topology": "net-topology-1"}, + expect: func(t *testing.T, data model.SchedulerCluster, ok bool) { + assert := assert.New(t) + assert.Equal(data.Name, "foo") + assert.Equal(ok, true) + }, + }, { name: "match according to location and idc condition", schedulerClusters: []model.SchedulerCluster{ @@ -118,9 +184,21 @@ func TestSchedulerCluster(t *testing.T) { "location": []string{"location-1"}, "idc": []string{"idc-1"}, }, + Schedulers: []model.Scheduler{ + { + HostName: "foo", + Status: "active", + }, + }, }, { Name: "bar", + Schedulers: []model.Scheduler{ + { + HostName: "bar", + Status: "active", + }, + }, }, }, conditions: map[string]string{ @@ -142,11 +220,27 @@ func TestSchedulerCluster(t *testing.T) { "location": []string{"location-1"}, }, SecurityGroup: model.SecurityGroup{ - Domain: "domain-1", + SecurityRules: []model.SecurityRule{ + { + Domain: "domain-1", + }, + }, + }, + Schedulers: []model.Scheduler{ + { + HostName: "foo", + Status: "active", + }, }, }, { Name: "bar", + Schedulers: []model.Scheduler{ + { + HostName: "bar", + Status: "active", + }, + }, }, }, conditions: map[string]string{ @@ -168,11 +262,27 @@ func TestSchedulerCluster(t *testing.T) { "idc": []string{"idc-1"}, }, SecurityGroup: model.SecurityGroup{ - Domain: "domain-1", + SecurityRules: []model.SecurityRule{ + { + Domain: "domain-1", + }, + }, + }, + Schedulers: []model.Scheduler{ + { + HostName: "foo", + Status: "active", + }, }, }, { Name: "bar", + Schedulers: []model.Scheduler{ + { + HostName: "bar", + Status: "active", + }, + }, }, }, conditions: map[string]string{ @@ -195,11 +305,27 @@ func TestSchedulerCluster(t *testing.T) { "location": []string{"location-1"}, }, SecurityGroup: model.SecurityGroup{ - Domain: "domain-1", + SecurityRules: []model.SecurityRule{ + { + Domain: "domain-1", + }, + }, + }, + Schedulers: []model.Scheduler{ + { + HostName: "foo", + Status: "active", + }, }, }, { Name: "bar", + Schedulers: []model.Scheduler{ + { + HostName: "bar", + Status: "active", + }, + }, }, }, conditions: map[string]string{ @@ -223,127 +349,3 @@ func TestSchedulerCluster(t *testing.T) { }) } } - -func TestCalculateSchedulerClusterMean(t *testing.T) { - tests := []struct { - name string - conditions map[string]string - rawScopes map[string]interface{} - expect func(t *testing.T, mean float64) - }{ - { - name: "conditions and rawScopes is empty", - conditions: map[string]string{}, - rawScopes: map[string]interface{}{}, - expect: func(t *testing.T, mean float64) { - assert := assert.New(t) - assert.Equal(mean, float64(0)) - }, - }, - { - name: "missed matches", - conditions: map[string]string{ - "location": "location-1", - }, - rawScopes: map[string]interface{}{ - "idc": []string{"idc-1"}, - }, - expect: func(t *testing.T, mean float64) { - assert := assert.New(t) - assert.Equal(mean, float64(0)) - }, - }, - { - name: "match according to location", - conditions: map[string]string{ - "location": "location-1", - }, - rawScopes: map[string]interface{}{ - "location": []string{"location-1"}, - }, - expect: func(t *testing.T, mean float64) { - assert := assert.New(t) - assert.Equal(mean, float64(conditionLocationWeight)) - }, - }, - { - name: "match according to idc", - conditions: map[string]string{ - "idc": "idc-1", - }, - rawScopes: map[string]interface{}{ - "idc": []string{"idc-1"}, - }, - expect: func(t *testing.T, mean float64) { - assert := assert.New(t) - assert.Equal(mean, float64(conditionIDCWeight)) - }, - }, - { - name: "match according to location and idc", - conditions: map[string]string{ - "location": "location-1", - "idc": "idc-1", - }, - rawScopes: map[string]interface{}{ - "location": []string{"location-1"}, - "idc": []string{"idc-1"}, - }, - expect: func(t *testing.T, mean float64) { - assert := assert.New(t) - assert.Equal(mean, float64(conditionLocationWeight+conditionIDCWeight)) - }, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - mean := calculateSchedulerClusterMean(tc.conditions, tc.rawScopes) - tc.expect(t, mean) - }) - } -} - -func TestCalculateConditionScore(t *testing.T) { - tests := []struct { - name string - value string - scope []string - expect func(t *testing.T, score float64) - }{ - { - name: "value is empty", - value: "", - scope: []string{"foo"}, - expect: func(t *testing.T, score float64) { - assert := assert.New(t) - assert.Equal(score, float64(0)) - }, - }, - { - name: "scope is empty", - value: "foo", - scope: []string{}, - expect: func(t *testing.T, score float64) { - assert := assert.New(t) - assert.Equal(score, float64(0)) - }, - }, - { - name: "match according to value", - value: "foo", - scope: []string{"foo"}, - expect: func(t *testing.T, score float64) { - assert := assert.New(t) - assert.Equal(score, float64(1)) - }, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - score := calculateConditionScore(tc.value, tc.scope) - tc.expect(t, score) - }) - } -} diff --git a/manager/service/cdn_cluster.go b/manager/service/cdn_cluster.go index 87f80452f..596475e00 100644 --- a/manager/service/cdn_cluster.go +++ b/manager/service/cdn_cluster.go @@ -56,33 +56,6 @@ func (s *rest) DestroyCDNCluster(ctx context.Context, id uint) error { return nil } -func (s *rest) CreateCDNClusterWithSecurityGroupDomain(ctx context.Context, json types.CreateCDNClusterRequest) (*model.CDNCluster, error) { - securityGroup := model.SecurityGroup{ - Domain: json.SecurityGroupDomain, - } - if err := s.db.WithContext(ctx).First(&securityGroup).Error; err != nil { - return s.CreateCDNCluster(ctx, json) - } - - config, err := structutils.StructToMap(json.Config) - if err != nil { - return nil, err - } - - cdnCluster := model.CDNCluster{ - Name: json.Name, - BIO: json.BIO, - Config: config, - } - - if err := s.db.WithContext(ctx).Model(&securityGroup).Association("CDNClusters").Append(&cdnCluster); err != nil { - return nil, err - - } - - return &cdnCluster, nil -} - func (s *rest) UpdateCDNCluster(ctx context.Context, id uint, json types.UpdateCDNClusterRequest) (*model.CDNCluster, error) { config, err := structutils.StructToMap(json.Config) if err != nil { @@ -101,32 +74,6 @@ func (s *rest) UpdateCDNCluster(ctx context.Context, id uint, json types.UpdateC return &cdnCluster, nil } -func (s *rest) UpdateCDNClusterWithSecurityGroupDomain(ctx context.Context, id uint, json types.UpdateCDNClusterRequest) (*model.CDNCluster, error) { - securityGroup := model.SecurityGroup{ - Domain: json.SecurityGroupDomain, - } - if err := s.db.WithContext(ctx).First(&securityGroup).Error; err != nil { - return s.UpdateCDNCluster(ctx, id, json) - } - - config, err := structutils.StructToMap(json.Config) - if err != nil { - return nil, err - } - - cdnCluster := model.CDNCluster{ - Name: json.Name, - BIO: json.BIO, - Config: config, - } - - if err := s.db.WithContext(ctx).Model(&securityGroup).Association("CDNClusters").Append(&cdnCluster); err != nil { - return nil, err - } - - return &cdnCluster, nil -} - func (s *rest) GetCDNCluster(ctx context.Context, id uint) (*model.CDNCluster, error) { cdnCluster := model.CDNCluster{} if err := s.db.WithContext(ctx).First(&cdnCluster, id).Error; err != nil { diff --git a/manager/service/scheduler_cluster.go b/manager/service/scheduler_cluster.go index a77fe3746..247ff31e9 100644 --- a/manager/service/scheduler_cluster.go +++ b/manager/service/scheduler_cluster.go @@ -62,51 +62,6 @@ func (s *rest) CreateSchedulerCluster(ctx context.Context, json types.CreateSche return &schedulerCluster, nil } -func (s *rest) CreateSchedulerClusterWithSecurityGroupDomain(ctx context.Context, json types.CreateSchedulerClusterRequest) (*model.SchedulerCluster, error) { - securityGroup := model.SecurityGroup{ - Domain: json.SecurityGroupDomain, - } - if err := s.db.WithContext(ctx).First(&securityGroup).Error; err != nil { - return s.CreateSchedulerCluster(ctx, json) - } - - config, err := structutils.StructToMap(json.Config) - if err != nil { - return nil, err - } - - clientConfig, err := structutils.StructToMap(json.ClientConfig) - if err != nil { - return nil, err - } - - scopes, err := structutils.StructToMap(json.Scopes) - if err != nil { - return nil, err - } - - schedulerCluster := model.SchedulerCluster{ - Name: json.Name, - BIO: json.BIO, - Config: config, - ClientConfig: clientConfig, - Scopes: scopes, - IsDefault: json.IsDefault, - } - - if err := s.db.WithContext(ctx).Model(&securityGroup).Association("SchedulerClusters").Append(&schedulerCluster); err != nil { - return nil, err - } - - if json.CDNClusterID > 0 { - if err := s.AddSchedulerClusterToCDNCluster(ctx, json.CDNClusterID, schedulerCluster.ID); err != nil { - return nil, err - } - } - - return &schedulerCluster, nil -} - func (s *rest) DestroySchedulerCluster(ctx context.Context, id uint) error { schedulerCluster := model.SchedulerCluster{} if err := s.db.WithContext(ctx).First(&schedulerCluster, id).Error; err != nil { @@ -157,51 +112,6 @@ func (s *rest) UpdateSchedulerCluster(ctx context.Context, id uint, json types.U return &schedulerCluster, nil } -func (s *rest) UpdateSchedulerClusterWithSecurityGroupDomain(ctx context.Context, id uint, json types.UpdateSchedulerClusterRequest) (*model.SchedulerCluster, error) { - securityGroup := model.SecurityGroup{ - Domain: json.SecurityGroupDomain, - } - if err := s.db.WithContext(ctx).First(&securityGroup).Error; err != nil { - return s.UpdateSchedulerCluster(ctx, id, json) - } - - config, err := structutils.StructToMap(json.Config) - if err != nil { - return nil, err - } - - clientConfig, err := structutils.StructToMap(json.ClientConfig) - if err != nil { - return nil, err - } - - scopes, err := structutils.StructToMap(json.Scopes) - if err != nil { - return nil, err - } - - schedulerCluster := model.SchedulerCluster{ - Name: json.Name, - BIO: json.BIO, - Config: config, - ClientConfig: clientConfig, - Scopes: scopes, - IsDefault: json.IsDefault, - } - - if err := s.db.WithContext(ctx).Model(&securityGroup).Association("SchedulerClusters").Append(&schedulerCluster); err != nil { - return nil, err - } - - if json.CDNClusterID > 0 { - if err := s.AddSchedulerClusterToCDNCluster(ctx, json.CDNClusterID, schedulerCluster.ID); err != nil { - return nil, err - } - } - - return &schedulerCluster, nil -} - func (s *rest) GetSchedulerCluster(ctx context.Context, id uint) (*model.SchedulerCluster, error) { schedulerCluster := model.SchedulerCluster{} if err := s.db.WithContext(ctx).Preload("CDNClusters").First(&schedulerCluster, id).Error; err != nil { diff --git a/manager/service/security_group.go b/manager/service/security_group.go index 635438a75..f0788b1ef 100644 --- a/manager/service/security_group.go +++ b/manager/service/security_group.go @@ -25,10 +25,8 @@ import ( func (s *rest) CreateSecurityGroup(ctx context.Context, json types.CreateSecurityGroupRequest) (*model.SecurityGroup, error) { securityGroup := model.SecurityGroup{ - Name: json.Name, - BIO: json.BIO, - Domain: json.Domain, - ProxyDomain: json.ProxyDomain, + Name: json.Name, + BIO: json.BIO, } if err := s.db.WithContext(ctx).Create(&securityGroup).Error; err != nil { @@ -54,10 +52,8 @@ func (s *rest) DestroySecurityGroup(ctx context.Context, id uint) error { func (s *rest) UpdateSecurityGroup(ctx context.Context, id uint, json types.UpdateSecurityGroupRequest) (*model.SecurityGroup, error) { securityGroup := model.SecurityGroup{} if err := s.db.WithContext(ctx).First(&securityGroup, id).Updates(model.SecurityGroup{ - Name: json.Name, - BIO: json.BIO, - Domain: json.Domain, - ProxyDomain: json.ProxyDomain, + Name: json.Name, + BIO: json.BIO, }).Error; err != nil { return nil, err } @@ -67,7 +63,7 @@ func (s *rest) UpdateSecurityGroup(ctx context.Context, id uint, json types.Upda func (s *rest) GetSecurityGroup(ctx context.Context, id uint) (*model.SecurityGroup, error) { securityGroup := model.SecurityGroup{} - if err := s.db.WithContext(ctx).First(&securityGroup, id).Error; err != nil { + if err := s.db.WithContext(ctx).Preload("SecurityRules").First(&securityGroup, id).Error; err != nil { return nil, err } @@ -78,9 +74,8 @@ func (s *rest) GetSecurityGroups(ctx context.Context, q types.GetSecurityGroupsQ var count int64 var securityGroups []model.SecurityGroup if err := s.db.WithContext(ctx).Scopes(model.Paginate(q.Page, q.PerPage)).Where(&model.SecurityGroup{ - Name: q.Name, - Domain: q.Domain, - }).Find(&securityGroups).Count(&count).Error; err != nil { + Name: q.Name, + }).Preload("SecurityRules").Find(&securityGroups).Count(&count).Error; err != nil { return nil, 0, err } @@ -122,3 +117,39 @@ func (s *rest) AddCDNClusterToSecurityGroup(ctx context.Context, id, cdnClusterI return nil } + +func (s *rest) AddSecurityRuleToSecurityGroup(ctx context.Context, id, securityRuleID uint) error { + securityGroup := model.SecurityGroup{} + if err := s.db.WithContext(ctx).First(&securityGroup, id).Error; err != nil { + return err + } + + securityRule := model.SecurityRule{} + if err := s.db.WithContext(ctx).First(&securityRule, securityRuleID).Error; err != nil { + return err + } + + if err := s.db.WithContext(ctx).Model(&securityGroup).Association("SecurityRules").Append(&securityRule); err != nil { + return err + } + + return nil +} + +func (s *rest) DestroySecurityRuleToSecurityGroup(ctx context.Context, id, securityRuleID uint) error { + securityGroup := model.SecurityGroup{} + if err := s.db.WithContext(ctx).First(&securityGroup, id).Error; err != nil { + return err + } + + securityRule := model.SecurityRule{} + if err := s.db.WithContext(ctx).First(&securityRule, securityRuleID).Error; err != nil { + return err + } + + if err := s.db.WithContext(ctx).Model(&securityGroup).Association("SecurityRules").Delete(&securityRule); err != nil { + return err + } + + return nil +} diff --git a/manager/service/security_rule.go b/manager/service/security_rule.go new file mode 100644 index 000000000..0cf8a6a15 --- /dev/null +++ b/manager/service/security_rule.go @@ -0,0 +1,87 @@ +/* + * Copyright 2020 The Dragonfly Authors + * + * Licensed 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 service + +import ( + "context" + + "d7y.io/dragonfly/v2/manager/model" + "d7y.io/dragonfly/v2/manager/types" +) + +func (s *rest) CreateSecurityRule(ctx context.Context, json types.CreateSecurityRuleRequest) (*model.SecurityRule, error) { + securityRule := model.SecurityRule{ + Name: json.Name, + BIO: json.BIO, + Domain: json.Domain, + ProxyDomain: json.ProxyDomain, + } + + if err := s.db.WithContext(ctx).Create(&securityRule).Error; err != nil { + return nil, err + } + + return &securityRule, nil +} + +func (s *rest) DestroySecurityRule(ctx context.Context, id uint) error { + securityRule := model.SecurityRule{} + if err := s.db.WithContext(ctx).First(&securityRule, id).Error; err != nil { + return err + } + + if err := s.db.WithContext(ctx).Unscoped().Delete(&model.SecurityRule{}, id).Error; err != nil { + return err + } + + return nil +} + +func (s *rest) UpdateSecurityRule(ctx context.Context, id uint, json types.UpdateSecurityRuleRequest) (*model.SecurityRule, error) { + securityRule := model.SecurityRule{} + if err := s.db.WithContext(ctx).First(&securityRule, id).Updates(model.SecurityRule{ + Name: json.Name, + BIO: json.BIO, + Domain: json.Domain, + ProxyDomain: json.ProxyDomain, + }).Error; err != nil { + return nil, err + } + + return &securityRule, nil +} + +func (s *rest) GetSecurityRule(ctx context.Context, id uint) (*model.SecurityRule, error) { + securityRule := model.SecurityRule{} + if err := s.db.WithContext(ctx).First(&securityRule, id).Error; err != nil { + return nil, err + } + + return &securityRule, nil +} + +func (s *rest) GetSecurityRules(ctx context.Context, q types.GetSecurityRulesQuery) (*[]model.SecurityRule, int64, error) { + var count int64 + var securityRules []model.SecurityRule + if err := s.db.WithContext(ctx).Scopes(model.Paginate(q.Page, q.PerPage)).Where(&model.SecurityRule{ + Name: q.Name, + }).Find(&securityRules).Count(&count).Error; err != nil { + return nil, 0, err + } + + return &securityRules, count, nil +} diff --git a/manager/service/service.go b/manager/service/service.go index c1dfaa18b..63b8c1904 100644 --- a/manager/service/service.go +++ b/manager/service/service.go @@ -60,10 +60,8 @@ type REST interface { GetOauths(context.Context, types.GetOauthsQuery) (*[]model.Oauth, int64, error) CreateCDNCluster(context.Context, types.CreateCDNClusterRequest) (*model.CDNCluster, error) - CreateCDNClusterWithSecurityGroupDomain(context.Context, types.CreateCDNClusterRequest) (*model.CDNCluster, error) DestroyCDNCluster(context.Context, uint) error UpdateCDNCluster(context.Context, uint, types.UpdateCDNClusterRequest) (*model.CDNCluster, error) - UpdateCDNClusterWithSecurityGroupDomain(context.Context, uint, types.UpdateCDNClusterRequest) (*model.CDNCluster, error) GetCDNCluster(context.Context, uint) (*model.CDNCluster, error) GetCDNClusters(context.Context, types.GetCDNClustersQuery) (*[]model.CDNCluster, int64, error) AddCDNToCDNCluster(context.Context, uint, uint) error @@ -76,10 +74,8 @@ type REST interface { GetCDNs(context.Context, types.GetCDNsQuery) (*[]model.CDN, int64, error) CreateSchedulerCluster(context.Context, types.CreateSchedulerClusterRequest) (*model.SchedulerCluster, error) - CreateSchedulerClusterWithSecurityGroupDomain(context.Context, types.CreateSchedulerClusterRequest) (*model.SchedulerCluster, error) DestroySchedulerCluster(context.Context, uint) error UpdateSchedulerCluster(context.Context, uint, types.UpdateSchedulerClusterRequest) (*model.SchedulerCluster, error) - UpdateSchedulerClusterWithSecurityGroupDomain(context.Context, uint, types.UpdateSchedulerClusterRequest) (*model.SchedulerCluster, error) GetSchedulerCluster(context.Context, uint) (*model.SchedulerCluster, error) GetSchedulerClusters(context.Context, types.GetSchedulerClustersQuery) (*[]model.SchedulerCluster, int64, error) AddSchedulerToSchedulerCluster(context.Context, uint, uint) error @@ -90,6 +86,12 @@ type REST interface { GetScheduler(context.Context, uint) (*model.Scheduler, error) GetSchedulers(context.Context, types.GetSchedulersQuery) (*[]model.Scheduler, int64, error) + CreateSecurityRule(context.Context, types.CreateSecurityRuleRequest) (*model.SecurityRule, error) + DestroySecurityRule(context.Context, uint) error + UpdateSecurityRule(context.Context, uint, types.UpdateSecurityRuleRequest) (*model.SecurityRule, error) + GetSecurityRule(context.Context, uint) (*model.SecurityRule, error) + GetSecurityRules(context.Context, types.GetSecurityRulesQuery) (*[]model.SecurityRule, int64, error) + CreateSecurityGroup(context.Context, types.CreateSecurityGroupRequest) (*model.SecurityGroup, error) DestroySecurityGroup(context.Context, uint) error UpdateSecurityGroup(context.Context, uint, types.UpdateSecurityGroupRequest) (*model.SecurityGroup, error) @@ -97,6 +99,8 @@ type REST interface { GetSecurityGroups(context.Context, types.GetSecurityGroupsQuery) (*[]model.SecurityGroup, int64, error) AddSchedulerClusterToSecurityGroup(context.Context, uint, uint) error AddCDNClusterToSecurityGroup(context.Context, uint, uint) error + AddSecurityRuleToSecurityGroup(context.Context, uint, uint) error + DestroySecurityRuleToSecurityGroup(context.Context, uint, uint) error CreateConfig(context.Context, types.CreateConfigRequest) (*model.Config, error) DestroyConfig(context.Context, uint) error diff --git a/manager/service/service_grpc.go b/manager/service/service_grpc.go index d09e739d0..28b94be55 100644 --- a/manager/service/service_grpc.go +++ b/manager/service/service_grpc.go @@ -66,7 +66,7 @@ func (s *GRPC) GetCDN(ctx context.Context, req *manager.GetCDNRequest) (*manager // Cache Miss logger.Infof("%s cache miss", cacheKey) cdn := model.CDN{} - if err := s.db.WithContext(ctx).Preload("CDNCluster.SecurityGroup").First(&cdn, &model.CDN{ + if err := s.db.WithContext(ctx).Preload("CDNCluster").First(&cdn, &model.CDN{ HostName: req.HostName, CDNClusterID: uint(req.CdnClusterId), }).Error; err != nil { @@ -93,13 +93,6 @@ func (s *GRPC) GetCDN(ctx context.Context, req *manager.GetCDNRequest) (*manager Name: cdn.CDNCluster.Name, Bio: cdn.CDNCluster.BIO, Config: config, - SecurityGroup: &manager.SecurityGroup{ - Id: uint64(cdn.CDNCluster.SecurityGroup.ID), - Name: cdn.CDNCluster.SecurityGroup.Name, - Bio: cdn.CDNCluster.SecurityGroup.BIO, - Domain: cdn.CDNCluster.SecurityGroup.Domain, - ProxyDomain: cdn.CDNCluster.SecurityGroup.ProxyDomain, - }, }, } @@ -197,7 +190,7 @@ func (s *GRPC) GetScheduler(ctx context.Context, req *manager.GetSchedulerReques // Cache Miss logger.Infof("%s cache miss", cacheKey) scheduler := model.Scheduler{} - if err := s.db.WithContext(ctx).Preload("SchedulerCluster.SecurityGroup").Preload("SchedulerCluster.CDNClusters.CDNs", &model.CDN{ + if err := s.db.WithContext(ctx).Preload("SchedulerCluster").Preload("SchedulerCluster.CDNClusters.CDNs", &model.CDN{ Status: model.CDNStatusActive, }).First(&scheduler, &model.Scheduler{ HostName: req.HostName, @@ -266,13 +259,6 @@ func (s *GRPC) GetScheduler(ctx context.Context, req *manager.GetSchedulerReques Bio: scheduler.SchedulerCluster.BIO, Config: schedulerClusterConfig, ClientConfig: schedulerClusterClientConfig, - SecurityGroup: &manager.SecurityGroup{ - Id: uint64(scheduler.SchedulerCluster.SecurityGroup.ID), - Name: scheduler.SchedulerCluster.SecurityGroup.Name, - Bio: scheduler.SchedulerCluster.SecurityGroup.BIO, - Domain: scheduler.SchedulerCluster.SecurityGroup.Domain, - ProxyDomain: scheduler.SchedulerCluster.SecurityGroup.ProxyDomain, - }, }, Cdns: pbCDNs, } @@ -391,7 +377,7 @@ func (s *GRPC) ListSchedulers(ctx context.Context, req *manager.ListSchedulersRe // Cache Miss logger.Infof("%s cache miss", cacheKey) var schedulerClusters []model.SchedulerCluster - if err := s.db.WithContext(ctx).Preload("SecurityGroup").Find(&schedulerClusters).Error; err != nil { + if err := s.db.WithContext(ctx).Preload("SecurityGroup.SecurityRules").Preload("Schedulers", "status = ?", "active").Find(&schedulerClusters).Error; err != nil { return nil, status.Error(codes.Unknown, err.Error()) } diff --git a/manager/types/cdn_cluster.go b/manager/types/cdn_cluster.go index 33c9379b0..07ce8e6ec 100644 --- a/manager/types/cdn_cluster.go +++ b/manager/types/cdn_cluster.go @@ -31,17 +31,15 @@ type AddSchedulerClusterToCDNClusterParams struct { } type CreateCDNClusterRequest struct { - Name string `json:"name" binding:"required"` - BIO string `json:"bio" binding:"omitempty"` - Config *CDNClusterConfig `json:"config" binding:"required"` - SecurityGroupDomain string `json:"security_group_domain" binding:"omitempty"` + Name string `json:"name" binding:"required"` + BIO string `json:"bio" binding:"omitempty"` + Config *CDNClusterConfig `json:"config" binding:"required"` } type UpdateCDNClusterRequest struct { - Name string `json:"name" binding:"omitempty"` - BIO string `json:"bio" binding:"omitempty"` - Config *CDNClusterConfig `json:"config" binding:"omitempty"` - SecurityGroupDomain string `json:"security_group_domain" binding:"omitempty"` + Name string `json:"name" binding:"omitempty"` + BIO string `json:"bio" binding:"omitempty"` + Config *CDNClusterConfig `json:"config" binding:"omitempty"` } type GetCDNClustersQuery struct { diff --git a/manager/types/scheduler_cluster.go b/manager/types/scheduler_cluster.go index 58da0b352..931222f4c 100644 --- a/manager/types/scheduler_cluster.go +++ b/manager/types/scheduler_cluster.go @@ -26,25 +26,23 @@ type AddSchedulerToSchedulerClusterParams struct { } type CreateSchedulerClusterRequest struct { - Name string `json:"name" binding:"required"` - BIO string `json:"bio" binding:"omitempty"` - Config *SchedulerClusterConfig `json:"config" binding:"required"` - ClientConfig *SchedulerClusterClientConfig `json:"client_config" binding:"required"` - Scopes *SchedulerClusterScopes `json:"scopes" binding:"omitempty"` - IsDefault bool `json:"is_default" binding:"omitempty"` - CDNClusterID uint `json:"cdn_cluster_id" binding:"omitempty"` - SecurityGroupDomain string `json:"security_group_domain" binding:"omitempty"` + Name string `json:"name" binding:"required"` + BIO string `json:"bio" binding:"omitempty"` + Config *SchedulerClusterConfig `json:"config" binding:"required"` + ClientConfig *SchedulerClusterClientConfig `json:"client_config" binding:"required"` + Scopes *SchedulerClusterScopes `json:"scopes" binding:"omitempty"` + IsDefault bool `json:"is_default" binding:"omitempty"` + CDNClusterID uint `json:"cdn_cluster_id" binding:"omitempty"` } type UpdateSchedulerClusterRequest struct { - Name string `json:"name" binding:"omitempty"` - BIO string `json:"bio" binding:"omitempty"` - Config *SchedulerClusterConfig `json:"config" binding:"omitempty"` - ClientConfig *SchedulerClusterClientConfig `json:"client_config" binding:"omitempty"` - Scopes *SchedulerClusterScopes `json:"scopes" binding:"omitempty"` - IsDefault bool `json:"is_default" binding:"omitempty"` - CDNClusterID uint `json:"cdn_cluster_id" binding:"omitempty"` - SecurityGroupDomain string `json:"security_group_domain" binding:"omitempty"` + Name string `json:"name" binding:"omitempty"` + BIO string `json:"bio" binding:"omitempty"` + Config *SchedulerClusterConfig `json:"config" binding:"omitempty"` + ClientConfig *SchedulerClusterClientConfig `json:"client_config" binding:"omitempty"` + Scopes *SchedulerClusterScopes `json:"scopes" binding:"omitempty"` + IsDefault bool `json:"is_default" binding:"omitempty"` + CDNClusterID uint `json:"cdn_cluster_id" binding:"omitempty"` } type GetSchedulerClustersQuery struct { diff --git a/manager/types/security_group.go b/manager/types/security_group.go index e01c4e0d3..4c9fdbcfc 100644 --- a/manager/types/security_group.go +++ b/manager/types/security_group.go @@ -30,23 +30,23 @@ type AddCDNClusterToSecurityGroupParams struct { CDNClusterID uint `uri:"cdn_cluster_id" binding:"required"` } +type AddSecurityRuleToSecurityGroupParams struct { + ID uint `uri:"id" binding:"required"` + SecurityRuleID uint `uri:"security_rule_id" binding:"required"` +} + type CreateSecurityGroupRequest struct { - Name string `json:"name" binding:"required"` - BIO string `json:"bio" binding:"omitempty"` - Domain string `json:"domain" binding:"required"` - ProxyDomain string `json:"proxy_domain" binding:"omitempty"` + Name string `json:"name" binding:"required"` + BIO string `json:"bio" binding:"omitempty"` } type UpdateSecurityGroupRequest struct { - Name string `json:"name" binding:"omitempty"` - BIO string `json:"bio" binding:"omitempty"` - Domain string `json:"domain" binding:"omitempty"` - ProxyDomain string `json:"proxy_domain" binding:"omitempty"` + Name string `json:"name" binding:"omitempty"` + BIO string `json:"bio" binding:"omitempty"` } type GetSecurityGroupsQuery struct { + Name string `form:"name" binding:"omitempty"` Page int `form:"page" binding:"omitempty,gte=1"` PerPage int `form:"per_page" binding:"omitempty,gte=1,lte=50"` - Name string `form:"name" binding:"omitempty"` - Domain string `form:"domain" binding:"omitempty"` } diff --git a/manager/types/security_rule.go b/manager/types/security_rule.go new file mode 100644 index 000000000..4351578f0 --- /dev/null +++ b/manager/types/security_rule.go @@ -0,0 +1,43 @@ +/* + * Copyright 2020 The Dragonfly Authors + * + * Licensed 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 types + +type SecurityRuleParams struct { + ID uint `uri:"id" binding:"required"` +} + +type CreateSecurityRuleRequest struct { + Name string `json:"name" binding:"required"` + BIO string `json:"bio" binding:"omitempty"` + Domain string `json:"domain" binding:"required"` + ProxyDomain string `json:"proxy_domain" binding:"omitempty"` +} + +type UpdateSecurityRuleRequest struct { + Name string `json:"name" binding:"omitempty"` + BIO string `json:"bio" binding:"omitempty"` + Domain string `json:"domain" binding:"omitempty"` + ProxyDomain string `json:"proxy_domain" binding:"omitempty"` +} + +type GetSecurityRulesQuery struct { + Page int `form:"page" binding:"omitempty,gte=1"` + PerPage int `form:"per_page" binding:"omitempty,gte=1,lte=50"` + Name string `form:"name" binding:"omitempty"` + Domain string `form:"domain" binding:"omitempty"` + ProxyDomain string `form:"proxy_domain" binding:"omitempty"` +}