From f67a3b357bf46dc011d5370c1ce746f82dce7b84 Mon Sep 17 00:00:00 2001 From: hanyajun <1581532052@qq.com> Date: Thu, 13 Jul 2023 20:09:32 +0800 Subject: [PATCH] feat: core-api add publish event report api (#88) * feat: core-api add publish event report api --- src/core-api/.golangci.yaml | 51 +++++ src/core-api/Makefile | 5 +- src/core-api/cmd/init.go | 6 +- src/core-api/cmd/root.go | 6 +- src/core-api/go.mod | 2 +- .../pkg/api/microgateway/permissions.go | 4 +- .../pkg/api/microgateway/public_key.go | 4 +- .../pkg/api/microgateway/publish_event.go | 62 +++++++ .../pkg/cacheimpls/app_gateway_permission.go | 4 +- .../cacheimpls/app_gateway_permission_test.go | 4 +- .../pkg/cacheimpls/app_resource_permission.go | 4 +- .../app_resource_permission_test.go | 4 +- src/core-api/pkg/cacheimpls/gateway.go | 4 +- src/core-api/pkg/cacheimpls/gateway_test.go | 4 +- src/core-api/pkg/cacheimpls/init.go | 8 + src/core-api/pkg/cacheimpls/jwt_public_key.go | 4 +- src/core-api/pkg/cacheimpls/microgateway.go | 7 +- .../pkg/cacheimpls/microgateway_test.go | 4 +- src/core-api/pkg/cacheimpls/release.go | 4 +- .../pkg/cacheimpls/release_history.go | 72 +++++++ .../pkg/cacheimpls/release_history_test.go | 65 +++++++ src/core-api/pkg/cacheimpls/release_test.go | 4 +- .../cacheimpls/resource_version_mapping.go | 6 +- src/core-api/pkg/cacheimpls/stage.go | 4 +- src/core-api/pkg/cacheimpls/stage_test.go | 4 +- src/core-api/pkg/cacheimpls/trace.go | 4 +- src/core-api/pkg/constant/event.go | 59 ++++++ .../database/dao/app_gateway_permission.go | 18 +- .../database/dao/app_resource_permission.go | 11 +- .../dao/app_resource_permission_test.go | 4 +- src/core-api/pkg/database/dao/gateway.go | 11 +- src/core-api/pkg/database/dao/gateway_test.go | 4 +- src/core-api/pkg/database/dao/jwt.go | 11 +- src/core-api/pkg/database/dao/jwt_test.go | 4 +- src/core-api/pkg/database/dao/microgateway.go | 12 +- .../pkg/database/dao/microgateway_test.go | 4 +- .../dao/mock/app_gateway_permission.go | 3 +- .../dao/mock/app_resource_permission.go | 3 +- src/core-api/pkg/database/dao/mock/gateway.go | 3 +- src/core-api/pkg/database/dao/mock/jwt.go | 3 +- .../pkg/database/dao/mock/microgateway.go | 3 +- .../pkg/database/dao/mock/publish_event.go | 52 ++++++ src/core-api/pkg/database/dao/mock/release.go | 3 +- .../pkg/database/dao/mock/release_history.go | 52 ++++++ .../pkg/database/dao/mock/resource_version.go | 3 +- src/core-api/pkg/database/dao/mock/stage.go | 3 +- .../pkg/database/dao/publish_event.go | 117 ++++++++++++ .../pkg/database/dao/publish_event_test.go | 53 ++++++ src/core-api/pkg/database/dao/release.go | 11 +- .../pkg/database/dao/release_history.go | 79 ++++++++ .../pkg/database/dao/release_history_test.go | 62 +++++++ src/core-api/pkg/database/dao/release_test.go | 4 +- .../pkg/database/dao/resource_version.go | 3 +- .../pkg/database/dao/resource_version_test.go | 4 +- src/core-api/pkg/database/dao/stage.go | 11 +- src/core-api/pkg/database/dao/stage_test.go | 4 +- src/core-api/pkg/database/dbmock.go | 5 +- src/core-api/pkg/database/init.go | 6 +- src/core-api/pkg/database/mysql.go | 13 +- src/core-api/pkg/database/sqlx.go | 20 +- src/core-api/pkg/database/utils.go | 4 +- src/core-api/pkg/logging/init.go | 1 + src/core-api/pkg/logging/writer.go | 2 +- src/core-api/pkg/middleware/logger_test.go | 6 +- .../pkg/middleware/micro_gateway_instance.go | 3 +- src/core-api/pkg/middleware/request_id.go | 4 +- src/core-api/pkg/server/router.go | 10 +- src/core-api/pkg/server/router_test.go | 4 +- src/core-api/pkg/service/app_permission.go | 22 ++- .../pkg/service/app_permission_test.go | 26 ++- .../pkg/service/mock/publish_event.go | 51 +++++ src/core-api/pkg/service/public_key.go | 1 + src/core-api/pkg/service/public_key_test.go | 8 +- src/core-api/pkg/service/publish_event.go | 96 ++++++++++ .../pkg/service/publish_event_test.go | 175 ++++++++++++++++++ src/core-api/pkg/trace/init.go | 6 +- src/core-api/pkg/util/request_test.go | 4 +- src/core-api/pkg/util/response_test.go | 4 +- src/core-api/pkg/util/string_test.go | 4 +- src/core-api/pkg/util/validation.go | 4 +- src/core-api/pkg/util/validation_test.go | 6 +- 81 files changed, 1290 insertions(+), 159 deletions(-) create mode 100644 src/core-api/.golangci.yaml create mode 100644 src/core-api/pkg/api/microgateway/publish_event.go create mode 100644 src/core-api/pkg/cacheimpls/release_history.go create mode 100644 src/core-api/pkg/cacheimpls/release_history_test.go create mode 100644 src/core-api/pkg/constant/event.go create mode 100644 src/core-api/pkg/database/dao/mock/publish_event.go create mode 100644 src/core-api/pkg/database/dao/mock/release_history.go create mode 100644 src/core-api/pkg/database/dao/publish_event.go create mode 100644 src/core-api/pkg/database/dao/publish_event_test.go create mode 100644 src/core-api/pkg/database/dao/release_history.go create mode 100644 src/core-api/pkg/database/dao/release_history_test.go create mode 100644 src/core-api/pkg/service/mock/publish_event.go create mode 100644 src/core-api/pkg/service/publish_event.go create mode 100644 src/core-api/pkg/service/publish_event_test.go diff --git a/src/core-api/.golangci.yaml b/src/core-api/.golangci.yaml new file mode 100644 index 000000000..49d73e75c --- /dev/null +++ b/src/core-api/.golangci.yaml @@ -0,0 +1,51 @@ +run: + # default concurrency is a available CPU number + concurrency: 4 + # timeout for analysis, e.g. 30s, 5m, default is 1m + timeout: 2m + # exit code when at least one issue was found, default is 1 + issues-exit-code: 1 + # include test files or not, default is true + tests: false + # default is true. Enables skipping of directories: + # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ + skip-dirs-use-default: true + + skip-files: + - ".*/mock/.*.go" + - ".*testing.go" + +linters: + # enable-all: true + # disable-all: true + disable: + - errcheck + enable: + - nilerr + - nakedret + - lll + - gofmt + - gocritic + - gocyclo + - whitespace + - stylecheck + - misspell + - goimports + # - bodyclose + # - nestif + # - gofumpt + # - godox + # - wsl + # - funlen + # - golint + # - cyclop + fast: false + +linters-settings: + stylecheck: + checks: ["-ST1000", "-ST1016", "-ST1020", "-ST1021", "-ST1022"] + goimports: + # A comma-separated list of prefixes, which, if set, checks import paths + # with the given prefixes are grouped after 3rd-party packages. + # Default: "" + local-prefixes: "core" \ No newline at end of file diff --git a/src/core-api/Makefile b/src/core-api/Makefile index b81ed1614..d70bb636d 100644 --- a/src/core-api/Makefile +++ b/src/core-api/Makefile @@ -13,6 +13,8 @@ init: go install mvdan.cc/gofumpt@latest # for golines go install github.com/segmentio/golines@latest + # for goimports + go install -v github.com/incu6us/goimports-reviser/v3@latest .PHONY: dep dep: @@ -38,7 +40,8 @@ check-license: .PHONY: fmt fmt: golines ./ -m 120 -w --base-formatter gofmt --no-reformat-tags - gofumpt -l -w . + gofumpt -l -w . + goimports-reviser -rm-unused -set-alias -format ./... .PHONY: test diff --git a/src/core-api/cmd/init.go b/src/core-api/cmd/init.go index 4d52ca433..b8d1d2abf 100644 --- a/src/core-api/cmd/init.go +++ b/src/core-api/cmd/init.go @@ -21,14 +21,14 @@ package cmd import ( "fmt" + sentry "github.com/getsentry/sentry-go" + "github.com/spf13/viper" + "core/pkg/config" "core/pkg/database" "core/pkg/logging" "core/pkg/metric" "core/pkg/trace" - - "github.com/getsentry/sentry-go" - "github.com/spf13/viper" ) var globalConfig *config.Config diff --git a/src/core-api/cmd/root.go b/src/core-api/cmd/root.go index 64b71d94b..035dcaa0a 100644 --- a/src/core-api/cmd/root.go +++ b/src/core-api/cmd/root.go @@ -22,13 +22,11 @@ import ( "fmt" "os" - "core/pkg/server" - + _ "github.com/go-sql-driver/mysql" "github.com/spf13/cobra" "github.com/spf13/viper" - // Register mysql resource - _ "github.com/go-sql-driver/mysql" + "core/pkg/server" ) // rootCmd represents the base command when called without any subcommands diff --git a/src/core-api/go.mod b/src/core-api/go.mod index da5a4efdf..72903c357 100644 --- a/src/core-api/go.mod +++ b/src/core-api/go.mod @@ -18,6 +18,7 @@ require ( github.com/onsi/ginkgo/v2 v2.9.5 github.com/onsi/gomega v1.27.6 github.com/prometheus/client_golang v1.15.0 + github.com/spf13/cast v1.5.0 github.com/spf13/cobra v1.7.0 github.com/spf13/viper v1.15.0 github.com/stretchr/testify v1.8.3 @@ -67,7 +68,6 @@ require ( github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/spf13/afero v1.9.3 // indirect - github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.4.2 // indirect diff --git a/src/core-api/pkg/api/microgateway/permissions.go b/src/core-api/pkg/api/microgateway/permissions.go index e40348309..56feb453f 100644 --- a/src/core-api/pkg/api/microgateway/permissions.go +++ b/src/core-api/pkg/api/microgateway/permissions.go @@ -22,10 +22,10 @@ import ( "database/sql" "errors" + "github.com/gin-gonic/gin" + "core/pkg/service" "core/pkg/util" - - "github.com/gin-gonic/gin" ) type queryPermissionSerializer struct { diff --git a/src/core-api/pkg/api/microgateway/public_key.go b/src/core-api/pkg/api/microgateway/public_key.go index e401ae9e4..e80b991ee 100644 --- a/src/core-api/pkg/api/microgateway/public_key.go +++ b/src/core-api/pkg/api/microgateway/public_key.go @@ -22,10 +22,10 @@ import ( "database/sql" "errors" + "github.com/gin-gonic/gin" + "core/pkg/service" "core/pkg/util" - - "github.com/gin-gonic/gin" ) type queryPublicKeySerializer struct { diff --git a/src/core-api/pkg/api/microgateway/publish_event.go b/src/core-api/pkg/api/microgateway/publish_event.go new file mode 100644 index 000000000..7397d1e47 --- /dev/null +++ b/src/core-api/pkg/api/microgateway/publish_event.go @@ -0,0 +1,62 @@ +/* + * TencentBlueKing is pleased to support the open source community by making + * 蓝鲸智云 - API 网关(BlueKing - APIGateway) available. + * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/MIT + * + * 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. + * + * We undertake not to change the open source license (MIT license) applicable + * to the current version of the project delivered to anyone in the future. + */ + +package microgateway + +import ( + "github.com/gin-gonic/gin" + "github.com/spf13/cast" + + "core/pkg/service" + "core/pkg/util" +) + +type reportPublishEventSerializer struct { + BkGatewayName string `json:"bk_gateway_name" binding:"required" example:"benchmark"` + BkStageName string `json:"bk_stage_name" binding:"required" example:"dev"` + Name string `json:"name" binding:"required" example:"generate_release_task"` + Status string `json:"status" binding:"required" example:"success" ` + Detail map[string]interface{} `json:"detail"` +} + +// ReportPublishEvent report publish event +func ReportPublishEvent(c *gin.Context) { + var query reportPublishEventSerializer + if err := c.ShouldBindJSON(&query); err != nil { + util.BadRequestErrorJSONResponse(c, util.ValidationErrorMessage(err)) + return + } + svc := service.NewPublishEventService() + publishID := cast.ToInt64(c.Param("publish_id")) + event := service.Event{ + Gateway: query.BkGatewayName, + Stage: query.BkGatewayName, + Name: query.Name, + Status: query.Status, + PublishID: publishID, + DetailMap: query.Detail, + } + err := svc.Report(c.Request.Context(), event) + if err != nil { + util.SystemErrorJSONResponse(c, err) + return + } + util.SuccessJSONResponse(c, gin.H{ + "result": "report success", + }) +} diff --git a/src/core-api/pkg/cacheimpls/app_gateway_permission.go b/src/core-api/pkg/cacheimpls/app_gateway_permission.go index 91b3e5689..370906ae5 100644 --- a/src/core-api/pkg/cacheimpls/app_gateway_permission.go +++ b/src/core-api/pkg/cacheimpls/app_gateway_permission.go @@ -24,10 +24,10 @@ import ( "errors" "strconv" + "github.com/TencentBlueKing/gopkg/cache" + "core/pkg/database/dao" "core/pkg/logging" - - "github.com/TencentBlueKing/gopkg/cache" ) // AppGatewayPermissionKey is the key of app-gateway permission diff --git a/src/core-api/pkg/cacheimpls/app_gateway_permission_test.go b/src/core-api/pkg/cacheimpls/app_gateway_permission_test.go index 5614dec43..eda850051 100644 --- a/src/core-api/pkg/cacheimpls/app_gateway_permission_test.go +++ b/src/core-api/pkg/cacheimpls/app_gateway_permission_test.go @@ -24,11 +24,11 @@ import ( "testing" "time" - "core/pkg/database/dao" - "github.com/TencentBlueKing/gopkg/cache" "github.com/TencentBlueKing/gopkg/cache/memory" "github.com/stretchr/testify/assert" + + "core/pkg/database/dao" ) func TestAppGatewayPermissionKey_Key(t *testing.T) { diff --git a/src/core-api/pkg/cacheimpls/app_resource_permission.go b/src/core-api/pkg/cacheimpls/app_resource_permission.go index 0b23dbee7..5683c6d78 100644 --- a/src/core-api/pkg/cacheimpls/app_resource_permission.go +++ b/src/core-api/pkg/cacheimpls/app_resource_permission.go @@ -24,10 +24,10 @@ import ( "errors" "strconv" + "github.com/TencentBlueKing/gopkg/cache" + "core/pkg/database/dao" "core/pkg/logging" - - "github.com/TencentBlueKing/gopkg/cache" ) // AppResourcePermissionKey is the key of app-resource permission diff --git a/src/core-api/pkg/cacheimpls/app_resource_permission_test.go b/src/core-api/pkg/cacheimpls/app_resource_permission_test.go index 68d2be285..958a7512b 100644 --- a/src/core-api/pkg/cacheimpls/app_resource_permission_test.go +++ b/src/core-api/pkg/cacheimpls/app_resource_permission_test.go @@ -24,11 +24,11 @@ import ( "testing" "time" - "core/pkg/database/dao" - "github.com/TencentBlueKing/gopkg/cache" "github.com/TencentBlueKing/gopkg/cache/memory" "github.com/stretchr/testify/assert" + + "core/pkg/database/dao" ) func TestAppResourcePermissionKey_Key(t *testing.T) { diff --git a/src/core-api/pkg/cacheimpls/gateway.go b/src/core-api/pkg/cacheimpls/gateway.go index ce5ec9d7c..9f5a35b3a 100644 --- a/src/core-api/pkg/cacheimpls/gateway.go +++ b/src/core-api/pkg/cacheimpls/gateway.go @@ -22,9 +22,9 @@ import ( "context" "errors" - "core/pkg/database/dao" - "github.com/TencentBlueKing/gopkg/cache" + + "core/pkg/database/dao" ) // GatewayNameKey is the key of gateway diff --git a/src/core-api/pkg/cacheimpls/gateway_test.go b/src/core-api/pkg/cacheimpls/gateway_test.go index df17329fe..d1ed7b08f 100644 --- a/src/core-api/pkg/cacheimpls/gateway_test.go +++ b/src/core-api/pkg/cacheimpls/gateway_test.go @@ -24,11 +24,11 @@ import ( "testing" "time" - "core/pkg/database/dao" - "github.com/TencentBlueKing/gopkg/cache" "github.com/TencentBlueKing/gopkg/cache/memory" "github.com/stretchr/testify/assert" + + "core/pkg/database/dao" ) func TestGatewayNameKey_Key(t *testing.T) { diff --git a/src/core-api/pkg/cacheimpls/init.go b/src/core-api/pkg/cacheimpls/init.go index 8af662caa..bc200483a 100644 --- a/src/core-api/pkg/cacheimpls/init.go +++ b/src/core-api/pkg/cacheimpls/init.go @@ -140,6 +140,14 @@ var ( newRandomDuration(10), ) + releaseHistoryCache = memory.NewCache( + "release_history", + DisableCache, + tracedFuncWrapper("release_history", retrieveReleaseHistory), + 1*time.Minute, + newRandomDuration(10), + ) + // app_code + gateway_id => permission, may change frequently appGatewayPermissionCache = memory.NewCache( "app_gateway_permission", diff --git a/src/core-api/pkg/cacheimpls/jwt_public_key.go b/src/core-api/pkg/cacheimpls/jwt_public_key.go index bd252d6eb..493428c30 100644 --- a/src/core-api/pkg/cacheimpls/jwt_public_key.go +++ b/src/core-api/pkg/cacheimpls/jwt_public_key.go @@ -23,9 +23,9 @@ import ( "errors" "strconv" - "core/pkg/database/dao" - "github.com/TencentBlueKing/gopkg/cache" + + "core/pkg/database/dao" ) // JWTPublicKeyCacheKey is the key of jwt public key diff --git a/src/core-api/pkg/cacheimpls/microgateway.go b/src/core-api/pkg/cacheimpls/microgateway.go index 999632238..26c6699fd 100644 --- a/src/core-api/pkg/cacheimpls/microgateway.go +++ b/src/core-api/pkg/cacheimpls/microgateway.go @@ -22,9 +22,9 @@ import ( "context" "errors" - "core/pkg/database/dao" - "github.com/TencentBlueKing/gopkg/cache" + + "core/pkg/database/dao" ) // MicroGatewayKey is the key of micro gateway @@ -66,7 +66,8 @@ func GetMicroGateway(ctx context.Context, instanceID string) (microGateway dao.M // MicroGatewayConfig is the config of micro gateway, it configured on dashboard, saved into db as a json // the schema is like {secret_key: {jwt_auth: xxxxx}} // here we use the jwt_auth as the credentials of the micro gateway with the instance id -// Note: The original credentials were a JWT token, and after refactoring we changed to the instance_id + token in the header. +// Note: The original credentials were a JWT token, and after refactoring we changed to the instance_id + token in the +// header. type MicroGatewayConfig struct { JwtAuth JwtAuth `json:"jwt_auth"` } diff --git a/src/core-api/pkg/cacheimpls/microgateway_test.go b/src/core-api/pkg/cacheimpls/microgateway_test.go index 4fe123fdd..933886414 100644 --- a/src/core-api/pkg/cacheimpls/microgateway_test.go +++ b/src/core-api/pkg/cacheimpls/microgateway_test.go @@ -24,11 +24,11 @@ import ( "testing" "time" - "core/pkg/database/dao" - "github.com/TencentBlueKing/gopkg/cache" "github.com/TencentBlueKing/gopkg/cache/memory" "github.com/stretchr/testify/assert" + + "core/pkg/database/dao" ) func TestMicroGatewayKey_Key(t *testing.T) { diff --git a/src/core-api/pkg/cacheimpls/release.go b/src/core-api/pkg/cacheimpls/release.go index f33832341..09fe59a8d 100644 --- a/src/core-api/pkg/cacheimpls/release.go +++ b/src/core-api/pkg/cacheimpls/release.go @@ -23,9 +23,9 @@ import ( "errors" "strconv" - "core/pkg/database/dao" - "github.com/TencentBlueKing/gopkg/cache" + + "core/pkg/database/dao" ) // ReleaseKey is the key of release diff --git a/src/core-api/pkg/cacheimpls/release_history.go b/src/core-api/pkg/cacheimpls/release_history.go new file mode 100644 index 000000000..54afb8e40 --- /dev/null +++ b/src/core-api/pkg/cacheimpls/release_history.go @@ -0,0 +1,72 @@ +/* + * TencentBlueKing is pleased to support the open source community by making + * 蓝鲸智云 - API 网关(BlueKing - APIGateway) available. + * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/MIT + * + * 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. + * + * We undertake not to change the open source license (MIT license) applicable + * to the current version of the project delivered to anyone in the future. + */ + +package cacheimpls + +import ( + "context" + "errors" + "strconv" + + "github.com/TencentBlueKing/gopkg/cache" + + "core/pkg/database/dao" +) + +// ReleaseHistoryCacheKey is the key of jwt public key +type ReleaseHistoryCacheKey struct { + ReleaseID int64 +} + +// Key return the key string of release history +func (k ReleaseHistoryCacheKey) Key() string { + return strconv.FormatInt(k.ReleaseID, 10) +} + +func retrieveReleaseHistory(ctx context.Context, k cache.Key) (interface{}, error) { + key := k.(ReleaseHistoryCacheKey) + + manager := dao.NewReleaseHistoryManger() + + releaseHistory, err := manager.Get(ctx, key.ReleaseID) + if err != nil { + return "", err + } + + return releaseHistory, nil +} + +// GetReleaseHistory will get the jwt public key from cache by ReleaseID +func GetReleaseHistory(ctx context.Context, releaseID int64) (releaseHistory dao.ReleaseHistory, err error) { + key := ReleaseHistoryCacheKey{ + ReleaseID: releaseID, + } + var value interface{} + value, err = cacheGet(ctx, releaseHistoryCache, key) + if err != nil { + return + } + + var ok bool + releaseHistory, ok = value.(dao.ReleaseHistory) + if !ok { + err = errors.New("not ReleaseHistory in cache") + return + } + return +} diff --git a/src/core-api/pkg/cacheimpls/release_history_test.go b/src/core-api/pkg/cacheimpls/release_history_test.go new file mode 100644 index 000000000..c17a52bdf --- /dev/null +++ b/src/core-api/pkg/cacheimpls/release_history_test.go @@ -0,0 +1,65 @@ +/* + * TencentBlueKing is pleased to support the open source community by making + * 蓝鲸智云 - API 网关(BlueKing - APIGateway) available. + * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/MIT + * + * 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. + * + * We undertake not to change the open source license (MIT license) applicable + * to the current version of the project delivered to anyone in the future. + */ + +package cacheimpls + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/TencentBlueKing/gopkg/cache" + "github.com/TencentBlueKing/gopkg/cache/memory" + "github.com/stretchr/testify/assert" + + "core/pkg/database/dao" +) + +func TestReleaseHistoryCacheKey_Key(t *testing.T) { + k := ReleaseHistoryCacheKey{ + ReleaseID: 1, + } + assert.Equal(t, "1", k.Key()) +} + +func TestGetReleaseHistory(t *testing.T) { + expiration := 5 * time.Minute + + // valid + retrieveFunc := func(ctx context.Context, key cache.Key) (interface{}, error) { + return dao.ReleaseHistory{}, nil + } + mockCache := memory.NewCache( + "mockCache", false, retrieveFunc, expiration, nil) + releaseHistoryCache = mockCache + + _, err := GetReleaseHistory(context.Background(), 1) + assert.NoError(t, err) + + // error + retrieveFunc = func(ctx context.Context, key cache.Key) (interface{}, error) { + return false, errors.New("error here") + } + mockCache = memory.NewCache( + "mockCache", false, retrieveFunc, expiration, nil) + releaseHistoryCache = mockCache + + _, err = GetReleaseHistory(context.Background(), 1) + assert.Error(t, err) +} diff --git a/src/core-api/pkg/cacheimpls/release_test.go b/src/core-api/pkg/cacheimpls/release_test.go index 9665eab58..369ce3404 100644 --- a/src/core-api/pkg/cacheimpls/release_test.go +++ b/src/core-api/pkg/cacheimpls/release_test.go @@ -24,11 +24,11 @@ import ( "testing" "time" - "core/pkg/database/dao" - "github.com/TencentBlueKing/gopkg/cache" "github.com/TencentBlueKing/gopkg/cache/memory" "github.com/stretchr/testify/assert" + + "core/pkg/database/dao" ) func TestGetMicroGateway_Key(t *testing.T) { diff --git a/src/core-api/pkg/cacheimpls/resource_version_mapping.go b/src/core-api/pkg/cacheimpls/resource_version_mapping.go index 92c535d67..ee3feb485 100644 --- a/src/core-api/pkg/cacheimpls/resource_version_mapping.go +++ b/src/core-api/pkg/cacheimpls/resource_version_mapping.go @@ -24,11 +24,11 @@ import ( "errors" "strconv" - "core/pkg/database/dao" - "core/pkg/logging" - "github.com/TencentBlueKing/gopkg/cache" jsoniter "github.com/json-iterator/go" + + "core/pkg/database/dao" + "core/pkg/logging" ) // ResourceVersionMappingKey is the key of resource version mapping diff --git a/src/core-api/pkg/cacheimpls/stage.go b/src/core-api/pkg/cacheimpls/stage.go index 929f839ab..aae83c128 100644 --- a/src/core-api/pkg/cacheimpls/stage.go +++ b/src/core-api/pkg/cacheimpls/stage.go @@ -23,9 +23,9 @@ import ( "errors" "strconv" - "core/pkg/database/dao" - "github.com/TencentBlueKing/gopkg/cache" + + "core/pkg/database/dao" ) // StageKey is the key of stage diff --git a/src/core-api/pkg/cacheimpls/stage_test.go b/src/core-api/pkg/cacheimpls/stage_test.go index ac1edbce2..78fb5c15b 100644 --- a/src/core-api/pkg/cacheimpls/stage_test.go +++ b/src/core-api/pkg/cacheimpls/stage_test.go @@ -24,11 +24,11 @@ import ( "testing" "time" - "core/pkg/database/dao" - "github.com/TencentBlueKing/gopkg/cache" "github.com/TencentBlueKing/gopkg/cache/memory" "github.com/stretchr/testify/assert" + + "core/pkg/database/dao" ) func TestStageKey_Key(t *testing.T) { diff --git a/src/core-api/pkg/cacheimpls/trace.go b/src/core-api/pkg/cacheimpls/trace.go index 2f13af75a..9c2a3e0b3 100644 --- a/src/core-api/pkg/cacheimpls/trace.go +++ b/src/core-api/pkg/cacheimpls/trace.go @@ -21,11 +21,11 @@ package cacheimpls import ( "context" - "core/pkg/trace" - "github.com/TencentBlueKing/gopkg/cache" "github.com/TencentBlueKing/gopkg/cache/memory" "go.opentelemetry.io/otel/attribute" + + "core/pkg/trace" ) // tracedFuncWrapper diff --git a/src/core-api/pkg/constant/event.go b/src/core-api/pkg/constant/event.go new file mode 100644 index 000000000..9033564b4 --- /dev/null +++ b/src/core-api/pkg/constant/event.go @@ -0,0 +1,59 @@ +/* + * TencentBlueKing is pleased to support the open source community by making + * 蓝鲸智云 - API 网关(BlueKing - APIGateway) available. + * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/MIT + * + * 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. + * + * We undertake not to change the open source license (MIT license) applicable + * to the current version of the project delivered to anyone in the future. + */ + +package constant + +const ( + // dashboard + EventNameGenerateReleaseTask = "generate_release_task" + EventNameDistributeConfiguration = "distribute_configuration" + + // operator + EventNameParseConfiguration = "parse_configuration" + EventNameApplyConfiguration = "apply_configuration" + + // apisix + EventNameLoadConfiguration = "load_configuration" +) + +func GetStep(name string) int { + /** + publish event report chain: + GenerateTask-> DistributeConfiguration-> ParseConfiguration-> ApplyConfiguration-> LoadConfiguration + */ + switch name { + case EventNameGenerateReleaseTask: + return 1 + case EventNameDistributeConfiguration: + return 2 + case EventNameParseConfiguration: + return 3 + case EventNameApplyConfiguration: + return 4 + case EventNameLoadConfiguration: + return 5 + } + return 0 +} + +const ( + EventStatusSuccess = "success" // 执行成功 + EventStatusFailure = "failure" // 执行失败 + EventStatusPending = "pending" // 待执行 + EventStatusDoing = "doing" // 执行中 +) diff --git a/src/core-api/pkg/database/dao/app_gateway_permission.go b/src/core-api/pkg/database/dao/app_gateway_permission.go index f10266597..11c04f6f0 100644 --- a/src/core-api/pkg/database/dao/app_gateway_permission.go +++ b/src/core-api/pkg/database/dao/app_gateway_permission.go @@ -24,9 +24,9 @@ import ( "context" "time" - "core/pkg/database" - "github.com/jmoiron/sqlx" + + "core/pkg/database" ) // TODO: split into thinx and x, for better performance @@ -45,6 +45,10 @@ type AppGatewayPermissionManager interface { Get(ctx context.Context, bkAppCode string, gatewayID int64) (AppGatewayPermission, error) } +type appGatewayPermissionManager struct { + DB *sqlx.DB +} + // NewAppGatewayPermissionManager ... func NewAppGatewayPermissionManager() AppGatewayPermissionManager { return &appGatewayPermissionManager{ @@ -52,12 +56,12 @@ func NewAppGatewayPermissionManager() AppGatewayPermissionManager { } } -type appGatewayPermissionManager struct { - DB *sqlx.DB -} - // Get ... -func (m appGatewayPermissionManager) Get(ctx context.Context, bkAppCode string, gatewayID int64) (AppGatewayPermission, error) { +func (m appGatewayPermissionManager) Get( + ctx context.Context, + bkAppCode string, + gatewayID int64, +) (AppGatewayPermission, error) { perm := AppGatewayPermission{} query := `SELECT id, diff --git a/src/core-api/pkg/database/dao/app_resource_permission.go b/src/core-api/pkg/database/dao/app_resource_permission.go index c2b59a53a..87680866b 100644 --- a/src/core-api/pkg/database/dao/app_resource_permission.go +++ b/src/core-api/pkg/database/dao/app_resource_permission.go @@ -24,9 +24,9 @@ import ( "context" "time" - "core/pkg/database" - "github.com/jmoiron/sqlx" + + "core/pkg/database" ) // TODO: split into thinx and x, for better performance @@ -58,7 +58,12 @@ type appResourcePermissionManager struct { } // Get ... -func (m appResourcePermissionManager) Get(ctx context.Context, bkAppCode string, gatewayID int64, resourceID int64) (AppResourcePermission, error) { +func (m appResourcePermissionManager) Get( + ctx context.Context, + bkAppCode string, + gatewayID int64, + resourceID int64, +) (AppResourcePermission, error) { perm := AppResourcePermission{} query := `SELECT id, diff --git a/src/core-api/pkg/database/dao/app_resource_permission_test.go b/src/core-api/pkg/database/dao/app_resource_permission_test.go index 7a6ca5e59..d5cbafa2f 100644 --- a/src/core-api/pkg/database/dao/app_resource_permission_test.go +++ b/src/core-api/pkg/database/dao/app_resource_permission_test.go @@ -23,11 +23,11 @@ import ( "testing" "time" - "core/pkg/database" - sqlmock "github.com/DATA-DOG/go-sqlmock" "github.com/jmoiron/sqlx" "github.com/stretchr/testify/assert" + + "core/pkg/database" ) func Test_appResourcePermissionManager_Get(t *testing.T) { diff --git a/src/core-api/pkg/database/dao/gateway.go b/src/core-api/pkg/database/dao/gateway.go index e10aebc14..5e1ce6988 100644 --- a/src/core-api/pkg/database/dao/gateway.go +++ b/src/core-api/pkg/database/dao/gateway.go @@ -22,9 +22,10 @@ package dao import ( "context" - "core/pkg/database" "github.com/jmoiron/sqlx" + + "core/pkg/database" ) // TODO: split into thinx and x, for better performance @@ -40,6 +41,10 @@ type GatewayManager interface { GetByName(ctx context.Context, name string) (Gateway, error) } +type gatewayManager struct { + DB *sqlx.DB +} + // NewGatewayManager ... func NewGatewayManager() GatewayManager { return &gatewayManager{ @@ -47,10 +52,6 @@ func NewGatewayManager() GatewayManager { } } -type gatewayManager struct { - DB *sqlx.DB -} - // GetByName ... func (m gatewayManager) GetByName(ctx context.Context, name string) (Gateway, error) { gateway := Gateway{} diff --git a/src/core-api/pkg/database/dao/gateway_test.go b/src/core-api/pkg/database/dao/gateway_test.go index aea4d6775..f1be4ffa2 100644 --- a/src/core-api/pkg/database/dao/gateway_test.go +++ b/src/core-api/pkg/database/dao/gateway_test.go @@ -22,11 +22,11 @@ import ( "context" "testing" - "core/pkg/database" - sqlmock "github.com/DATA-DOG/go-sqlmock" "github.com/jmoiron/sqlx" "github.com/stretchr/testify/assert" + + "core/pkg/database" ) func Test_gatewayManager_GetByName(t *testing.T) { diff --git a/src/core-api/pkg/database/dao/jwt.go b/src/core-api/pkg/database/dao/jwt.go index c4610eafe..8e81b3dd5 100644 --- a/src/core-api/pkg/database/dao/jwt.go +++ b/src/core-api/pkg/database/dao/jwt.go @@ -22,9 +22,10 @@ package dao import ( "context" - "core/pkg/database" "github.com/jmoiron/sqlx" + + "core/pkg/database" ) // JWT ... @@ -37,6 +38,10 @@ type JWTManager interface { Get(ctx context.Context, gatewayID int64) (JWT, error) } +type jwtManager struct { + DB *sqlx.DB +} + // NewJWTManager ... func NewJWTManager() JWTManager { return &jwtManager{ @@ -44,10 +49,6 @@ func NewJWTManager() JWTManager { } } -type jwtManager struct { - DB *sqlx.DB -} - // Get ... func (m jwtManager) Get(ctx context.Context, gatewayID int64) (JWT, error) { JWT := JWT{} diff --git a/src/core-api/pkg/database/dao/jwt_test.go b/src/core-api/pkg/database/dao/jwt_test.go index bfd26f841..5904884f8 100644 --- a/src/core-api/pkg/database/dao/jwt_test.go +++ b/src/core-api/pkg/database/dao/jwt_test.go @@ -22,11 +22,11 @@ import ( "context" "testing" - "core/pkg/database" - sqlmock "github.com/DATA-DOG/go-sqlmock" "github.com/jmoiron/sqlx" "github.com/stretchr/testify/assert" + + "core/pkg/database" ) func Test_jwtManager_Get(t *testing.T) { diff --git a/src/core-api/pkg/database/dao/microgateway.go b/src/core-api/pkg/database/dao/microgateway.go index 3df11bddc..8c2ac5df7 100644 --- a/src/core-api/pkg/database/dao/microgateway.go +++ b/src/core-api/pkg/database/dao/microgateway.go @@ -24,9 +24,9 @@ import ( "context" "strings" - "core/pkg/database" - "github.com/jmoiron/sqlx" + + "core/pkg/database" ) // TODO: split into thinx and x, for better performance @@ -48,6 +48,10 @@ type MicroGatewayManager interface { Get(ctx context.Context, instanceID string) (MicroGateway, error) } +type microGatewayManager struct { + DB *sqlx.DB +} + // NewMicroGatewayManager ... func NewMicroGatewayManager() MicroGatewayManager { return µGatewayManager{ @@ -55,10 +59,6 @@ func NewMicroGatewayManager() MicroGatewayManager { } } -type microGatewayManager struct { - DB *sqlx.DB -} - // Get ... func (m microGatewayManager) Get(ctx context.Context, instanceID string) (MicroGateway, error) { // the id in database is uuid(32), the django handled the 36 to 32 by default diff --git a/src/core-api/pkg/database/dao/microgateway_test.go b/src/core-api/pkg/database/dao/microgateway_test.go index ebe171a97..20876208d 100644 --- a/src/core-api/pkg/database/dao/microgateway_test.go +++ b/src/core-api/pkg/database/dao/microgateway_test.go @@ -22,11 +22,11 @@ import ( "context" "testing" - "core/pkg/database" - sqlmock "github.com/DATA-DOG/go-sqlmock" "github.com/jmoiron/sqlx" "github.com/stretchr/testify/assert" + + "core/pkg/database" ) func Test_microGatewayManager_Get(t *testing.T) { diff --git a/src/core-api/pkg/database/dao/mock/app_gateway_permission.go b/src/core-api/pkg/database/dao/mock/app_gateway_permission.go index 45e6b871a..6b09ec5e1 100644 --- a/src/core-api/pkg/database/dao/mock/app_gateway_permission.go +++ b/src/core-api/pkg/database/dao/mock/app_gateway_permission.go @@ -6,9 +6,10 @@ package mock import ( context "context" - dao "core/pkg/database/dao" reflect "reflect" + dao "core/pkg/database/dao" + gomock "github.com/golang/mock/gomock" ) diff --git a/src/core-api/pkg/database/dao/mock/app_resource_permission.go b/src/core-api/pkg/database/dao/mock/app_resource_permission.go index 903ce77ae..03639ce20 100644 --- a/src/core-api/pkg/database/dao/mock/app_resource_permission.go +++ b/src/core-api/pkg/database/dao/mock/app_resource_permission.go @@ -6,9 +6,10 @@ package mock import ( context "context" - dao "core/pkg/database/dao" reflect "reflect" + dao "core/pkg/database/dao" + gomock "github.com/golang/mock/gomock" ) diff --git a/src/core-api/pkg/database/dao/mock/gateway.go b/src/core-api/pkg/database/dao/mock/gateway.go index be33e3a21..85b4c8cbc 100644 --- a/src/core-api/pkg/database/dao/mock/gateway.go +++ b/src/core-api/pkg/database/dao/mock/gateway.go @@ -6,9 +6,10 @@ package mock import ( context "context" - dao "core/pkg/database/dao" reflect "reflect" + dao "core/pkg/database/dao" + gomock "github.com/golang/mock/gomock" ) diff --git a/src/core-api/pkg/database/dao/mock/jwt.go b/src/core-api/pkg/database/dao/mock/jwt.go index ebfad9e52..546dedeba 100644 --- a/src/core-api/pkg/database/dao/mock/jwt.go +++ b/src/core-api/pkg/database/dao/mock/jwt.go @@ -6,9 +6,10 @@ package mock import ( context "context" - dao "core/pkg/database/dao" reflect "reflect" + dao "core/pkg/database/dao" + gomock "github.com/golang/mock/gomock" ) diff --git a/src/core-api/pkg/database/dao/mock/microgateway.go b/src/core-api/pkg/database/dao/mock/microgateway.go index 46779f3d5..f51c450d6 100644 --- a/src/core-api/pkg/database/dao/mock/microgateway.go +++ b/src/core-api/pkg/database/dao/mock/microgateway.go @@ -6,9 +6,10 @@ package mock import ( context "context" - dao "core/pkg/database/dao" reflect "reflect" + dao "core/pkg/database/dao" + gomock "github.com/golang/mock/gomock" ) diff --git a/src/core-api/pkg/database/dao/mock/publish_event.go b/src/core-api/pkg/database/dao/mock/publish_event.go new file mode 100644 index 000000000..4192fe88d --- /dev/null +++ b/src/core-api/pkg/database/dao/mock/publish_event.go @@ -0,0 +1,52 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: publish_event.go + +// Package mock is a generated GoMock package. +package mock + +import ( + context "context" + reflect "reflect" + + dao "core/pkg/database/dao" + + gomock "github.com/golang/mock/gomock" +) + +// MockPublishEventManger is a mock of PublishEventManger interface. +type MockPublishEventManger struct { + ctrl *gomock.Controller + recorder *MockPublishEventMangerMockRecorder +} + +// MockPublishEventMangerMockRecorder is the mock recorder for MockPublishEventManger. +type MockPublishEventMangerMockRecorder struct { + mock *MockPublishEventManger +} + +// NewMockPublishEventManger creates a new mock instance. +func NewMockPublishEventManger(ctrl *gomock.Controller) *MockPublishEventManger { + mock := &MockPublishEventManger{ctrl: ctrl} + mock.recorder = &MockPublishEventMangerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockPublishEventManger) EXPECT() *MockPublishEventMangerMockRecorder { + return m.recorder +} + +// Create mocks base method. +func (m *MockPublishEventManger) Create(ctx context.Context, publishEvent dao.PublishEvent) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", ctx, publishEvent) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Create indicates an expected call of Create. +func (mr *MockPublishEventMangerMockRecorder) Create(ctx, publishEvent interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockPublishEventManger)(nil).Create), ctx, publishEvent) +} diff --git a/src/core-api/pkg/database/dao/mock/release.go b/src/core-api/pkg/database/dao/mock/release.go index 8e6c8d93f..b067414c2 100644 --- a/src/core-api/pkg/database/dao/mock/release.go +++ b/src/core-api/pkg/database/dao/mock/release.go @@ -6,9 +6,10 @@ package mock import ( context "context" - dao "core/pkg/database/dao" reflect "reflect" + dao "core/pkg/database/dao" + gomock "github.com/golang/mock/gomock" ) diff --git a/src/core-api/pkg/database/dao/mock/release_history.go b/src/core-api/pkg/database/dao/mock/release_history.go new file mode 100644 index 000000000..d9cb416c8 --- /dev/null +++ b/src/core-api/pkg/database/dao/mock/release_history.go @@ -0,0 +1,52 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: release_history.go + +// Package mock is a generated GoMock package. +package mock + +import ( + context "context" + reflect "reflect" + + dao "core/pkg/database/dao" + + gomock "github.com/golang/mock/gomock" +) + +// MockReleaseHistoryManger is a mock of ReleaseHistoryManger interface. +type MockReleaseHistoryManger struct { + ctrl *gomock.Controller + recorder *MockReleaseHistoryMangerMockRecorder +} + +// MockReleaseHistoryMangerMockRecorder is the mock recorder for MockReleaseHistoryManger. +type MockReleaseHistoryMangerMockRecorder struct { + mock *MockReleaseHistoryManger +} + +// NewMockReleaseHistoryManger creates a new mock instance. +func NewMockReleaseHistoryManger(ctrl *gomock.Controller) *MockReleaseHistoryManger { + mock := &MockReleaseHistoryManger{ctrl: ctrl} + mock.recorder = &MockReleaseHistoryMangerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockReleaseHistoryManger) EXPECT() *MockReleaseHistoryMangerMockRecorder { + return m.recorder +} + +// Get mocks base method. +func (m *MockReleaseHistoryManger) Get(ctx context.Context, publishID int64) (dao.ReleaseHistory, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", ctx, publishID) + ret0, _ := ret[0].(dao.ReleaseHistory) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockReleaseHistoryMangerMockRecorder) Get(ctx, publishID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockReleaseHistoryManger)(nil).Get), ctx, publishID) +} diff --git a/src/core-api/pkg/database/dao/mock/resource_version.go b/src/core-api/pkg/database/dao/mock/resource_version.go index 012e98a66..91fa8281f 100644 --- a/src/core-api/pkg/database/dao/mock/resource_version.go +++ b/src/core-api/pkg/database/dao/mock/resource_version.go @@ -6,9 +6,10 @@ package mock import ( context "context" - dao "core/pkg/database/dao" reflect "reflect" + dao "core/pkg/database/dao" + gomock "github.com/golang/mock/gomock" ) diff --git a/src/core-api/pkg/database/dao/mock/stage.go b/src/core-api/pkg/database/dao/mock/stage.go index 999e95192..8c20293d7 100644 --- a/src/core-api/pkg/database/dao/mock/stage.go +++ b/src/core-api/pkg/database/dao/mock/stage.go @@ -6,9 +6,10 @@ package mock import ( context "context" - dao "core/pkg/database/dao" reflect "reflect" + dao "core/pkg/database/dao" + gomock "github.com/golang/mock/gomock" ) diff --git a/src/core-api/pkg/database/dao/publish_event.go b/src/core-api/pkg/database/dao/publish_event.go new file mode 100644 index 000000000..2a0687917 --- /dev/null +++ b/src/core-api/pkg/database/dao/publish_event.go @@ -0,0 +1,117 @@ +/* + * TencentBlueKing is pleased to support the open source community by making + * 蓝鲸智云 - API 网关(BlueKing - APIGateway) available. + * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/MIT + * + * 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. + * + * We undertake not to change the open source license (MIT license) applicable + * to the current version of the project delivered to anyone in the future. + */ + +package dao + +import ( + "context" + "database/sql/driver" + "encoding/json" + "errors" + "fmt" + "time" + + "github.com/go-sql-driver/mysql" + "github.com/jmoiron/sqlx" + + "core/pkg/database" +) + +//go:generate mockgen -source=$GOFILE -destination=./mock/$GOFILE -package=mock + +type PublishEvent struct { + ID int64 `db:"id"` + GatewayID int64 `db:"gateway_id"` + PublishID int64 `db:"publish_id"` + StageID int64 `db:"stage_id"` + Name string `db:"name"` + Step int `db:"step"` + Status string `db:"status"` + Detail Detail `db:"detail"` + CreatedTime time.Time `db:"created_time"` + UpdatedTime time.Time `db:"updated_time"` +} + +type Detail map[string]interface{} + +// Scan Implement the sql.Scanner interface, Scan scans the value to Detail +func (d *Detail) Scan(value interface{}) error { + bytes, ok := value.([]byte) + if !ok { + return errors.New(fmt.Sprint("Failed to unmarshal Detail value:", value)) + } + resultMap := make(Detail) + err := json.Unmarshal(bytes, &resultMap) + *d = resultMap + return err +} + +// Value Implement driver.Valuer interface, Value returns Detail value +func (d Detail) Value() (driver.Value, error) { + if len(d) == 0 { + return nil, nil + } + return json.Marshal(d) +} + +type PublishEventManger interface { + Create(ctx context.Context, publishEvent PublishEvent) (int64, error) +} + +type publishEventManager struct { + DB *sqlx.DB +} + +// NewPublishEventManger +func NewPublishEventManger() PublishEventManger { + return &publishEventManager{ + DB: database.GetDefaultDBClient().DB, + } +} + +var _ PublishEventManger = publishEventManager{} + +// Create publish event +func (p publishEventManager) Create(ctx context.Context, publishEvent PublishEvent) (int64, error) { + insertSql := `INSERT INTO core_publish_event ( + gateway_id, + publish_id, + stage_id, + name, + step, + status, + detail, + created_time, + updated_time + )VALUES (:gateway_id, :publish_id, :stage_id, :name, :step, :status, :detail,:created_time,:updated_time)` + query, args, err := sqlx.Named(insertSql, publishEvent) + if err != nil { + return 0, err + } + result, err := database.SqxExec(ctx, p.DB, query, args...) + if err != nil { + // make sure err is a mysql.MySQLError. + if errMySQL, ok := err.(*mysql.MySQLError); ok { + if errMySQL.Number == database.DuplicateErrCode { + return 0, fmt.Errorf("insert event duplicated err: %w", err) + } + } + return 0, fmt.Errorf("failed to insert publish event: %w", err) + } + return result.LastInsertId() +} diff --git a/src/core-api/pkg/database/dao/publish_event_test.go b/src/core-api/pkg/database/dao/publish_event_test.go new file mode 100644 index 000000000..22259dede --- /dev/null +++ b/src/core-api/pkg/database/dao/publish_event_test.go @@ -0,0 +1,53 @@ +/* + * TencentBlueKing is pleased to support the open source community by making + * 蓝鲸智云 - API 网关(BlueKing - APIGateway) available. + * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/MIT + * + * 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. + * + * We undertake not to change the open source license (MIT license) applicable + * to the current version of the project delivered to anyone in the future. + */ + +package dao + +import ( + "context" + "testing" + + sqlmock "github.com/DATA-DOG/go-sqlmock" + "github.com/jmoiron/sqlx" + "github.com/stretchr/testify/assert" + + "core/pkg/constant" + "core/pkg/database" +) + +func Test_publishEventManager_Create(t *testing.T) { + database.RunWithMock(t, func(db *sqlx.DB, mock sqlmock.Sqlmock, t *testing.T) { + mockQuery := `^INSERT INTO core_publish_event` + record := PublishEvent{ + GatewayID: 67, + PublishID: 89, + StageID: 12, + Name: constant.EventNameApplyConfiguration, + Step: 1, + Status: constant.EventStatusSuccess, + Detail: map[string]interface{}{"err_msg": "success"}, + } + mock.ExpectExec(mockQuery).WillReturnResult( + sqlmock.NewResult(1, 1)) + + manager := &publishEventManager{DB: db} + result, err := manager.Create(context.Background(), record) + assert.NoError(t, err, "insert db fail.") + assert.Equal(t, result, int64(1)) + }) +} diff --git a/src/core-api/pkg/database/dao/release.go b/src/core-api/pkg/database/dao/release.go index ec6786950..a14d4eb10 100644 --- a/src/core-api/pkg/database/dao/release.go +++ b/src/core-api/pkg/database/dao/release.go @@ -22,9 +22,10 @@ package dao import ( "context" - "core/pkg/database" "github.com/jmoiron/sqlx" + + "core/pkg/database" ) // TODO: split into thinx and x, for better performance @@ -45,6 +46,10 @@ type ReleaseManager interface { Get(ctx context.Context, gatewayID int64, stageID int64) (Release, error) } +type releaseManager struct { + DB *sqlx.DB +} + // NewReleaseManager ... func NewReleaseManager() ReleaseManager { return &releaseManager{ @@ -52,10 +57,6 @@ func NewReleaseManager() ReleaseManager { } } -type releaseManager struct { - DB *sqlx.DB -} - // Get ... func (m releaseManager) Get(ctx context.Context, gatewayID int64, stageID int64) (Release, error) { Release := Release{} diff --git a/src/core-api/pkg/database/dao/release_history.go b/src/core-api/pkg/database/dao/release_history.go new file mode 100644 index 000000000..0644eda99 --- /dev/null +++ b/src/core-api/pkg/database/dao/release_history.go @@ -0,0 +1,79 @@ +/* + * TencentBlueKing is pleased to support the open source community by making + * 蓝鲸智云 - API 网关(BlueKing - APIGateway) available. + * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/MIT + * + * 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. + * + * We undertake not to change the open source license (MIT license) applicable + * to the current version of the project delivered to anyone in the future. + */ + +package dao + +import ( + "context" + "database/sql" + "errors" + "fmt" + "time" + + "github.com/jmoiron/sqlx" + + "core/pkg/database" +) + +//go:generate mockgen -source=$GOFILE -destination=./mock/$GOFILE -package=mock + +type ReleaseHistory struct { + ID int64 `db:"id"` + GatewayID int64 `db:"api_id"` + StageID int `db:"stage_id"` + ResourceVersionID int `db:"resource_version_id"` + CreatedTime time.Time `db:"created_time"` + UpdatedTime time.Time `db:"updated_time"` +} + +type ReleaseHistoryManger interface { + Get(ctx context.Context, publishID int64) (ReleaseHistory, error) +} + +// NewReleaseHistoryManger +func NewReleaseHistoryManger() ReleaseHistoryManger { + return &releaseHistoryManager{ + DB: database.GetDefaultDBClient().DB, + } +} + +type releaseHistoryManager struct { + DB *sqlx.DB +} + +var _ ReleaseHistoryManger = releaseHistoryManager{} + +// Get release history by id +func (p releaseHistoryManager) Get(ctx context.Context, publishID int64) (ReleaseHistory, error) { + query := `SELECT + stage_id, + api_id, + created_time, + updated_time + FROM core_release_history + WHERE id = ?` + var releaseHistory ReleaseHistory + err := database.SqlxGet(ctx, p.DB, &releaseHistory, query, publishID) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return releaseHistory, fmt.Errorf("release[ id:%d ] history not found: %w", publishID, err) + } + return releaseHistory, fmt.Errorf("get release[ id:%d ] history err: %w", publishID, err) + } + return releaseHistory, nil +} diff --git a/src/core-api/pkg/database/dao/release_history_test.go b/src/core-api/pkg/database/dao/release_history_test.go new file mode 100644 index 000000000..180d23c5a --- /dev/null +++ b/src/core-api/pkg/database/dao/release_history_test.go @@ -0,0 +1,62 @@ +/* + * TencentBlueKing is pleased to support the open source community by making + * 蓝鲸智云 - API 网关(BlueKing - APIGateway) available. + * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/MIT + * + * 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. + * + * We undertake not to change the open source license (MIT license) applicable + * to the current version of the project delivered to anyone in the future. + */ + +package dao + +import ( + "context" + "testing" + "time" + + sqlmock "github.com/DATA-DOG/go-sqlmock" + "github.com/jmoiron/sqlx" + "github.com/stretchr/testify/assert" + + "core/pkg/database" +) + +func Test_releaseHistoryManager_Get(t *testing.T) { + database.RunWithMock(t, func(db *sqlx.DB, mock sqlmock.Sqlmock, t *testing.T) { + mockQuery := `^SELECT + stage_id, + api_id, + created_time, + updated_time + FROM core_release_history + WHERE id = ?` + publishID := 16 + record := ReleaseHistory{ + ID: 16, + CreatedTime: time.Time{}, + UpdatedTime: time.Time{}, + GatewayID: 23, + ResourceVersionID: 23, + StageID: 23, + } + mockData := []interface{}{ + record, + } + mockRows := database.NewMockRows(mock, mockData...) + mock.ExpectQuery(mockQuery).WithArgs(publishID).WillReturnRows(mockRows) + + manager := &releaseHistoryManager{DB: db} + p, err := manager.Get(context.Background(), int64(publishID)) + assert.NoError(t, err, "query from db fail.") + assert.Equal(t, record.ID, p.ID) + }) +} diff --git a/src/core-api/pkg/database/dao/release_test.go b/src/core-api/pkg/database/dao/release_test.go index e910804aa..c07990b9d 100644 --- a/src/core-api/pkg/database/dao/release_test.go +++ b/src/core-api/pkg/database/dao/release_test.go @@ -22,11 +22,11 @@ import ( "context" "testing" - "core/pkg/database" - sqlmock "github.com/DATA-DOG/go-sqlmock" "github.com/jmoiron/sqlx" "github.com/stretchr/testify/assert" + + "core/pkg/database" ) func Test_releaseManager_Get(t *testing.T) { diff --git a/src/core-api/pkg/database/dao/resource_version.go b/src/core-api/pkg/database/dao/resource_version.go index fb300f0bb..28635710f 100644 --- a/src/core-api/pkg/database/dao/resource_version.go +++ b/src/core-api/pkg/database/dao/resource_version.go @@ -22,9 +22,10 @@ package dao import ( "context" - "core/pkg/database" "github.com/jmoiron/sqlx" + + "core/pkg/database" ) // TODO: split into thinx and x, for better performance diff --git a/src/core-api/pkg/database/dao/resource_version_test.go b/src/core-api/pkg/database/dao/resource_version_test.go index fbc96b2ce..38d6a4bed 100644 --- a/src/core-api/pkg/database/dao/resource_version_test.go +++ b/src/core-api/pkg/database/dao/resource_version_test.go @@ -22,11 +22,11 @@ import ( "context" "testing" - "core/pkg/database" - sqlmock "github.com/DATA-DOG/go-sqlmock" "github.com/jmoiron/sqlx" "github.com/stretchr/testify/assert" + + "core/pkg/database" ) func Test_resourceVersionManager_Get(t *testing.T) { diff --git a/src/core-api/pkg/database/dao/stage.go b/src/core-api/pkg/database/dao/stage.go index ed2837987..cde2d6fc9 100644 --- a/src/core-api/pkg/database/dao/stage.go +++ b/src/core-api/pkg/database/dao/stage.go @@ -22,9 +22,10 @@ package dao import ( "context" - "core/pkg/database" "github.com/jmoiron/sqlx" + + "core/pkg/database" ) // TODO: split into thinx and x, for better performance @@ -40,6 +41,10 @@ type StageManager interface { GetByName(ctx context.Context, gatewayID int64, stageName string) (Stage, error) } +type stageManager struct { + DB *sqlx.DB +} + // NewStageManager ... func NewStageManager() StageManager { return &stageManager{ @@ -47,10 +52,6 @@ func NewStageManager() StageManager { } } -type stageManager struct { - DB *sqlx.DB -} - // GetByName ... func (m stageManager) GetByName(ctx context.Context, gatewayID int64, stageName string) (Stage, error) { Stage := Stage{} diff --git a/src/core-api/pkg/database/dao/stage_test.go b/src/core-api/pkg/database/dao/stage_test.go index cf542be9b..a89b9603a 100644 --- a/src/core-api/pkg/database/dao/stage_test.go +++ b/src/core-api/pkg/database/dao/stage_test.go @@ -22,11 +22,11 @@ import ( "context" "testing" - "core/pkg/database" - sqlmock "github.com/DATA-DOG/go-sqlmock" "github.com/jmoiron/sqlx" "github.com/stretchr/testify/assert" + + "core/pkg/database" ) func Test_stageManager_GetByName(t *testing.T) { diff --git a/src/core-api/pkg/database/dbmock.go b/src/core-api/pkg/database/dbmock.go index c4405bbf7..a59adb7df 100644 --- a/src/core-api/pkg/database/dbmock.go +++ b/src/core-api/pkg/database/dbmock.go @@ -23,11 +23,10 @@ import ( "reflect" "testing" - "core/pkg/logging" - sqlmock "github.com/DATA-DOG/go-sqlmock" "github.com/jmoiron/sqlx" - // log "github.com/sirupsen/logrus" + + "core/pkg/logging" ) // NewMockSqlxDB ... diff --git a/src/core-api/pkg/database/init.go b/src/core-api/pkg/database/init.go index 615b2eac1..6e91030af 100644 --- a/src/core-api/pkg/database/init.go +++ b/src/core-api/pkg/database/init.go @@ -21,11 +21,11 @@ package database import ( "sync" - "core/pkg/config" - "github.com/dlmiddlecote/sqlstats" "github.com/jmoiron/sqlx" "github.com/prometheus/client_golang/prometheus" + + "core/pkg/config" ) // NOTE: 独立/原子/单一 @@ -43,7 +43,7 @@ func InitDBClients(defaultDBConfig *config.Database, tracerConfig config.Tracing if DefaultDBClient == nil { defaultDBClientOnce.Do(func() { DefaultDBClient = NewDBClient(defaultDBConfig) - //set db trace + // set db trace DefaultDBClient.SetTraceEnabled(tracerConfig.DBAPIEnabled()) if err := DefaultDBClient.Connect(); err != nil { panic(err) diff --git a/src/core-api/pkg/database/mysql.go b/src/core-api/pkg/database/mysql.go index f48666e9e..f771e85d1 100644 --- a/src/core-api/pkg/database/mysql.go +++ b/src/core-api/pkg/database/mysql.go @@ -23,13 +23,13 @@ import ( "net/url" "time" - "core/pkg/config" - "core/pkg/logging" - "github.com/jmoiron/sqlx" "github.com/uptrace/opentelemetry-go-extra/otelsql" "github.com/uptrace/opentelemetry-go-extra/otelsqlx" - "go.opentelemetry.io/otel/semconv/v1.10.0" + semconv "go.opentelemetry.io/otel/semconv/v1.10.0" + + "core/pkg/config" + "core/pkg/logging" ) // ! set the default https://making.pusher.com/production-ready-connection-pooling-in-go/ @@ -45,6 +45,11 @@ const ( defaultConnMaxLifetime = 10 * time.Minute ) +const ( + // sql errCode + DuplicateErrCode uint16 = 1062 +) + // DBClient MySQL DB Instance type DBClient struct { name string diff --git a/src/core-api/pkg/database/sqlx.go b/src/core-api/pkg/database/sqlx.go index 3af0c689e..c22f7463a 100644 --- a/src/core-api/pkg/database/sqlx.go +++ b/src/core-api/pkg/database/sqlx.go @@ -20,12 +20,16 @@ package database import ( "context" + "database/sql" "time" "github.com/jmoiron/sqlx" ) -type queryFunc func(ctx context.Context, db *sqlx.DB, dest interface{}, query string, args ...interface{}) error +type ( + queryFunc func(ctx context.Context, db *sqlx.DB, dest interface{}, query string, args ...interface{}) error + execFunc func(ctx context.Context, db *sqlx.DB, query string, args ...any) (sql.Result, error) +) func queryTimer(f queryFunc) queryFunc { return func(ctx context.Context, db *sqlx.DB, dest interface{}, query string, args ...interface{}) error { @@ -36,6 +40,15 @@ func queryTimer(f queryFunc) queryFunc { } } +func execTimer(f execFunc) execFunc { + return func(ctx context.Context, db *sqlx.DB, query string, args ...any) (sql.Result, error) { + start := time.Now() + defer logSlowSQL(start, query, args) + // NOTE: must be args... + return f(ctx, db, query, args...) + } +} + func sqlxSelectFunc(ctx context.Context, db *sqlx.DB, dest interface{}, query string, args ...interface{}) error { query, args, err := sqlx.In(query, args...) if err != nil { @@ -59,6 +72,10 @@ func sqlxGetFunc(ctx context.Context, db *sqlx.DB, dest interface{}, query strin return err } +func sqlxExecFunc(ctx context.Context, db *sqlx.DB, query string, args ...any) (sql.Result, error) { + return db.ExecContext(ctx, query, args...) +} + // note: if you want to add more functions, please take a look at // https://github.com/TencentBlueKing/bk-iam/blob/master/pkg/database/sqlx.go @@ -66,4 +83,5 @@ func sqlxGetFunc(ctx context.Context, db *sqlx.DB, dest interface{}, query strin var ( SqlxSelect = queryTimer(sqlxSelectFunc) SqlxGet = queryTimer(sqlxGetFunc) + SqxExec = execTimer(sqlxExecFunc) ) diff --git a/src/core-api/pkg/database/utils.go b/src/core-api/pkg/database/utils.go index 1c549b32b..a8dcdff0a 100644 --- a/src/core-api/pkg/database/utils.go +++ b/src/core-api/pkg/database/utils.go @@ -24,12 +24,12 @@ import ( "strings" "time" - "core/pkg/logging" - "github.com/TencentBlueKing/gopkg/stringx" "github.com/jmoiron/sqlx" jsoniter "github.com/json-iterator/go" "go.uber.org/zap" + + "core/pkg/logging" ) // ArgsTruncateLength ... diff --git a/src/core-api/pkg/logging/init.go b/src/core-api/pkg/logging/init.go index b61a19fad..3838736c4 100644 --- a/src/core-api/pkg/logging/init.go +++ b/src/core-api/pkg/logging/init.go @@ -25,6 +25,7 @@ import ( "time" "go.uber.org/zap" + "go.uber.org/zap/zapcore" "core/pkg/config" diff --git a/src/core-api/pkg/logging/writer.go b/src/core-api/pkg/logging/writer.go index a12b86946..7fa311c6f 100644 --- a/src/core-api/pkg/logging/writer.go +++ b/src/core-api/pkg/logging/writer.go @@ -27,7 +27,7 @@ import ( "strconv" "strings" - "gopkg.in/natefinch/lumberjack.v2" + lumberjack "gopkg.in/natefinch/lumberjack.v2" ) func getWriter(writerType string, settings map[string]string) (io.Writer, error) { diff --git a/src/core-api/pkg/middleware/logger_test.go b/src/core-api/pkg/middleware/logger_test.go index 6fb9d1d85..d5993c906 100644 --- a/src/core-api/pkg/middleware/logger_test.go +++ b/src/core-api/pkg/middleware/logger_test.go @@ -23,12 +23,12 @@ import ( "net/http/httptest" "testing" + "github.com/gin-gonic/gin" + "github.com/stretchr/testify/assert" + "core/pkg/config" "core/pkg/logging" "core/pkg/util" - - "github.com/gin-gonic/gin" - "github.com/stretchr/testify/assert" ) func TestAPILogger(t *testing.T) { diff --git a/src/core-api/pkg/middleware/micro_gateway_instance.go b/src/core-api/pkg/middleware/micro_gateway_instance.go index 1e86d9163..d93701e6b 100644 --- a/src/core-api/pkg/middleware/micro_gateway_instance.go +++ b/src/core-api/pkg/middleware/micro_gateway_instance.go @@ -27,7 +27,8 @@ import ( "core/pkg/util" ) -// MicroGatewayInstanceMiddleware is the middleware to verify the micro gateway instance by instance id and instance secret +// MicroGatewayInstanceMiddleware is the middleware to verify the micro gateway instance by instance id and instance +// secret func MicroGatewayInstanceMiddleware() gin.HandlerFunc { return func(c *gin.Context) { instanceID := c.GetHeader("X-Bk-Micro-Gateway-Instance-Id") diff --git a/src/core-api/pkg/middleware/request_id.go b/src/core-api/pkg/middleware/request_id.go index 22a39c252..8c1d3d3de 100644 --- a/src/core-api/pkg/middleware/request_id.go +++ b/src/core-api/pkg/middleware/request_id.go @@ -19,9 +19,9 @@ package middleware import ( - "core/pkg/util" - "github.com/gin-gonic/gin" + + "core/pkg/util" ) // RequestIDHeaderKey is a key to set the request id in header diff --git a/src/core-api/pkg/server/router.go b/src/core-api/pkg/server/router.go index a88948e9c..82a56e1c4 100644 --- a/src/core-api/pkg/server/router.go +++ b/src/core-api/pkg/server/router.go @@ -22,14 +22,14 @@ import ( "fmt" "net/http" + "github.com/gin-gonic/gin" + "github.com/prometheus/client_golang/prometheus/promhttp" + "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" + "core/pkg/api/microgateway" "core/pkg/config" "core/pkg/database" "core/pkg/middleware" - - "github.com/gin-gonic/gin" - "github.com/prometheus/client_golang/prometheus/promhttp" - "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" ) func checkDatabase(dbConfig *config.Database) error { @@ -86,6 +86,6 @@ func NewRouter(cfg *config.Config) *gin.Engine { microGatewayRouter.Use(middleware.MicroGatewayInstanceMiddleware()) microGatewayRouter.GET("/:micro_gateway_instance_id/permissions/", microgateway.QueryPermission) microGatewayRouter.GET("/:micro_gateway_instance_id/public_keys/", microgateway.QueryPublicKey) - + microGatewayRouter.POST("/release/:publish_id/events/", microgateway.ReportPublishEvent) return router } diff --git a/src/core-api/pkg/server/router_test.go b/src/core-api/pkg/server/router_test.go index f57aa123d..515ac81fd 100644 --- a/src/core-api/pkg/server/router_test.go +++ b/src/core-api/pkg/server/router_test.go @@ -21,9 +21,9 @@ package server import ( "testing" - "core/pkg/config" - "github.com/stretchr/testify/assert" + + "core/pkg/config" ) func TestNewRouter(t *testing.T) { diff --git a/src/core-api/pkg/service/app_permission.go b/src/core-api/pkg/service/app_permission.go index 520baf231..ab299f279 100644 --- a/src/core-api/pkg/service/app_permission.go +++ b/src/core-api/pkg/service/app_permission.go @@ -37,7 +37,10 @@ const ( // AppPermissionService is the interface of app permission service type AppPermissionService interface { - Query(ctx context.Context, instanceID, gatewayName, stageName, resourceName, appCode string) (map[string]int64, error) + Query( + ctx context.Context, + instanceID, gatewayName, stageName, resourceName, appCode string, + ) (map[string]int64, error) } type appPermissionService struct { @@ -166,8 +169,13 @@ func (s *appPermissionService) Query( return permissions, nil } - // 2.2 query teh app-resource permission - resourcePermissionExpiredAt, err := cacheimpls.GetAppResourcePermissionExpiredAt(ctx, appCode, gatewayID, resourceID) + // 2.2 query app-resource permission + resourcePermissionExpiredAt, err := cacheimpls.GetAppResourcePermissionExpiredAt( + ctx, + appCode, + gatewayID, + resourceID, + ) if err != nil { return nil, fmt.Errorf( "call GetAppResourcePermissionExpiredAt fail: %w, appCode=%s, gatewayID=%d, resourceID=%d", @@ -227,7 +235,12 @@ func getStageID(ctx context.Context, gatewayID int64, stageName string) (int64, return stage.ID, nil } -func getResourceIDByName(ctx context.Context, gatewayID int64, stageID int64, resourceName string) (resourceID int64, ok bool, err error) { +func getResourceIDByName( + ctx context.Context, + gatewayID int64, + stageID int64, + resourceName string, +) (resourceID int64, ok bool, err error) { // NOTE: there got no resourceID in private Gateway(isShared=False), only have resourceName // so, we should get resourceID by resourceName // 1. get `Release` by gatewayID and stageID, release has a reference field `resource_version_id ` to ResourceVersion @@ -254,5 +267,6 @@ func getResourceIDByName(ctx context.Context, gatewayID int64, stageID int64, re // 2.2 get resource id resourceID, ok = resourceNameToID[resourceName] + //nolint return } diff --git a/src/core-api/pkg/service/app_permission_test.go b/src/core-api/pkg/service/app_permission_test.go index f87b94450..a1e1928cc 100644 --- a/src/core-api/pkg/service/app_permission_test.go +++ b/src/core-api/pkg/service/app_permission_test.go @@ -23,12 +23,12 @@ import ( "errors" "time" - "core/pkg/cacheimpls" - "core/pkg/database/dao" - - "github.com/agiledragon/gomonkey/v2" + gomonkey "github.com/agiledragon/gomonkey/v2" . "github.com/onsi/ginkgo/v2" "github.com/stretchr/testify/assert" + + "core/pkg/cacheimpls" + "core/pkg/database/dao" ) var _ = Describe("AppPermissionService", func() { @@ -350,7 +350,14 @@ var _ = Describe("AppPermissionService", func() { ) svc := &appPermissionService{} - permissions, err := svc.Query(context.Background(), instanceID, gatewayName, stageName, resourceName, appCode) + permissions, err := svc.Query( + context.Background(), + instanceID, + gatewayName, + stageName, + resourceName, + appCode, + ) assert.NoError(GinkgoT(), err) assert.Equal(GinkgoT(), int64(123), permissions[gatewayName+":-:"+appCode]) @@ -373,7 +380,14 @@ var _ = Describe("AppPermissionService", func() { ) svc := &appPermissionService{} - permissions, err := svc.Query(context.Background(), instanceID, gatewayName, stageName, resourceName, appCode) + permissions, err := svc.Query( + context.Background(), + instanceID, + gatewayName, + stageName, + resourceName, + appCode, + ) assert.NoError(GinkgoT(), err) assert.Equal(GinkgoT(), expiredAt, permissions[gatewayName+":-:"+appCode]) diff --git a/src/core-api/pkg/service/mock/publish_event.go b/src/core-api/pkg/service/mock/publish_event.go new file mode 100644 index 000000000..6ac6776de --- /dev/null +++ b/src/core-api/pkg/service/mock/publish_event.go @@ -0,0 +1,51 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: publish_event.go + +// Package mock is a generated GoMock package. +package mock + +import ( + context "context" + reflect "reflect" + + service "core/pkg/service" + + gomock "github.com/golang/mock/gomock" +) + +// MockPublishEventService is a mock of PublishEventService interface. +type MockPublishEventService struct { + ctrl *gomock.Controller + recorder *MockPublishEventServiceMockRecorder +} + +// MockPublishEventServiceMockRecorder is the mock recorder for MockPublishEventService. +type MockPublishEventServiceMockRecorder struct { + mock *MockPublishEventService +} + +// NewMockPublishEventService creates a new mock instance. +func NewMockPublishEventService(ctrl *gomock.Controller) *MockPublishEventService { + mock := &MockPublishEventService{ctrl: ctrl} + mock.recorder = &MockPublishEventServiceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockPublishEventService) EXPECT() *MockPublishEventServiceMockRecorder { + return m.recorder +} + +// Report mocks base method. +func (m *MockPublishEventService) Report(ctx context.Context, event service.Event) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Report", ctx, event) + ret0, _ := ret[0].(error) + return ret0 +} + +// Report indicates an expected call of Report. +func (mr *MockPublishEventServiceMockRecorder) Report(ctx, event interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Report", reflect.TypeOf((*MockPublishEventService)(nil).Report), ctx, event) +} diff --git a/src/core-api/pkg/service/public_key.go b/src/core-api/pkg/service/public_key.go index e876e7906..c912edf0a 100644 --- a/src/core-api/pkg/service/public_key.go +++ b/src/core-api/pkg/service/public_key.go @@ -22,6 +22,7 @@ package service import ( "context" + "core/pkg/cacheimpls" "core/pkg/database/dao" ) diff --git a/src/core-api/pkg/service/public_key_test.go b/src/core-api/pkg/service/public_key_test.go index 7f3c3e9b5..349c358ef 100644 --- a/src/core-api/pkg/service/public_key_test.go +++ b/src/core-api/pkg/service/public_key_test.go @@ -22,13 +22,13 @@ import ( "context" "errors" - "core/pkg/cacheimpls" - "core/pkg/database/dao/mock" - - "github.com/agiledragon/gomonkey/v2" + gomonkey "github.com/agiledragon/gomonkey/v2" "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo/v2" "github.com/stretchr/testify/assert" + + "core/pkg/cacheimpls" + "core/pkg/database/dao/mock" ) var _ = Describe("GatewayPublicKeyService", func() { diff --git a/src/core-api/pkg/service/publish_event.go b/src/core-api/pkg/service/publish_event.go new file mode 100644 index 000000000..fb78eadf6 --- /dev/null +++ b/src/core-api/pkg/service/publish_event.go @@ -0,0 +1,96 @@ +/* + * TencentBlueKing is pleased to support the open source community by making + * 蓝鲸智云 - API 网关(BlueKing - APIGateway) available. + * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/MIT + * + * 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. + * + * We undertake not to change the open source license (MIT license) applicable + * to the current version of the project delivered to anyone in the future. + */ + +package service + +import ( + "context" + "fmt" + "time" + + "core/pkg/cacheimpls" + "core/pkg/constant" + "core/pkg/database/dao" +) + +const ( + eventExpireTime = time.Hour +) + +//go:generate mockgen -source=$GOFILE -destination=./mock/$GOFILE -package=mock + +type PublishEventService interface { + Report(ctx context.Context, event Event) error +} + +type publishEventService struct { + publishEventManager dao.PublishEventManger +} + +type Event struct { + Gateway string + Stage string + Name string + Status string + PublishID int64 + DetailMap map[string]interface{} +} + +var _ PublishEventService = publishEventService{} + +func NewPublishEventService() PublishEventService { + return &publishEventService{ + publishEventManager: dao.NewPublishEventManger(), + } +} + +func (p publishEventService) Report(ctx context.Context, event Event) error { + // get release history info by publish id + releaseHistory, err := cacheimpls.GetReleaseHistory(ctx, event.PublishID) + if err != nil { + return fmt.Errorf("gateway[%s] get Stage [%s] release history by publish_id:%d failed, err: %w", + event.Gateway, event.Stage, event.PublishID, err) + } + // For events that have passed for a long time, filter and lose it + if time.Since(releaseHistory.CreatedTime) > eventExpireTime { + return fmt.Errorf("gateway[%s] get Stage [%s] event has passed for a long time, publish id: %d", + event.Gateway, event.Stage, event.PublishID) + } + // determine whether the event is reported + // get Stage id + stageInfo, err := cacheimpls.GetStage(ctx, releaseHistory.GatewayID, event.Stage) + if err != nil { + return fmt.Errorf("gateway[%s] get Stage[%s] info failed, err: %w", event.Gateway, event.Stage, err) + } + // create event + publishEvent := dao.PublishEvent{ + PublishID: event.PublishID, + StageID: stageInfo.ID, + Name: event.Name, + Status: event.Status, + Detail: event.DetailMap, + Step: constant.GetStep(event.Name), + CreatedTime: time.Now(), + UpdatedTime: time.Now(), + } + _, err = p.publishEventManager.Create(ctx, publishEvent) + if err != nil { + return fmt.Errorf("create event failed, err: %w", err) + } + return nil +} diff --git a/src/core-api/pkg/service/publish_event_test.go b/src/core-api/pkg/service/publish_event_test.go new file mode 100644 index 000000000..4c1c4f651 --- /dev/null +++ b/src/core-api/pkg/service/publish_event_test.go @@ -0,0 +1,175 @@ +/* + * TencentBlueKing is pleased to support the open source community by making + * 蓝鲸智云 - API 网关(BlueKing - APIGateway) available. + * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/MIT + * + * 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. + * + * We undertake not to change the open source license (MIT license) applicable + * to the current version of the project delivered to anyone in the future. + */ + +package service + +import ( + "context" + "errors" + "time" + + gomonkey "github.com/agiledragon/gomonkey/v2" + "github.com/go-sql-driver/mysql" + "github.com/golang/mock/gomock" + . "github.com/onsi/ginkgo/v2" + "github.com/stretchr/testify/assert" + + "core/pkg/cacheimpls" + "core/pkg/constant" + "core/pkg/database" + "core/pkg/database/dao" + "core/pkg/database/dao/mock" +) + +var _ = Describe("PublishEventService", func() { + Describe("publish event report", func() { + var patches *gomonkey.Patches + var ctl *gomock.Controller + var ctx context.Context + var svc PublishEventService + var event Event + var releaseHistory dao.ReleaseHistory + var stage dao.Stage + + var mockPublishEventManager *mock.MockPublishEventManger + BeforeEach(func() { + patches = gomonkey.NewPatches() + ctl = gomock.NewController(GinkgoT()) + ctx = context.Background() + event = Event{ + Gateway: "dev", + Stage: "test", + Name: constant.EventNameLoadConfiguration, + Status: constant.EventStatusFailure, + PublishID: 1, + DetailMap: nil, + } + mockPublishEventManager = mock.NewMockPublishEventManger(ctl) + svc = publishEventService{ + publishEventManager: mockPublishEventManager, + } + + // mock data + releaseHistory = dao.ReleaseHistory{ + ID: 1, + CreatedTime: time.Now().Add(time.Hour * -24), + UpdatedTime: time.Now().Add(time.Hour * -24), + GatewayID: 12, + ResourceVersionID: 13, + StageID: 1, + } + + stage = dao.Stage{ + ID: 1, + Name: "stage", + } + }) + AfterEach(func() { + ctl.Finish() + patches.Reset() + }) + + It("error: release history not found", func() { + patches.ApplyFunc( + cacheimpls.GetReleaseHistory, + func(ctx context.Context, publishID int64) (dao.ReleaseHistory, error) { + return dao.ReleaseHistory{}, errors.New("get release history fail") + }, + ) + err := svc.Report(ctx, event) + assert.Error(GinkgoT(), err) + assert.Contains(GinkgoT(), err.Error(), "release history by publish_id:1 failed") + }) + + It("error: event has expire", func() { + releaseHistory.CreatedTime = time.Now().Add(time.Hour * -3) + patches.ApplyFunc( + cacheimpls.GetReleaseHistory, + func(ctx context.Context, publishID int64) (dao.ReleaseHistory, error) { + return releaseHistory, nil + }, + ) + err := svc.Report(ctx, event) + assert.Error(GinkgoT(), err) + assert.Contains(GinkgoT(), err.Error(), "event has passed for a long time") + }) + + It("error: stage not found", func() { + releaseHistory.CreatedTime = time.Now() + patches.ApplyFunc( + cacheimpls.GetReleaseHistory, + func(ctx context.Context, publishID int64) (dao.ReleaseHistory, error) { + return releaseHistory, nil + }, + ) + patches.ApplyFunc( + cacheimpls.GetStage, + func(ctx context.Context, gatewayID int64, name string) (dao.Stage, error) { + return dao.Stage{}, errors.New("stage not found") + }, + ) + err := svc.Report(ctx, event) + assert.Error(GinkgoT(), err) + assert.Contains(GinkgoT(), err.Error(), "get Stage[test] info failed") + }) + + It("error: duplicate report", func() { + releaseHistory.CreatedTime = time.Now() + patches.ApplyFunc( + cacheimpls.GetReleaseHistory, + func(ctx context.Context, publishID int64) (dao.ReleaseHistory, error) { + return releaseHistory, nil + }, + ) + patches.ApplyFunc( + cacheimpls.GetStage, + func(ctx context.Context, gatewayID int64, name string) (dao.Stage, error) { + return stage, nil + }, + ) + mockPublishEventManager.EXPECT().Create(ctx, gomock.Any()).Return( + int64(0), + &mysql.MySQLError{ + Number: database.DuplicateErrCode, + }) + err := svc.Report(ctx, event) + assert.Error(GinkgoT(), err) + assert.Contains(GinkgoT(), err.Error(), "create event failed, err:") + }) + It("ok: report success", func() { + releaseHistory.CreatedTime = time.Now() + patches.ApplyFunc( + cacheimpls.GetReleaseHistory, + func(ctx context.Context, publishID int64) (dao.ReleaseHistory, error) { + return releaseHistory, nil + }, + ) + patches.ApplyFunc( + cacheimpls.GetStage, + func(ctx context.Context, gatewayID int64, name string) (dao.Stage, error) { + return stage, nil + }, + ) + mockPublishEventManager.EXPECT().Create(ctx, gomock.Any()).Return( + int64(1), + nil) + err := svc.Report(ctx, event) + assert.NoError(GinkgoT(), err) + }) + }) +}) diff --git a/src/core-api/pkg/trace/init.go b/src/core-api/pkg/trace/init.go index e59a78773..56569f039 100644 --- a/src/core-api/pkg/trace/init.go +++ b/src/core-api/pkg/trace/init.go @@ -23,8 +23,6 @@ import ( "fmt" "sync" - "core/pkg/config" - "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" @@ -34,6 +32,8 @@ import ( "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.10.0" tc "go.opentelemetry.io/otel/trace" + + "core/pkg/config" ) const ( @@ -131,7 +131,7 @@ func getTraceSampler(samplerStrategy string, ratio float64) trace.TracerProvider case sampleTypeParentBaseAlwaysOn: return trace.WithSampler(trace.ParentBased(trace.AlwaysSample())) default: - //TraceIDRatioBased samples + // TraceIDRatioBased samples return trace.WithSampler(trace.TraceIDRatioBased(ratio)) } } diff --git a/src/core-api/pkg/util/request_test.go b/src/core-api/pkg/util/request_test.go index b09473a56..0552d9968 100644 --- a/src/core-api/pkg/util/request_test.go +++ b/src/core-api/pkg/util/request_test.go @@ -21,11 +21,11 @@ package util_test import ( "net/http" - "core/pkg/util" - "github.com/gin-gonic/gin" . "github.com/onsi/ginkgo/v2" "github.com/stretchr/testify/assert" + + "core/pkg/util" ) var _ = Describe("Request", func() { diff --git a/src/core-api/pkg/util/response_test.go b/src/core-api/pkg/util/response_test.go index 5be543fd1..020c2d6f2 100644 --- a/src/core-api/pkg/util/response_test.go +++ b/src/core-api/pkg/util/response_test.go @@ -26,11 +26,11 @@ import ( "net/http" "net/http/httptest" - "core/pkg/util" - "github.com/gin-gonic/gin" . "github.com/onsi/ginkgo/v2" "github.com/stretchr/testify/assert" + + "core/pkg/util" ) func readResponse(w *httptest.ResponseRecorder) map[string]interface{} { diff --git a/src/core-api/pkg/util/string_test.go b/src/core-api/pkg/util/string_test.go index 3f8f9441c..f4b0b48ef 100644 --- a/src/core-api/pkg/util/string_test.go +++ b/src/core-api/pkg/util/string_test.go @@ -19,10 +19,10 @@ package util_test import ( - "core/pkg/util" - . "github.com/onsi/ginkgo/v2" "github.com/stretchr/testify/assert" + + "core/pkg/util" ) var _ = Describe("String", func() { diff --git a/src/core-api/pkg/util/validation.go b/src/core-api/pkg/util/validation.go index 6c7641bb6..0b33c1dcf 100644 --- a/src/core-api/pkg/util/validation.go +++ b/src/core-api/pkg/util/validation.go @@ -22,9 +22,9 @@ import ( "fmt" "io" - "core/pkg/logging" + validator "github.com/go-playground/validator/v10" - "github.com/go-playground/validator/v10" + "core/pkg/logging" ) // 这里是通用的 FieldError 处理, 如果需要针对某些字段或struct做定制, 需要自行定义一个 diff --git a/src/core-api/pkg/util/validation_test.go b/src/core-api/pkg/util/validation_test.go index b1ef1f503..780834d88 100644 --- a/src/core-api/pkg/util/validation_test.go +++ b/src/core-api/pkg/util/validation_test.go @@ -23,11 +23,11 @@ import ( "io" "strings" - "core/pkg/util" - - "github.com/go-playground/validator/v10" + validator "github.com/go-playground/validator/v10" . "github.com/onsi/ginkgo/v2" "github.com/stretchr/testify/assert" + + "core/pkg/util" ) var _ = Describe("Validation", func() {