diff --git a/dbm-services/go.work b/dbm-services/go.work index 8d3276e207..ab449600d1 100644 --- a/dbm-services/go.work +++ b/dbm-services/go.work @@ -24,4 +24,5 @@ use ( redis/db-tools/dbmon redis/redis-dts common/celery-service + sqlserver/db-tools/dbactuator ) diff --git a/dbm-services/sqlserver/db-tools/dbactuator/.gitignore b/dbm-services/sqlserver/db-tools/dbactuator/.gitignore new file mode 100644 index 0000000000..4b4413259e --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/.gitignore @@ -0,0 +1,31 @@ +!.gitkeep +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +# Test binary, built with `go test -c` +*.test +# Output of the go coverage tool, specifically when used with LiteIDE +*.out +# Dependency directories (remove the comment below to include it) +vendor/ +# Go workspace file +go.work +configs/* +log/ +build/ +conf/ +*exe +*.log +.idea/ +.DS_Store +sync_test.sh +.vscode/ +scripts/upload_media.sh +scripts/upload.sh +localtest/ +.codecc +.idea +.vscode diff --git a/dbm-services/sqlserver/db-tools/dbactuator/.golangci.yml b/dbm-services/sqlserver/db-tools/dbactuator/.golangci.yml new file mode 100644 index 0000000000..0b06aedc4d --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/.golangci.yml @@ -0,0 +1,66 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +linters-settings: + lll: + line-length: 120 + funlen: + lines: 80 + statements: 80 + gocritic: + enabled-checks: + - nestingReduce + - commentFormatting + +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 + - sqlclosecheck + - deadcode + - govet + - bodyclose + - staticcheck + # - errorlint + # - varcheck + # - typecheck + # - nestif + # - gofumpt + # - godox + # - wsl + # - funlen + # - golint + # - cyclop + fast: false \ No newline at end of file diff --git a/dbm-services/sqlserver/db-tools/dbactuator/LICENSE b/dbm-services/sqlserver/db-tools/dbactuator/LICENSE new file mode 100644 index 0000000000..e69de29bb2 diff --git a/dbm-services/sqlserver/db-tools/dbactuator/Makefile b/dbm-services/sqlserver/db-tools/dbactuator/Makefile new file mode 100644 index 0000000000..bd7e8a8a40 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/Makefile @@ -0,0 +1,32 @@ +SHELL := /bin/bash +BASE_DIR = $(shell pwd) +VERSION = 0.0.1 +APPNAME = dbactuator.exe +GOOS ?= windows +BUILD_FLAG = " -X main.version=${VERSION} -X main.buildstamp=`date -u '+%Y-%m-%d_%I:%M:%S%p'` -X main.githash=`git rev-parse HEAD` " +BUILD_EXTERNAL_FLAG = " -X main.external=ON -X main.version=${VERSION} -X main.buildstamp=`date -u '+%Y-%m-%d_%I:%M:%S%p'` -X main.githash=`git rev-parse HEAD` " +BUILD_MINI_FLAG = " -s -w -X main.version=${VERSION} -X main.buildstamp=`date -u '+%Y-%m-%d_%I:%M:%S%p'` -X main.githash=`git rev-parse HEAD` " + +.PHONY: all build clean + +build: + cd ${BASE_DIR}/cmd && CGO_ENABLED=0 GOOS=${GOOS} GOARCH=amd64 go build -gcflags=-trimpath=${PWD} -asmflags=-trimpath=${PWD} -ldflags ${BUILD_FLAG} -o $(BASE_DIR)/build/$(APPNAME) -v . + +external : + cd ${BASE_DIR}/cmd && CGO_ENABLED=0 GOOS=${GOOS} GOARCH=amd64 go build -gcflags=-trimpath=${PWD} -asmflags=-trimpath=${PWD} -ldflags ${BUILD_EXTERNAL_FLAG} -o $(BASE_DIR)/build/$(APPNAME) -v . + +mini: + cd ${BASE_DIR}/cmd && CGO_ENABLED=0 GOOS=${GOOS} GOARCH=amd64 go build -gcflags=-trimpath=${PWD} -asmflags=-trimpath=${PWD} -ldflags ${BUILD_MINI_FLAG} -o $(BASE_DIR)/build/$(APPNAME) -v . + # need install upx + upx $(BASE_DIR)/build/$(APPNAME) + +clean: + cd ${BASE_DIR}/build && rm -rf ${APPNAME} + +gotool: + @-gofmt -w . + +help: + @echo "make - compile go source" + @echo "make gotool - run gofmt" + @echo "make clean - do some clean job" diff --git a/dbm-services/sqlserver/db-tools/dbactuator/README.md b/dbm-services/sqlserver/db-tools/dbactuator/README.md new file mode 100644 index 0000000000..c90ebd06d3 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/README.md @@ -0,0 +1,170 @@ +# git.tencent.com/dbs/bk-dbactuator + +## 开发规范 + +> go版本 >= **1.9** + +> 配置代码格式化 & import规范,请配置 **goimports** `vscode: "go.formatTool": "goimports"` + +> 使用 **golangci-lint** 进行代码规范检查 + +> 配置自动化注释**gonote** + ``` + // vscode 配置 + "filewatcher.commands": [ + { + "match": ".*\\.go$", + "isAsync": false, + "cmd": "cd '${fileDirname}' && gonote -w '${file}' > /tmp/gonote.log 2>&1", + "event": "onFileChange" + } + ] + ``` + > 其他规范参照 **Go开发规范** + + + + +## dbactuator + +数据库操作指令集合,实现MySQL、Proxy、监控、备份 部署,MySQL、Proxy 变更等原子任务操作,由上层Pipeline 编排组合不同的指令,来完成不同的场景化的任务 +``` +Db Operation Command Line Interface +Version: 0.0.1 +Githash: 212617a717c3a3a968eb0c7d3a2c4ea2bc21abc2 +Buildstamp:2022-05-27_06:42:56AM + +Usage: + dbactuator [flags] + dbactuator [command] + +Available Commands: + completion Generate the autocompletion script for the specified shell + help Help about any command + mysql MySQL Operation Command Line Interface + proxy MySQL Proxy Operation Command Line Interface + sysinit Exec sysinit_mysql.sh,Init mysql default os user,password + +Flags: + -h, --help help for dbactuator + -n, --node_id string 节点id + -p, --payload string command payload + -r, --rollback 回滚任务 + -x, --show-payload show payload for man + -u, --uid string 单据id + +Use "dbactuator [command] --help" for more information about a command. +``` + +## 文档 + +### subcommand 开发 + +#### 给 payload 添加说明和 example (swagger) +##### **查看注释** +``` +./dbactuator mysql find-local-backup --helper +``` + +##### **怎么增加注释到 --helper** +在 subcommand 定义上添加注释,示例: +``` +// FindLocalBackupCommand godoc +// +// @Summary 查找本地备份 +// @Description 查找本地备份 +// @Tags mysql +// @Accept json +// @Param body body mysql.FindLocalBackupParam true "short description" +// @Success 200 {object} mysql.FindLocalBackupResp +// @Router /mysql/find-local-backup [post] +func FindLocalBackupCommand() *cobra.Command { +... +``` + +- `@Param` 把中间的 `mysql.FindLocalBackupParam` 替换成 subcommand 的参数 struct 定义,且 struct 需要能被当前包引用 + swagger 使用 `@param` 来解析参数,所以不要与其它函数注释冲突,否则可能 build doc 失败,output example 见下文 +- `@Router` 格式 `/cmd/subcmd [post]`,保留后面的`[post]` +- 如果没有输出则去掉 `@Success` 这行,output example 见下文 + +**param struct 的字段注释示例:** +``` +// field 枚举说明. 字段注释可以在字段上一行,或者字段行后 +Field1 int `json:"field1" enums:"0,1,2"` // 枚举类型 +Field2 string `json:"field2" validate:"required" example:"test"` // 必填项,example内容 +Field3 int `json:"field2" valildate:"gte:999,lte:0" default:"2"` // 最大值最小值,默认值 +``` + +##### **怎么增加 example** +在 component 的 struct 增加 `Example() interface()` 方法,示例: +``` +func (f *FindLocalBackupComp) Example() interface{} { + comp := FindLocalBackupComp{ + Params: FindLocalBackupParam{ + BackupDirs: []string{"/data/dbbak", "/data1/dbbak"}, + TgtInstance: &common.InstanceExample, + FileServer: false, + }, + } + return comp +} +``` +填充你需要的示例字段,能序列化成 json 格式。 + +然后在 subcommand 定义里面完善 `Example` 字段,示例: +``` +cmd := &cobra.Command{ + Use: "find-local-backup", + Example: fmt.Sprintf(`dbactuator mysql find-local-backup %s %s`, + subcmd.CmdBaseExampleStr, common.ToPrettyJson(act.Service.Example())), + ... + } +``` + +如果有输出 output 示例需求,可以参照 `mysql restore-dr` 写一个 `ExampleOutput()`。 + +##### **生成注释** +需要先从 https://github.com/swaggo/swag 下载 `swag` 命令(推荐 v1.8.12,低版本可能不适应go1.19)。 +``` +# 需要想先让 swagger 生成注释 docs/swagger.json +# 需要关注注释是否编译成功 +./build_doc.sh + +# 再编译打包进二进制 +make +``` +或者一步 `./build.sh` + +目前为了避免代码冲突,.gitignore 忽略了 docs/swagger.json, docs/swagger.yaml + +### payload 中字段从环境变量读取 +如果有一些认证或者密码信息,不方便在 payload 里提供,可以设置环境变量。 +只需要在 struct 上设置 tag `env` 为环境变量名即可,其它 validate required 属性依然会生效 + +但是目前对于嵌套 struct 类型,nested struct 不能是 nil point,要空初始化之后才能 Parse 进去。 + +示例: +``` +EXPORT GENERAL_ACCOUNT_admin_user=ADMIN +EXPORT GENERAL_ACCOUNT_admin_pwd=xxx + +或者 IBS_INFO_key=xxxxx ./dbactuator download ibs-recover ... +``` + + +#### 格式化 +- 代码都必须用 `gofmt` 格式化。(使用不用ide的同学注意调整) + +#### import 规范 +- 使用 `goimports` 自动格式化引入的包名,import 规范原则上以 `goimports` 规则为准。 + +#### 包命名 +- 保持 `package` 的名字和目录一致。 +- 包名应该为小写单词,不要使用下划线或者混合大小写,使用多级目录来划分层级。 +- 不要使用无意义的包名,如:`util`、`common`、`misc`、`global`。`package`名字应该追求清晰且越来越收敛,符合‘单一职责’原则。而不是像`common`一样,什么都能往里面放,越来越膨胀,让依赖关系变得复杂,不利于阅读、复用、重构。注意,`xx/util/encryption`这样的包名是允许的。 + +#### 文件命名 +- 文件名应该采用小写,并且使用下划线分割各个单词。 + +#### 变量命名 +- 变量名必须遵循驼峰式,首字母根据访问控制决定使用大写或小写。 \ No newline at end of file diff --git a/dbm-services/sqlserver/db-tools/dbactuator/cmd/cmd.go b/dbm-services/sqlserver/db-tools/dbactuator/cmd/cmd.go new file mode 100644 index 0000000000..e784581eb9 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/cmd/cmd.go @@ -0,0 +1,143 @@ +// Package main 总入口 +/* + * @Description: dbactuator 入口函数,主要实现数据侧一些操作的命令,比如安装mssql(sqlserver)等等一系列的操作集合 + * @Useage: dbactuator --help + */ +package main + +import ( + "fmt" + "os" + "runtime/debug" + "strings" + "time" + + "dbm-services/common/go-pubpkg/logger" + "dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd" + "dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/sqlservercmd" + "dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/sysinitcmd" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/core/cst" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/util/templates" + + "github.com/spf13/cobra" +) + +const ( + // CMD actor入口 + CMD = "dbactuator" +) + +var ( + buildstamp, githash, version, external string +) + +// @title dbactuator API +// @version 0.0.1 +// @description This is a dbactuator command collection. +// @termsOfService http://swagger.io/terms/ +// @Schemes http +// @contact.name API Support +// @contact.url http://www.swagger.io/support +// @contact.email support@swagger.io + +// @license.name Apache 2.0 +// @license.url http://www.apache.org/licenses/LICENSE-2.0.html + +// @host ./dbactuator +// @BasePath / + +// main godoc +func main() { + defer func() { + if err := recover(); err != nil { + fmt.Println(err) + logger.Error("panic goroutine inner error!%v;%s", err, string(debug.Stack())) + os.Exit(1) + return + } + }() + if err := NewDbActuatorCommand().Execute(); err != nil { + fmt.Fprint(os.Stderr, err.Error()) + logger.Error("NewDbActuatorCommand run failed:%s", err.Error()) + os.Exit(1) + } +} + +// NewDbActuatorCommand 新建命令 +func NewDbActuatorCommand() *cobra.Command { + cmds := &cobra.Command{ + Use: CMD, + Short: fmt.Sprintf(`Db Operation Command Line Interface +Version: %s +Githash: %s +External: %s +Buildstamp:%s`, version, githash, strings.ToUpper(external), buildstamp), + Args: cobra.OnlyValidArgs, + PersistentPreRun: func(cmd *cobra.Command, args []string) { + if !cmd.IsAvailableCommand() { + runHelp(cmd, args) + return + } + subcmd.SetLogger(cmd, subcmd.GBaseOptions) + if subcmd.PrintSubCommandHelper(cmd, subcmd.GBaseOptions) { + runHelp(cmd, args) + } + // 定时输出标准心跳输出 + startHeartbeat(10 * time.Second) + }, + Run: runHelp, + SuggestFor: []string{CMD}, + } + groups := templates.CommandGroups{ + { + Message: "sysinit operation sets", + Commands: []*cobra.Command{ + sysinitcmd.NewSysInitCommand(), + }, + }, + { + Message: "sqlserver operation sets", + Commands: []*cobra.Command{ + sqlservercmd.NewSQLserverCommand(), + }, + }, + } + groups.Add(cmds) + // 标志可以是 "persistent" 的,这意味着该标志将可用于分配给它的命令以及该命令下的每个命令。对于全局标志,将标志分配为根上的持久标志。 + // 默认每个subcomand 都默认带这些参数 + cmds.PersistentFlags().StringVarP(&subcmd.GBaseOptions.Payload, "payload", "p", subcmd.GBaseOptions.Payload, + "command payload ") + cmds.PersistentFlags().StringVarP(&subcmd.GBaseOptions.PayloadFormat, "payload-format", "m", + subcmd.GBaseOptions.PayloadFormat, "command payload format, default base64, value_allowed: base64|raw") + cmds.PersistentFlags().StringVarP(&subcmd.GBaseOptions.Uid, "uid", "U", subcmd.GBaseOptions.Uid, "单据id") + cmds.PersistentFlags().StringVarP(&subcmd.GBaseOptions.RootId, "root_id", "R", subcmd.GBaseOptions.NodeId, "流程id") + cmds.PersistentFlags().StringVarP(&subcmd.GBaseOptions.NodeId, "node_id", "N", subcmd.GBaseOptions.NodeId, "节点id") + cmds.PersistentFlags().StringVarP(&subcmd.GBaseOptions.VersionId, "version_id", "V", subcmd.GBaseOptions.NodeId, + "运行版本id") + cmds.PersistentFlags().BoolVarP(&subcmd.GBaseOptions.RollBack, "rollback", "r", subcmd.GBaseOptions.RollBack, "回滚任务") + cmds.PersistentFlags().BoolVarP(&subcmd.GBaseOptions.Helper, "helper", "E", subcmd.GBaseOptions.Helper, "payload参数说明") + subcmd.GBaseOptions.External = external + // @todo add --daemon mode to serve http to call subcmd/components + return cmds +} + +func runHelp(cmd *cobra.Command, args []string) { + cmd.Help() + os.Exit(1) +} + +// startHeartbeat 定時输出日志 +func startHeartbeat(period time.Duration) { + go func() { + ticker := time.NewTicker(period) + defer ticker.Stop() + var hearbeatTime string + for { + select { + case <-ticker.C: + hearbeatTime = time.Now().Local().Format(cst.TIMELAYOUT) + fmt.Fprintf(os.Stdin, "["+hearbeatTime+"]hearbeating ...\n") + } + } + }() +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/docs/.gitkeep b/dbm-services/sqlserver/db-tools/dbactuator/docs/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/dbm-services/sqlserver/db-tools/dbactuator/docs/dbactuator.md b/dbm-services/sqlserver/db-tools/dbactuator/docs/dbactuator.md new file mode 100644 index 0000000000..efe24099a5 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/docs/dbactuator.md @@ -0,0 +1,30 @@ +# dbactuator + +数据库操作指令集合,实现MssSQL(SQLServer)等原子任务操作,由上层Pipeline 编排组合不同的指令,来完成不同的场景化的任务 +``` +Db Operation Command Line Interface +Version: 0.0.1 +Githash: 212617a717c3a3a968eb0c7d3a2c4ea2bc21abc2 +Buildstamp:2022-05-27_06:42:56AM + +Usage: + dbactuator [flags] + dbactuator [command] + +Available Commands: + completion Generate the autocompletion script for the specified shell + help Help about any command + mysql MySQL Operation Command Line Interface + proxy MySQL Proxy Operation Command Line Interface + sysinit Exec sysinit_mysql.sh,Init mysql default os user,password + +Flags: + -h, --help help for dbactuator + -n, --node_id string 节点id + -p, --payload string command payload + -r, --rollback 回滚任务 + -x, --show-payload show payload for man + -u, --uid string 单据id + +Use "dbactuator [command] --help" for more information about a command. +``` \ No newline at end of file diff --git a/dbm-services/sqlserver/db-tools/dbactuator/docs/docs.go b/dbm-services/sqlserver/db-tools/dbactuator/docs/docs.go new file mode 100644 index 0000000000..67384e3939 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/docs/docs.go @@ -0,0 +1,2 @@ +// Package docs TODO +package docs diff --git a/dbm-services/sqlserver/db-tools/dbactuator/docs/embed_docs.go b/dbm-services/sqlserver/db-tools/dbactuator/docs/embed_docs.go new file mode 100644 index 0000000000..f7c1683e24 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/docs/embed_docs.go @@ -0,0 +1,8 @@ +package docs + +import "embed" + +// SwaggerDocs TODO +// +//go:embed swagger.json +var SwaggerDocs embed.FS diff --git a/dbm-services/sqlserver/db-tools/dbactuator/docs/swagger.json b/dbm-services/sqlserver/db-tools/dbactuator/docs/swagger.json new file mode 100644 index 0000000000..543229ba12 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/docs/swagger.json @@ -0,0 +1,162 @@ +{ + "schemes": [ + "http" + ], + "swagger": "2.0", + "info": { + "description": "This is a dbactuator command collection.", + "title": "dbactuator API", + "termsOfService": "http://swagger.io/terms/", + "contact": { + "name": "API Support", + "url": "http://www.swagger.io/support", + "email": "support@swagger.io" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + }, + "version": "0.0.1" + }, + "host": "./dbactuator", + "basePath": "/", + "paths": { + "/sqlserver/deploy": { + "post": { + "description": "部署 sqlserver 实例说明", + "consumes": [ + "application/json" + ], + "tags": [ + "sqlserver" + ], + "summary": "部署 sqlserver 实例", + "parameters": [ + { + "description": "short description", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dbm-services_sqlserver_db-tools_dbactuator_pkg_components_sqlserver.InstallsqlserverComp" + } + } + ], + "responses": {} + } + } + }, + "definitions": { + "dbm-services_sqlserver_db-tools_dbactuator_pkg_components.GeneralParam": { + "type": "object", + "properties": { + "runtime_account": { + "$ref": "#/definitions/dbm-services_sqlserver_db-tools_dbactuator_pkg_components.RuntimeAccountParam" + } + } + }, + "dbm-services_sqlserver_db-tools_dbactuator_pkg_components.RuntimeAccountParam": { + "type": "object", + "properties": { + "sa_pwd": { + "description": "sa 密码", + "type": "string" + }, + "sa_user": { + "description": "sa 账户", + "type": "string" + }, + "sqlserver_pwd": { + "description": "sqlserver 密码", + "type": "string" + }, + "sqlserver_user": { + "description": "sqlserver 账户", + "type": "string" + }, + "mssql_pwd": { + "description": "mssql 密码", + "type": "string" + }, + "mssql_user": { + "description": "mssql 账户", + "type": "string" + } + } + }, + "dbm-services_sqlserver_db-tools_dbactuator_pkg_components_sqlserver.InstallsqlserverComp": { + "type": "object", + "properties": { + "extend": { + "$ref": "#/definitions/dbm-services_sqlserver_db-tools_dbactuator_pkg_components_sqlserver.InstallsqlserverParams" + }, + "general": { + "$ref": "#/definitions/dbm-services_sqlserver_db-tools_dbactuator_pkg_components.GeneralParam" + }, + "timeZone": { + "type": "string" + } + } + }, + "dbm-services_sqlserver_db-tools_dbactuator_pkg_components_sqlserver.InstallsqlserverParams": { + "type": "object", + "required": [ + "host", + "ports", + "sqlserver_configs", + "sqlserver_version", + "pkg", + "pkg_md5", + "ports", + "install_key", + "buffer_percent", + "max_remain_mem_gb" + ], + "properties": { + "host": { + "type": "string" + }, + "mycnf_configs": { + "description": "map[port]sqlserver.cnf", + "type": "array", + "items": { + "type": "integer" + } + }, + "sqlserver_version": { + "description": "sqlserverVerion 版本, 比如SQL2008x64", + "type": "string" + }, + "pkg": { + "description": "安装包名", + "type": "string" + }, + "pkg_md5": { + "description": "安装包MD5", + "type": "string" + }, + "ports": { + "description": "Ports", + "type": "array", + "items": { + "type": "integer" + } + }, + "install_key": { + "description": "安装key", + "type": "string" + }, + "buffer_percent": { + "description": "实例内存分配比", + "type": "integer" + }, + "max_remain_mem_gb": { + "description": "剩余内存最大限制GB", + "type": "integer" + } + + } + } + + } +} \ No newline at end of file diff --git a/dbm-services/sqlserver/db-tools/dbactuator/docs/swagger.yaml b/dbm-services/sqlserver/db-tools/dbactuator/docs/swagger.yaml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/dbm-services/sqlserver/db-tools/dbactuator/go.mod b/dbm-services/sqlserver/db-tools/dbactuator/go.mod new file mode 100644 index 0000000000..60c8b60145 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/go.mod @@ -0,0 +1,54 @@ +module dbm-services/sqlserver/db-tools/dbactuator + +go 1.21 + +require ( + github.com/MakeNowJust/heredoc v1.0.0 + github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 + github.com/caarlos0/env/v6 v6.10.1 + github.com/go-playground/locales v0.14.1 + github.com/go-playground/universal-translator v0.18.1 + github.com/go-playground/validator/v10 v10.14.1 + github.com/gofrs/flock v0.8.1 + github.com/golang-jwt/jwt/v4 v4.5.0 + github.com/jmoiron/sqlx v1.3.5 + github.com/juju/ratelimit v1.0.2 + github.com/pkg/errors v0.9.1 + github.com/shirou/gopsutil v3.21.11+incompatible + github.com/spf13/cast v1.5.1 + github.com/spf13/cobra v1.7.0 + github.com/spf13/viper v1.16.0 + golang.org/x/sys v0.10.0 +) + +require ( + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect + github.com/golang-sql/sqlexp v0.1.0 // indirect + github.com/yusufpapurcu/wmi v1.2.3 // indirect +) + +require ( + github.com/denisenkom/go-mssqldb v0.12.3 + github.com/fatih/color v1.13.0 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/spf13/afero v1.9.5 // 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 + golang.org/x/crypto v0.9.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/text v0.9.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/dbm-services/sqlserver/db-tools/dbactuator/go.sum b/dbm-services/sqlserver/db-tools/dbactuator/go.sum new file mode 100644 index 0000000000..898405b5c6 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/go.sum @@ -0,0 +1,568 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0= +github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= +github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 h1:ZBbLwSJqkHBuFDA6DUhhse0IGJ7T5bemHyNILUjvOq4= +github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2/go.mod h1:VSw57q4QFiWDbRnjdX8Cb3Ow0SFncRw+bA/ofY6Q83w= +github.com/caarlos0/env/v6 v6.10.1 h1:t1mPSxNpei6M5yAeu1qtRdPAK29Nbcf/n3G7x+b3/II= +github.com/caarlos0/env/v6 v6.10.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw= +github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k= +github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f h1:7LYC+Yfkj3CTRcShK0KOL/w6iTiKyqqBA9a41Wnggw8= +github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= +github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/juju/ratelimit v1.0.2 h1:sRxmtRiajbvrcLQT7S+JbqU0ntsb9W2yhSdNN8tWfaI= +github.com/juju/ratelimit v1.0.2/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= +github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= +github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= +github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= +github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= +github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= +github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= +github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/sqlservercmd/install_sqlserver.go b/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/sqlservercmd/install_sqlserver.go new file mode 100644 index 0000000000..d3f3be71d9 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/sqlservercmd/install_sqlserver.go @@ -0,0 +1,141 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package sqlservercmd + +import ( + "encoding/json" + "fmt" + + "dbm-services/common/go-pubpkg/logger" + "dbm-services/riak/db-tools/dbactuator/pkg/rollback" + "dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/components/sqlserver" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/util" + + "github.com/spf13/cobra" +) + +// DeploySqlServerAct 部署 sqlserver 实例, 可支持多实例安装 +type DeploySqlServerAct struct { + *subcmd.BaseOptions + BaseService sqlserver.InstallSqlServerComp +} + +// NewDeploySqlServerCommand godoc +// +// @Summary 部署 sqlserver 实例 +// @Description 可支持多实例部署 +// @Tags sqlserver +// @Accept json +// @Param body body mysql.InstallSqlServerComp true "short description" +func NewDeploySqlServerCommand() *cobra.Command { + act := DeploySqlServerAct{ + BaseOptions: subcmd.GBaseOptions, + } + cmd := &cobra.Command{ + Use: "deploy", + Short: "部署SqlServer实例", + Example: fmt.Sprintf( + `dbactuator sqlserver deploy %s %s`, + subcmd.CmdBaseExampleStr, subcmd.ToPrettyJson(act.BaseService.Example()), + ), + Run: func(cmd *cobra.Command, args []string) { + util.CheckErr(act.Validate()) + if act.RollBack { + util.CheckErr(act.Rollback()) + return + } + util.CheckErr(act.Init()) + util.CheckErr(act.Run()) + }, + } + return cmd +} + +// Init 初始化 +func (d *DeploySqlServerAct) Init() (err error) { + logger.Info("DeploySpiderAct Init") + if err = d.Deserialize(&d.BaseService.Params); err != nil { + logger.Error("DeserializeAndValidate failed, %v", err) + return err + } + d.BaseService.GeneralParam = subcmd.GeneralRuntimeParam + + return d.BaseService.InitDefaultParam() +} + +// Rollback 回滚 +// +// @receiver d +// @return err +func (d *DeploySqlServerAct) Rollback() (err error) { + var r rollback.RollBackObjects + if err = d.DeserializeAndValidate(&r); err != nil { + logger.Error("DeserializeAndValidate failed, %v", err) + return err + } + err = r.RollBack() + if err != nil { + logger.Error("roll back failed %s", err.Error()) + } + return +} + +// Run 执行 +func (d *DeploySqlServerAct) Run() (err error) { + steps := subcmd.Steps{ + { + FunName: "预检查", + Func: d.BaseService.PreCheck, + }, + { + FunName: "渲染实例配置", + Func: d.BaseService.GenerateCnf, + }, + { + FunName: "初始化SQLserver相关目录", + Func: d.BaseService.InitInstanceDirs, + }, + { + FunName: "下载并且解压安装包", + Func: d.BaseService.DecompressPkg, + }, + { + FunName: "启动SQLserver", + Func: d.BaseService.SqlServerStartup, + }, + { + FunName: "初始化配置", + Func: d.BaseService.InitConfigs, + }, + { + FunName: "分配实例BUFFER", + Func: d.BaseService.InitInstanceBuffer, + }, + { + FunName: "初始化实例", + Func: d.BaseService.InitDB, + }, + } + + if err := steps.Run(); err != nil { + rollbackCtxb, rerr := json.Marshal(d.BaseService.RollBackContext) + if rerr != nil { + logger.Error("json Marshal %s", err.Error()) + fmt.Printf("Can't RollBack\n") + } + fmt.Printf("%s\n", string(rollbackCtxb)) + return err + } + + logger.Info("install_sqlserver_successfully") + return nil +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/sqlservercmd/sqlservercmd.go b/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/sqlservercmd/sqlservercmd.go new file mode 100644 index 0000000000..bbc295fc33 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/sqlservercmd/sqlservercmd.go @@ -0,0 +1,39 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +// Package sqlservercmd TODO +package sqlservercmd + +import ( + "dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/util/templates" + + "github.com/spf13/cobra" +) + +// NewSQLserverCommand mysql子命令 +func NewSQLserverCommand() *cobra.Command { + cmds := &cobra.Command{ + Use: "sqlserver [sqlserver operation]", + Short: "SQLServer Operation Command Line Interface", + RunE: subcmd.ValidateSubCommand(), + } + groups := templates.CommandGroups{ + { + Message: "sqlserver operation sets", + Commands: []*cobra.Command{ + NewDeploySqlServerCommand(), + NewUnInstallSqlServerCommand(), + }, + }, + } + groups.Add(cmds) + return cmds +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/sqlservercmd/uninstall_sqlserver.go b/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/sqlservercmd/uninstall_sqlserver.go new file mode 100644 index 0000000000..b71fd46bed --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/sqlservercmd/uninstall_sqlserver.go @@ -0,0 +1,87 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package sqlservercmd + +import ( + "fmt" + + "dbm-services/common/go-pubpkg/logger" + "dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/components/sqlserver" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/util" + + "github.com/spf13/cobra" +) + +// UninstallSqlServerAct 下架 sqlserver 实例, 可支持多实例下架 +type UninstallSqlServerAct struct { + *subcmd.BaseOptions + BaseService sqlserver.UnInstallSQLServerComp +} + +// NewUnInstallSqlServerCommand godoc +// +// @Summary 下架 sqlserver 实例 +// @Description 可支持多实例下架 +// @Tags sqlserver +// @Accept json +// @Param body body mysql.UnInstallSQLServerComp true "short description" +func NewUnInstallSqlServerCommand() *cobra.Command { + act := UninstallSqlServerAct{ + BaseOptions: subcmd.GBaseOptions, + } + cmd := &cobra.Command{ + Use: "Uninstall", + Short: "下架SqlServer实例", + Example: fmt.Sprintf(`dbactuator sqlserver Uninstall %s `, subcmd.CmdBaseExampleStr), + Run: func(cmd *cobra.Command, args []string) { + util.CheckErr(act.Validate()) + if act.RollBack { + return + } + util.CheckErr(act.Init()) + util.CheckErr(act.Run()) + }, + } + return cmd +} + +// Init 初始化 +func (u *UninstallSqlServerAct) Init() (err error) { + logger.Info("UninstallSqlServerAct Init") + if err = u.Deserialize(&u.BaseService.Params); err != nil { + logger.Error("DeserializeAndValidate failed, %v", err) + return err + } + u.BaseService.GeneralParam = subcmd.GeneralRuntimeParam + + return u.BaseService.Init() +} + +// Run 执行 +func (u *UninstallSqlServerAct) Run() (err error) { + steps := subcmd.Steps{ + { + FunName: "预检查", + Func: u.BaseService.PreCheck, + }, + { + FunName: "停止数据库实例", + Func: u.BaseService.ShutDownMSSQL, + }, + } + + if err := steps.Run(); err != nil { + return err + } + logger.Info("uninstall_sqlserver successfully") + return nil +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/subcmd.go b/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/subcmd.go new file mode 100644 index 0000000000..6b66a53266 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/subcmd.go @@ -0,0 +1,400 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +// Package subcmd TODO +package subcmd + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "dbm-services/common/go-pubpkg/logger" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/components" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/util" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/util/templates" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/util/validate" + "encoding/base64" + "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/caarlos0/env/v6" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +const ( + // CmdBaseExampleStr TODO + CmdBaseExampleStr = "-u {uid} -n {node_id} -p {base64}" + // PayloadFormatRaw TODO + PayloadFormatRaw = "raw" +) + +// GBaseOptions TODO +var GBaseOptions *BaseOptions + +// GeneralRuntimeParam TODO +var GeneralRuntimeParam *components.GeneralParam + +func init() { + GBaseOptions = &BaseOptions{} + GeneralRuntimeParam = &components.GeneralParam{} +} + +// BaseOptions TODO +/* + 此参数是json字符串的base64编码之后的字符串 +*/ +type BaseOptions struct { + Uid string + RootId string + NodeId string + VersionId string + Payload string + PayloadFormat string + RollBack bool + Helper bool + // 是否为外部版本 + // on ON + External string +} + +// IsExternal 是否编译成外部版本 +func (b *BaseOptions) IsExternal() bool { + return strings.ToUpper(b.External) == "ON" +} + +const ( + // StepStateDefault TODO + StepStateDefault = "default" + // StepStateRunning TODO + StepStateRunning = "running" + // StepStateSucc TODO + StepStateSucc = "success" + // StepStateSkip TODO + StepStateSkip = "skipped" // 用户主动跳过该 step + // StepStateStop TODO + StepStateStop = "stopped" // 用户主动暂停,特殊形式的 failed + // StepStateFail TODO + StepStateFail = "failed" +) + +// StepFunc TODO +type StepFunc struct { + FunName string + Func func() error + State string + FuncRetry func() error + FuncRollback func() error + FuncStop func() error + Retries int +} + +// Steps TODO +type Steps []StepFunc + +// Run TODO +func (s Steps) Run() (err error) { + for idx, step := range s { + logMessage := fmt.Sprintf("step <%d>, ready start run [%s]", idx, step.FunName) + logger.Info(logMessage) + if err = step.Func(); err != nil { + logger.Error("step<%d>: %s失败 , 错误: %s", idx, step.FunName, err) + // @todo + // 顺便输出接下来还有哪些 step 未允许 + return err + } + logger.Info("step <%d>, start run [%s] successfully", idx, step.FunName) + } + return nil +} + +// DeserializeAndValidate TODO +/* + 反序列化payload,并校验参数 + ps: 参数校验 from golang validate v10 +*/ +func (b *BaseOptions) DeserializeAndValidate(s interface{}) (err error) { + var bp []byte + if b.PayloadFormat == PayloadFormatRaw { + bp = []byte(b.Payload) + } else { + bp, err = base64.StdEncoding.DecodeString(b.Payload) + if err != nil { + return err + } + } + // logger.Info("payload received: %s", bp) + // 如果 s 里面的 sub struct 是 pointer,要初始化后再传进来才能解析到环境变量 + if err := env.Parse(s); err != nil { + logger.Warn("env parse error, ignore environment variables for payload:%s", err.Error()) + // env: expected a pointer to a Struct + } + defer logger.Info("payload parsed: %+v", s) + if err = json.Unmarshal(bp, s); err != nil { + logger.Error("json.Unmarshal failed, %v", s, err) + return + } + if err = validate.GoValidateStruct(s, false, true); err != nil { + logger.Error("validate struct failed, %v", s, err) + return + } + return nil +} + +// Deserialize TODO +/* + { + "general":{} // + "extend":{} // 实际参数 + } + 反序列化payload,并校验参数 + ps: 参数校验 from golang validate v10 +*/ +func (b *BaseOptions) Deserialize(s interface{}) (err error) { + var bp []byte + if b.PayloadFormat == PayloadFormatRaw { + bp = []byte(b.Payload) + } else { + bp, err = base64.StdEncoding.DecodeString(b.Payload) + if err != nil { + return err + } + } + if err := env.Parse(s); err != nil { + logger.Warn("env parse error, ignore environment variables for payload:%s", err.Error()) + } + logger.Info("params from env %+v", s) + g := components.RuntimeAccountParam{} + if err := env.Parse(&g); err != nil { + logger.Warn("env parse error, ignore environment variables for payload:%s", err.Error()) + } + // logger.Info("Account from env: %+v", g) + bip := components.BaseInputParam{ + ExtendParam: s, + GeneralParam: &components.GeneralParam{RuntimeAccountParam: g}, + } + // logger.Info("payload received: %s", bp) + defer logger.Info("payload parsed: %+v", bip) + if err = json.Unmarshal(bp, &bip); err != nil { + logger.Error("json.Unmarshal failed, %v", s, err) + err = errors.WithMessage(err, "参数解析错误") + return + } + // logger.Info("params after unmarshal %+v", bip) + if err = validate.GoValidateStruct(bip, false, true); err != nil { + logger.Error("validate struct failed, %v", s, err) + err = errors.WithMessage(err, "参数输入错误") + return + } + GeneralRuntimeParam = bip.GeneralParam + return nil +} + +// DeserializeSimple 简单 payload 不需要 {"extend":{body}},直接传入 body +func (b *BaseOptions) DeserializeSimple(s interface{}) (err error) { + var body []byte + if b.PayloadFormat == PayloadFormatRaw { + body = []byte(b.Payload) + } else { + body, err = base64.StdEncoding.DecodeString(b.Payload) + if err != nil { + return err + } + } + // logger.Info("payload received: %s", body) + // 如果 s 里面的 sub struct 是 pointer,要初始化后再传进来才能解析到环境变量 + if err := env.Parse(s); err != nil { + logger.Warn("env parse error, ignore environment variables for payload:%s", err.Error()) + } + + defer logger.Info("payload parsed: %+v", s) + if err = json.Unmarshal(body, &s); err != nil { + logger.Error("json.Unmarshal failed, %v", s, err) + err = errors.WithMessage(err, "参数解析错误") + return + } + if err = validate.GoValidateStruct(s, false, true); err != nil { + logger.Error("validate struct failed, %v", s, err) + err = errors.WithMessage(err, "参数输入错误") + return + } + return nil +} + +// Validate TODO +func (b BaseOptions) Validate() (err error) { + if len(b.Payload) == 0 { + return fmt.Errorf("payload need input") + } + return nil +} + +// OutputCtx TODO +// +// @receiver b +func (b BaseOptions) OutputCtx(ctx string) { + fmt.Printf("%s", ctx) +} + +// SetLogger will mkdir logs/ +func SetLogger(cmd *cobra.Command, opt *BaseOptions) { + var file *os.File + var err error + var format = true + + executable, _ := os.Executable() + // executeName := filepath.Base(executable) + executeDir := filepath.Dir(executable) + if err = os.Chdir(executeDir); err != nil { + os.Stderr.WriteString(err.Error()) + os.Exit(1) + } + + mode := os.Getenv("MODE") + lgn := "" + if cmd != nil && cmd.Parent() != nil { + lgn = fmt.Sprintf("%s-%s", cmd.Parent().Name(), cmd.Name()) + } + switch mode { + case "dev": + file = os.Stdout + format = false + default: + logFileDir := filepath.Join(executeDir, "logs") + _ = os.MkdirAll(logFileDir, 0755) + fileName := filepath.Join(logFileDir, fmt.Sprintf("actuator_%s_%s_%s.log", opt.Uid, lgn, opt.NodeId)) + file, err = os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModePerm) + if err != nil { + os.Stderr.WriteString(err.Error()) + os.Exit(1) + } + } + + extMap := map[string]string{ + "uid": opt.Uid, + "node_id": opt.NodeId, + "root_id": opt.RootId, + "version_id": opt.VersionId, + } + l := logger.New(file, format, logger.InfoLevel, extMap) + logger.ResetDefault(l) + defer logger.Sync() +} + +// ValidateSubCommand TODO +func ValidateSubCommand() func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, args []string) error { + if len(args) <= 0 { + return fmt.Errorf( + "You must specify the type of Operation Describe. %s\n", + SuggestAPIResources(cmd.Parent().Name()), + ) + } + curName := args[0] + var subCommands []string + for _, c := range cmd.Commands() { + subCommands = append(subCommands, c.Name()) + } + if len(subCommands) <= 0 { + return nil + } + if !util.StringsHas(subCommands, curName) { + return fmt.Errorf("Unknown subcommand %s\n", curName) + } + return nil + } +} + +// PrintSubCommandHelper 返回是否成功打印 helper +// 如果打印,同时运行下 runHelp +func PrintSubCommandHelper(cmd *cobra.Command, opt *BaseOptions) bool { + if opt.Helper { + if cmd.Parent().Name() == "dbactuator" { + fmt.Println("--helper need sub-command to show payload parameter") + os.Exit(1) + } + if cmd.Name() != "" { + subcmdPath := fmt.Sprintf("%s %s", cmd.Parent().Name(), cmd.Name()) + if err := GetPathDefinitionHelper(subcmdPath); err != nil { + fmt.Println(err) + os.Exit(1) + } else { + return true + } + } else { + fmt.Println("--example need sub-command") + } + } + return false +} + +// SuggestAPIResources returns a suggestion to use the "api-resources" command +// to retrieve a supported list of resources +func SuggestAPIResources(parent string) string { + return templates.LongDesc( + fmt.Sprintf( + "Use \"%s {Operation Type}\" for a complete list of supported resources.", + parent, + ), + ) +} + +// PKCS5Padding TODO +func PKCS5Padding(ciphertext []byte, blockSize int) []byte { + padding := blockSize - len(ciphertext)%blockSize + padtext := bytes.Repeat([]byte{byte(padding)}, padding) + return append(ciphertext, padtext...) +} + +// PKCS5UnPadding TODO +func PKCS5UnPadding(origData []byte) []byte { + length := len(origData) + unpadding := int(origData[length-1]) + return origData[:(length - unpadding)] +} + +// AesEncrypt TODO +// +// 增加加密函数,加密的key必须是16,24,32位长 +func AesEncrypt(origData, key []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + blockSize := block.BlockSize() + origData = PKCS5Padding(origData, blockSize) + fmt.Println(origData) + blockMode := cipher.NewCBCEncrypter(block, key[:blockSize]) + crypted := make([]byte, len(origData)) + blockMode.CryptBlocks(crypted, origData) + return crypted, nil +} + +// AesDecrypt 增加解密函数 +func AesDecrypt(crypted string, key []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + data, err1 := base64.StdEncoding.DecodeString(crypted) + if err1 != nil { + return nil, err1 + } + blockSize := block.BlockSize() + blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]) + origData := make([]byte, len(data)) + blockMode.CryptBlocks(origData, data) + origData = PKCS5UnPadding(origData) + return origData, nil +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/subcmd_helper.go b/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/subcmd_helper.go new file mode 100644 index 0000000000..738fdc1881 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/subcmd_helper.go @@ -0,0 +1,344 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package subcmd + +import ( + "dbm-services/common/go-pubpkg/logger" + "dbm-services/sqlserver/db-tools/dbactuator/docs" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/components" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/util" + "encoding/json" + "fmt" + "log" + "strings" +) + +const ( + // DTString TODO + DTString = "string" + // DTInteger TODO + DTInteger = "integer" + // DTNumber TODO + DTNumber = "number" + // DTObject TODO + DTObject = "object" + // DTArray TODO + DTArray = "array" + // DTArrayObject TODO + DTArrayObject = "array object" + // DTBOOLEAN TODO + DTBOOLEAN = "boolean" + // DTUndefined TODO + DTUndefined = "undefined ref" + // RefMaxDepth TODO + RefMaxDepth = 9 +) + +const ( + // DefinitionPrefix TODO + DefinitionPrefix = "#/definitions/" + // RefKey TODO + RefKey = "$ref" + // IndentStep TODO + IndentStep = " " + // DefinitionKey TODO + DefinitionKey = "post" +) + +// PostPath TODO +type PostPath map[string]*Path // "post": {} +// Path TODO +type Path struct { + Description string `json:"description"` + Summary string `json:"summary"` + Parameters []Param `json:"parameters"` // parameters[0].schema.$ref + Responses map[string]Param `json:"responses"` +} + +// PrintDescription TODO +func (p *Path) PrintDescription() { + fmt.Printf("# Summary: %s\n", p.Summary) + if p.Description != "" { + fmt.Printf("# Description: %s\n", p.Description) + } +} + +// Param TODO +type Param struct { + Schema RefMap `json:"schema"` // {"$ref":""} + Name string `json:"name"` + Description string `json:"description"` +} + +// RefMap TODO +type RefMap map[string]string // "$ref":"#/definitions/xx" + +// RefMapObj TODO +type RefMapObj struct { + Ref string `json:"$ref"` +} + +// Parameter TODO +type Parameter struct { + Type string `json:"type"` + // Properties components.BaseInputParam `json:"properties"` + GeneralParam components.GeneralParam `json:"generalParam"` // generalParam.$ref + Params Definition `json:"params"` // params.$ref +} + +// Definition TODO +type Definition struct { + Type string `json:"type"` + Required []string `json:"required"` + Properties map[string]*Property `json:"properties"` + description string + depth int // 禁止无限套娃 + name string + expanded bool +} + +// PrintProperties TODO +func (d *Definition) PrintProperties(indent string, header string) { + if indent == "" { + fmt.Printf("%s: %s\n", header, d.description) + } + indent = IndentStep + indent + for _, prop := range d.Properties { + prop.Print(indent) + } +} + +// NestedRef TODO +type NestedRef struct { + Type string `json:"type"` + RefMapObj + Items *NestedRef `json:"items"` +} + +// Property TODO +type Property struct { + Type string `json:"type"` + Description string `json:"description"` + Example interface{} `json:"example"` + Default interface{} `json:"default"` + Enum []interface{} `json:"enum"` + AdditionalProperties *NestedRef `json:"additionalProperties"` // additionalProperties.$ref + Ref string `json:"$ref"` // $ref, RefKey + Items *NestedRef `json:"items"` // array: items.$ref + + additionalProperties map[string]*Definition + ref *Definition + required bool + name string + depth int // 禁止无限套娃 +} + +func wrapperBoolean(flag bool) string { + if flag { + return " Required," + } else { + return " " // Optional + } +} + +func wrapperType(t string) string { + if t == DTObject { + return "dict" + } else if t == DTNumber { + return "float" + } + return t +} + +func wrapperEnum(v []interface{}) string { + var enumStr = "" + if v != nil && len(v) > 0 { + enumStr = fmt.Sprintf(` Enum oneof%v,`, v) + } + return enumStr +} + +// Print TODO +func (p *Property) Print(indent string) { + leftMaxPad := "20" + left := fmt.Sprintf("%s%s:", indent, p.name) + + leftWithPad := fmt.Sprintf("%-"+leftMaxPad+"s", left) + ss := fmt.Sprintf("%s\t%s,%s%s %s", + leftWithPad, p.Type, wrapperBoolean(p.required), wrapperEnum(p.Enum), p.Description) + if p.Example != nil { + ss += fmt.Sprintf(". 例: %v", p.Example) + } + if p.Default != nil { + ss += fmt.Sprintf(", 默认值: %v", p.Default) + } + if p.ref != nil { + fmt.Println(ss) + p.ref.PrintProperties(indent, p.ref.description) + } else { + fmt.Println(ss) + } +} + +// Definitions TODO +type Definitions map[string]*Definition + +// JsonSpec TODO +type JsonSpec struct { + Paths map[string]PostPath `json:"paths"` + Definitions Definitions `json:"definitions"` +} + +// GetOneDefinition TODO +func (ds *Definitions) GetOneDefinition(name string) *Definition { + name = strings.TrimPrefix(name, DefinitionPrefix) + if obj, ok := (*ds)[name]; ok { + return obj + } else { + // 未定义的 definition name + } + return nil +} + +// expandProperties 将 ref definition 展开 +func (ds *Definitions) expandProperties() { + for defName, d := range *ds { + d.name = defName + if !d.expanded { // 因为展开时,一直在操作同一个引用,不要重复展开 + d.ExpandProperties(ds) + } + } +} + +// ExpandProperties 展开 definition 的 property +// 因为 property 可能引用其它 definition +func (d *Definition) ExpandProperties(defs *Definitions) { + d.expanded = true + if d.Type != DTObject { + logger.Info("helper definition is no object %v", d) + return + } + for pname, prop := range d.Properties { + prop.depth = d.depth + prop.name = pname + if util.StringsHas(d.Required, pname) { + prop.required = true + } + + refObjName := prop.getRef() + if refObjName != "" { + prop.ref = defs.GetOneDefinition(refObjName) + if prop.ref == nil { + prop.Type = DTUndefined // 未知 definition, 置空 + prop.Ref = "" + continue + } + prop.ref.depth = prop.depth + 1 + d.depth = prop.ref.depth + if d.depth > RefMaxDepth { + fmt.Printf("ref max depth exceed, definition name:%v, depth:%d, depth def:%v\n", + d.name, d.depth, prop.ref) + continue + } + prop.ref.ExpandProperties(defs) // 递归 + prop.ref.description = prop.Description + if prop.Type == "" { + prop.Type = DTObject + } + } + } +} + +// getRef 判断该 property 是否有下级嵌套 +// 如果有则存到 ref 中,且修改 Type 加上 嵌套类型 +func (p *Property) getRef() string { + if p.Ref != "" { + p.Type += " " + DTObject + return p.Ref + } else if p.AdditionalProperties != nil { + p.Type += ":map[string]" + " " + p.AdditionalProperties.Type // DTString + return p.getItemsNestedRef(p.AdditionalProperties) + } else if p.Items != nil { + p.Type += " " + p.Items.Type + return p.getItemsNestedRef(p.Items) + } + return "" +} + +func (p *Property) getItemsNestedRef(subRef *NestedRef) string { + if ref := subRef.RefMapObj.Ref; ref != "" { + p.Ref = ref + p.Type += " " + DTObject // DTArrayObject + return ref + } else if subRef.Items != nil { + if ref = subRef.Items.RefMapObj.Ref; ref != "" { + p.Ref = ref + p.Type += " " + DTObject // DTArrayObject + return ref + } + p.Type += " " + subRef.Items.Type + } + return "" +} + +// GetPathDefinitionHelper 结束命令字符串,打印描述 +// mysql mycnf-change +// /mysql/mycnf-change +func GetPathDefinitionHelper(subcmd string) error { + defer func() { + if r := recover(); r != nil { + // logger.Error("get helper failed %s: %s", subcmd, r, string(debug.Stack())) + } + }() + if strings.Contains(subcmd, " ") { + tmp := strings.Split(strings.TrimSpace(subcmd), " ") + subcmd = "/" + strings.Join(tmp, "/") + } + f := docs.SwaggerDocs + doc := "swagger.json" + b, err := f.ReadFile(doc) + if err != nil { + return err + } + jsonSpec := JsonSpec{} + if err := json.Unmarshal(b, &jsonSpec); err != nil { + fmt.Println(err) + log.Fatalln("docs/swagger.json 解析失败") + } + if pathObj, ok := jsonSpec.Paths[subcmd]; !ok { + fmt.Printf("未找到参数定义 %s\n", subcmd) + } else { + if params, ok := pathObj[DefinitionKey]; !ok { + fmt.Printf("未找到参数定义post %s\n", subcmd) + } else if len(params.Parameters) == 0 { + fmt.Printf("未找到参数定义param %s\n", subcmd) + } + } + // jsonSpec.Definitions.ExpandProperties() + pathDefinition := jsonSpec.Paths[subcmd][DefinitionKey] + pathDefinition.PrintDescription() + // parameters + reqSchema := pathDefinition.Parameters[0].Schema + schemaName := strings.TrimPrefix(reqSchema[RefKey], DefinitionPrefix) + thisDef := jsonSpec.Definitions[schemaName] + thisDef.ExpandProperties(&jsonSpec.Definitions) + thisDef.PrintProperties("", "\n# Param") + + // responses + for code, resp := range pathDefinition.Responses { + respSchema := resp.Schema + schemaName = strings.TrimPrefix(respSchema[RefKey], DefinitionPrefix) + thisDef = jsonSpec.Definitions[schemaName] + thisDef.ExpandProperties(&jsonSpec.Definitions) // 如果 param 对象里面包含了 resp 的对象,这里可能重复展开。暂不处理 + thisDef.PrintProperties("", "\n# Response "+code) + } + return nil +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/subcmd_util.go b/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/subcmd_util.go new file mode 100644 index 0000000000..c7f93d4e71 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/subcmd_util.go @@ -0,0 +1,24 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package subcmd + +import ( + "encoding/json" +) + +// ToPrettyJson TODO +func ToPrettyJson(v interface{}) string { + if data, err := json.MarshalIndent(v, "", " "); err == nil { + // ss := "\n# use --helper to show explanations. example for payload:\n --payload-format raw --payload '%s'" + return string(data) + } + return "未找到合法的 example " +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/sysinitcmd/sysinit.go b/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/sysinitcmd/sysinit.go new file mode 100644 index 0000000000..ac336bd03b --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/sysinitcmd/sysinit.go @@ -0,0 +1,86 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package sysinitcmd + +import ( + "dbm-services/common/go-pubpkg/logger" + "dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/components/sysinit" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/util" + + "github.com/spf13/cobra" +) + +// SysInitAct TODO +type SysInitAct struct { + *subcmd.BaseOptions + Service sysinit.SysInitParam +} + +// NewSysInitCommand TODO +func NewSysInitCommand() *cobra.Command { + act := SysInitAct{ + BaseOptions: subcmd.GBaseOptions, + } + cmd := &cobra.Command{ + Use: "sysinit", + Short: "test", + Example: `dbactuator sysinit -p e30=`, + Run: func(cmd *cobra.Command, args []string) { + util.CheckErr(act.Validate()) + util.CheckErr(act.Init()) + util.CheckErr(act.Run()) + }, + } + return cmd +} + +// Init TODO +func (d *SysInitAct) Init() (err error) { + if err = d.DeserializeAndValidate(&d.Service); err != nil { + logger.Error("DeserializeAndValidate err %s", err.Error()) + return err + } + return +} + +// Run TODO +func (s *SysInitAct) Run() (err error) { + steps := []subcmd.StepFunc{ + { + FunName: "预检测", + Func: s.Service.PreCheck, + }, + { + FunName: "创建系统目录", + Func: s.Service.CreateSysDir, + }, + { + FunName: "创建系统账号", + Func: s.Service.CreateSysUser, + }, + { + FunName: "执行sysInit脚本", + Func: s.Service.SysInitMachine, + }, + } + + logger.Info("start sysinit ...") + for idx, f := range steps { + if err = f.Func(); err != nil { + logger.Error("step <%d>, run [%s] occur %v", idx, f.FunName, err) + return err + } + logger.Info("step <%d>, run [%s] successfully", idx, f.FunName) + } + logger.Info("sysinit successfully") + return +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/sysinitcmd/sysinitcmd.go b/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/sysinitcmd/sysinitcmd.go new file mode 100644 index 0000000000..7cfef4a132 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/internal/subcmd/sysinitcmd/sysinitcmd.go @@ -0,0 +1,12 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +// Package sysinitcmd TODO +package sysinitcmd diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/base.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/base.go new file mode 100644 index 0000000000..ec39f34132 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/base.go @@ -0,0 +1,39 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package components + +// BaseInputParam TODO +type BaseInputParam struct { + GeneralParam *GeneralParam `json:"general"` + ExtendParam interface{} `json:"extend"` +} + +// GeneralParam TODO +type GeneralParam struct { + RuntimeAccountParam RuntimeAccountParam `json:"runtime_account"` + // more Runtime Struct +} + +// RuntimeAccountParam TODO +type RuntimeAccountParam struct { + // mssql 账户 + OSMssqlUser string `json:"mssql_user,omitempty"` + // mssql 密码 + OSMssqlPwd string `json:"mssql_pwd,omitempty"` + // sa 账户 + SAUser string `json:"sa_user,omitempty"` + // sa 密码 + SAPwd string `json:"sa_pwd,omitempty"` + // sqlserver 账户 + SQLServerUser string `json:"sqlserver_user,omitempty"` + // sqlserver 密码 + SQLServerPwd string `json:"sqlserver_pwd,omitempty"` +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/components.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/components.go new file mode 100644 index 0000000000..feb24ef392 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/components.go @@ -0,0 +1,12 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +// Package components TODO +package components diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/medium.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/medium.go new file mode 100644 index 0000000000..ccba4d5748 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/medium.go @@ -0,0 +1,47 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package components + +import ( + "fmt" + + "dbm-services/sqlserver/db-tools/dbactuator/pkg/core/cst" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/util" +) + +// Medium 通用介质包处理 +type Medium struct { + Pkg string `json:"pkg" validate:"required"` // 安装包名 + PkgMd5 string `json:"pkg_md5" validate:"required,md5"` // 安装包MD5 +} + +// Check TODO +func (m *Medium) Check() (err error) { + var fileMd5 string + // 判断安装包是否存在 + pkgAbPath := m.GetAbsolutePath() + if !util.FileExists(pkgAbPath) { + return fmt.Errorf("%s不存在", pkgAbPath) + } + if fileMd5, err = util.GetFileMd5(pkgAbPath); err != nil { + return fmt.Errorf("获取[%s]md5失败, %v", m.Pkg, err.Error()) + } + // 校验md5 + if fileMd5 != m.PkgMd5 { + return fmt.Errorf("安装包的md5不匹配,[%s]文件的md5[%s]不正确", fileMd5, m.PkgMd5) + } + return +} + +// GetAbsolutePath 返回介质存放的绝对路径 +func (m *Medium) GetAbsolutePath() string { + return fmt.Sprintf("%s%s\\%s", cst.BASE_DATA_PATH, cst.BK_PKG_INSTALL_NAME, m.Pkg) +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/output.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/output.go new file mode 100644 index 0000000000..27c34c0958 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/output.go @@ -0,0 +1,40 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package components + +import ( + "encoding/json" + "fmt" +) + +// WrapperOutputString TODO +func WrapperOutputString(output string) string { + return fmt.Sprintf(`%s`, output) +} + +// WrapperOutput TODO +func WrapperOutput(v interface{}) (string, error) { + if b, e := json.Marshal(v); e != nil { + return "", e + } else { + return fmt.Sprintf(`%s`, string(b)), nil + } +} + +// PrintOutputCtx TODO +func PrintOutputCtx(v interface{}) error { + if ss, err := WrapperOutput(v); err != nil { + return err + } else { + fmt.Println(ss) + } + return nil +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/sqlserver/install_sqlserver.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/sqlserver/install_sqlserver.go new file mode 100644 index 0000000000..70378f8b1c --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/sqlserver/install_sqlserver.go @@ -0,0 +1,498 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package sqlserver + +import ( + "bytes" + "encoding/json" + "fmt" + "html/template" + "os" + "strings" + + "dbm-services/common/go-pubpkg/logger" + "dbm-services/riak/db-tools/dbactuator/pkg/rollback" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/components" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/core/cst" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/util/sqlserver" + + "github.com/shirou/gopsutil/mem" +) + +// InstallSqlServerComp TODO +type InstallSqlServerComp struct { + GeneralParam *components.GeneralParam `json:"general"` + Params *InstallSqlServerParams `json:"extend"` + installSQLServerConfig `json:"-"` + RollBackContext rollback.RollBackObjects `json:"-"` +} + +// InitDirs TODO +type InitDirs = []string + +// Port TODO +type Port = int + +// InstallSqlServerParams TODO +type InstallSqlServerParams struct { + components.Medium + Ports []int `json:"ports" validate:"required,gt=0,dive"` + SQlServerVersion string `json:"sqlserver_version" validate:"required"` + Host string `json:"host" validate:"required,ip" ` + InstallKey string `json:"install_key" validate:"required" ` + BufferPercent uint64 `json:"buffer_percent" validate:"required,gt=0,lt=100"` + MaxRemainMemGB uint64 `json:"max_remain_mem_gb" validate:"required,gt=0"` + SQLServerConfigs json.RawMessage `json:"sqlserver_configs" validate:"required" ` +} + +// RenderConfigs TODO +// type RenderConfig struct { +// InstanceID string `json:"instance_id"` +// InstanceName string `json:"instance_name"` +// InstallKey string `json:"install_key"` +// DataDir string `json:"data_dir"` +// SqlSVCAccout string `json:"sql_svc_account"` +// SqlSVCPassWord string `json:"sql_svc_password"` +// AgtSVCAccount string `json:"agt_svc_account"` +// AgtSVCPassWord string `json:"agt_svc_password"` +// SAPwd string `json:"sa_pwd"` +// } + +// RenderConfig TODO +type RenderConfig struct { + InstanceID string + InstanceName string + InstallKey string + DataDir string + SqlSVCAccout string + SqlSVCPassWord string + AgtSVCAccount string + AgtSVCPassWord string + SAPwd string +} + +// Cnf TODO +type Cnf struct { + ConfFile string + MssqlConf json.RawMessage +} + +type installSQLServerConfig struct { + InstallDir string + DataRootPath string + BackupRootPath string + CnfTpls map[Port]*Cnf + InsPorts []Port + RenderConfigs map[Port]RenderConfig + InsInitDirs map[Port]InitDirs +} + +// Example TODO +func (i *InstallSqlServerComp) Example() interface{} { + comp := InstallSqlServerComp{ + Params: &InstallSqlServerParams{ + Medium: components.Medium{ + Pkg: "SQL2008x64_SorceMedia.7z", + PkgMd5: "xxx", + }, + Host: "1.1.1.1", + SQlServerVersion: "SQL2008x64", + Ports: []int{48322, 48332}, + InstallKey: "xxxx", + BufferPercent: 75, + MaxRemainMemGB: 32, + SQLServerConfigs: []byte(`{ + "48322":{"xxx":"xxx"}, + "48332":{"xxx":"xxx"} + }`), + }, + } + return comp +} + +// InitDefaultParam 初始化一些安装时需要的变量 +func (i *InstallSqlServerComp) InitDefaultParam() error { + i.InstallDir = cst.INSTALL_SQL_DATA_DIR + i.DataRootPath = fmt.Sprintf("%s\\%s", cst.BASE_DATA_PATH, cst.MSSQL_DATA_NAME) + i.InsPorts = i.Params.Ports + + // 判断E盘是否存在,如果存在,设计backup目录在E盘上 + e := osutil.WINSFile{FileName: cst.BASE_BACKUP_PATH} + if _, check := e.FileExists(); check { + i.BackupRootPath = fmt.Sprintf("%s\\%s", cst.BASE_BACKUP_PATH, cst.MSSQL_BACKUP_NAME) + } else { + i.BackupRootPath = fmt.Sprintf("%s\\%s", cst.BASE_DATA_PATH, cst.MSSQL_BACKUP_NAME) + } + + i.CnfTpls = make(map[int]*Cnf) + + // 反序列化sqlserver的配置 + var MssqlCnfs map[Port]json.RawMessage + if err := json.Unmarshal([]byte(i.Params.SQLServerConfigs), &MssqlCnfs); err != nil { + logger.Error("反序列化配置失败:%s", err.Error()) + return err + } + + // 计算每个实例需要安装的配置信息 + for _, port := range i.InsPorts { + var conf json.RawMessage + var ok bool + confFile := fmt.Sprintf( + "%s\\%s\\%s_%d", cst.BASE_DATA_PATH, cst.BK_PKG_INSTALL_NAME, cst.CONFIGURATION_FILE_NAME, port, + ) + if conf, ok = MssqlCnfs[port]; !ok { + return fmt.Errorf("参数中没有%d的配置", port) + } + i.CnfTpls[port] = &Cnf{ConfFile: confFile, MssqlConf: conf} + } + // 计算需要替换的安装配置参数 + i.RenderConfigs = make(map[Port]RenderConfig) + for _, port := range i.InsPorts { + i.RenderConfigs[port] = RenderConfig{ + InstanceID: osutil.GetInstallName(port), + InstanceName: osutil.GetInstallName(port), + InstallKey: i.Params.InstallKey, + DataDir: fmt.Sprintf("%s\\\\%d", i.DataRootPath, port), + SqlSVCAccout: i.GeneralParam.RuntimeAccountParam.SQLServerUser, + SqlSVCPassWord: i.GeneralParam.RuntimeAccountParam.SQLServerPwd, + AgtSVCAccount: i.GeneralParam.RuntimeAccountParam.SQLServerUser, + AgtSVCPassWord: i.GeneralParam.RuntimeAccountParam.SQLServerPwd, + SAPwd: i.GeneralParam.RuntimeAccountParam.SAPwd, + } + } + + return nil +} + +// CheckDataDir 检测数据目录是否存在 +func (i *InstallSqlServerComp) CheckDataDir() error { + dataDir := osutil.WINSFile{FileName: i.DataRootPath} + err, check := dataDir.FileExists() + if err != nil { + return err + } + if !check { + return fmt.Errorf("data dir [%s] not exists!", i.DataRootPath) + } + return nil +} + +// CheckMssqlProcess 判断本地是否部署mssql开头的服务进程 +func (i *InstallSqlServerComp) CheckMssqlProcess() error { + ret, err := osutil.StandardPowerShellCommand( + "GET-SERVICE -NAME MSSQL* | " + + "WHERE-OBJECT {$_.STATUS -EQ \"RUNNING\" -AND $_.NAME -NOTLIKE \"*#*\"} | " + + "SELECT-OBJECT -PROPERTY NAME", + ) + if err != nil { + return err + } + if ret != "" { + // 输出不为空则表示有部署进程 + return fmt.Errorf("There is a mssql process, check!:[%s]", osutil.CleanExecOutput(ret)) + } + return nil +} + +// PreCheck 预检测,检测必要目录、进程、介质包的md5 +func (i *InstallSqlServerComp) PreCheck() error { + // 验证文件的md5值 + if err := i.Params.Medium.Check(); err != nil { + logger.Error("md5 check failed %s", err.Error()) + return err + } + // 检测机器是否存在必要目录 + if err := i.CheckDataDir(); err != nil { + logger.Error("check datadir failed %s", err.Error()) + return err + } + // 检测机器是否有启动mssql服务,如果有则退出,表示机器不属于干净机器 + if err := i.CheckMssqlProcess(); err != nil { + logger.Error("check mssql process failed %s", err.Error()) + return err + } + + return nil +} + +// GenerateCnf 生成sqlserver安装配置 +func (i *InstallSqlServerComp) GenerateCnf() error { + for _, port := range i.InsPorts { + // 模板配置渲染 + var rendered bytes.Buffer + + tmpl := template.Must(template.New("conf").Parse(string(i.CnfTpls[port].MssqlConf))) + err := tmpl.Execute(&rendered, i.RenderConfigs[port]) + if err != nil { + return err + } + // 生成对应配置文件 + if err := osutil.CreateInstallConf( + []byte(rendered.String()), i.CnfTpls[port].ConfFile, i.Params.SQlServerVersion); err != nil { + return err + } + } + return nil +} + +// InitInstanceDirs 负责生成每个实例下的数据目录 +// 因为安装SQLserver时候数据目录是不影响安装进度的,所以这里如果检测不存在,则做生成处理 +func (i *InstallSqlServerComp) InitInstanceDirs() error { + for _, port := range i.InsPorts { + dataDir := fmt.Sprintf("%s\\\\%d", i.DataRootPath, port) + f := osutil.WINSFile{FileName: dataDir} + if _, check := f.FileExists(); !check { + // 不存在则创建 + logger.Info(fmt.Sprintf("data dir [%s] not exists, create", dataDir)) + if !f.Create(0777) { + return fmt.Errorf("create dir [%s] failed", dataDir) + } + } + // 目录归属于mssql账号 + if !f.SetChown(i.GeneralParam.RuntimeAccountParam.OSMssqlUser) { + return fmt.Errorf("create dir [%s] failed", dataDir) + } + // 目录归属于sqlserver账号 + if !f.SetChown(i.GeneralParam.RuntimeAccountParam.SQLServerUser) { + return fmt.Errorf("create dir [%s] failed", dataDir) + } + } + return nil +} + +// DecompressPkg TODO +// 解压安装文件,支持.7z 和 .zip的解压方式 +func (i *InstallSqlServerComp) DecompressPkg() error { + switch { + case strings.Contains(i.Params.Pkg, ".7z"): + // 安装包属于7z文件包,选择7z的解压方式 + _, err := osutil.StandardPowerShellCommand( + fmt.Sprintf(" & '%s' x -y %s -o%s ", cst.SQLSERVER_UNZIP_TOOL, i.Params.GetAbsolutePath(), cst.BASE_DATA_PATH), + ) + if err != nil { + return err + } + case strings.Contains(i.Params.Pkg, ".zip"): + // 安装包属于zip文件包,选择zip的解压方式 + _, err := osutil.StandardPowerShellCommand( + fmt.Sprintf("Expand-Archive -Path %s -DestinationPath %s", i.Params.GetAbsolutePath(), cst.BASE_DATA_PATH), + ) + if err != nil { + return err + } + default: + return fmt.Errorf("[%s] Currently only supports decompression of .7z files and .zip files. check", i.Params.Pkg) + } + + logger.Info("decompress mysql pkg successfully") + return nil +} + +// SqlServerStartup TODO +// 遍历端口,启动实例 +func (i *InstallSqlServerComp) SqlServerStartup() error { + // 导入相关模块 + cmds := []string{ + "IMPORT-MODULE SERVERMANAGER", + "ADD-WINDOWSFEATURE TELNET-CLIENT", + } + if _, err := osutil.StandardPowerShellCommands(cmds); err != nil { + return err + } + // 遍历端口安装启动实例 + for _, port := range i.InsPorts { + _, err := osutil.StandardPowerShellCommand( + fmt.Sprintf( + "& %s\\%s\\setup.exe /ConfigurationFile=%s", + cst.BASE_DATA_PATH, + osutil.GetInstallPackageName(i.Params.SQlServerVersion), + i.CnfTpls[port].ConfFile, + ), + ) + if err != nil { + i.DeleteConfs() + return err + } + logger.Info("installing sqlserver instance [%d] successfully") + } + i.DeleteConfs() + return nil +} + +// DeleteConfs 删除所有实例配置安装配置, 无论是安装失败或者成功 +func (i *InstallSqlServerComp) DeleteConfs() error { + var cmds []string + for _, port := range i.InsPorts { + cmds = append(cmds, fmt.Sprintf("REMOVE-ITEM %s", i.CnfTpls[port].ConfFile)) + } + if _, err := osutil.StandardPowerShellCommands(cmds); err != nil { + return err + } + return nil +} + +// InitConfigs 成功安装之后初始化配置 +func (i *InstallSqlServerComp) InitConfigs() error { + logger.Info("start exec init_sqlserver ...") + data, err := staticembed.InitSqlServer.ReadFile(staticembed.InitSqlServerFileName) + if err != nil { + logger.Error("read init_sqlserver script failed %s", err.Error()) + return err + } + tmpScriptName := fmt.Sprintf("%s\\%s\\init_sqlserver.ps1", cst.BASE_DATA_PATH, cst.BK_PKG_INSTALL_NAME) + if err = os.WriteFile(tmpScriptName, data, 0755); err != nil { + logger.Error("write tmp script failed %s", err.Error()) + return err + } + var InstanceNames []string + var HADREnabled int = 0 + var SSMSEnabled int = 0 + for _, port := range i.InsPorts { + InstanceNames = append(InstanceNames, osutil.GetInstallName(port)) + } + num, err := osutil.GetVersionYears(i.Params.SQlServerVersion) + if err != nil { + return err + } + if num >= 2017 { + // 版本大于2017,安装allway-on集群模块 + HADREnabled = 1 + } + if num >= 2016 { + // 版本大于2016,需要安装smss18版本 + SSMSEnabled = 1 + } + cmd := fmt.Sprintf("& %s %s %s %s %d %d", + tmpScriptName, + i.Params.Host, + i.Params.SQlServerVersion, + strings.Join(InstanceNames, ","), + HADREnabled, + SSMSEnabled, + ) + + if _, err := osutil.StandardPowerShellCommand(cmd); err != nil { + logger.Error("exec init script failed %s", err.Error()) + return err + } + // 执行完成后删除文件,删除失败不退出 + remoteCmd := fmt.Sprintf("REMOVE-ITEM %s", tmpScriptName) + if _, err := osutil.StandardPowerShellCommand(remoteCmd); err != nil { + logger.Warn("delete init-script failed %s", err.Error()) + } + return nil +} + +// InitDB TODO +// 按照实例维度初始化实例DB +func (i *InstallSqlServerComp) InitDB() error { + // 把初始化sql脚本加载到本地d: + var files []string + var err error + if files, err = WriteInitSQLFile(); err != nil { + return err + } + for _, port := range i.InsPorts { + if err := sqlserver.ExecLocalSQLFile(i.Params.SQlServerVersion, files, port); err != nil { + return err + } + } + // 执行完成后删除文件,删除失败不退出 + for _, file := range files { + remoteCmd := fmt.Sprintf("REMOVE-ITEM %s", file) + if _, err := osutil.StandardPowerShellCommand(remoteCmd); err != nil { + logger.Warn("delete [%s] failed %s", file, err.Error()) + } + } + + return nil +} + +// InitInstanceBuffer TODO +// 计算每个实例的内存分配 +func (i *InstallSqlServerComp) InitInstanceBuffer() error { + + // 获取系统物理内存 + mem, err := mem.VirtualMemory() + if err != nil { + return err + } + // 计算每个实例分配到内存 + var secondUsedMem float32 = 0 + usedMem := float32(mem.Total) * (float32(i.Params.BufferPercent) / 100) + if usedMem > float32(i.Params.MaxRemainMemGB*1024*1024*1024) { + secondUsedMem = usedMem - float32(i.Params.MaxRemainMemGB*1024*1024*1024) + } + instMemMB := (usedMem + secondUsedMem) / float32(len(i.InsPorts)) / 1024 / 1024 + logger.Info("%d", int(instMemMB)) + + cmds := []string{ + "EXEC SP_CONFIGURE 'SHOW ADVANCED OPTIONS',1;", + "RECONFIGURE;", + fmt.Sprintf("EXEC SP_CONFIGURE N'MIN SERVER MEMORY (MB)', N'%d';", int(instMemMB)), + fmt.Sprintf("EXEC SP_CONFIGURE N'MAX SERVER MEMORY (MB)', N'%d';", int(instMemMB)), + "RECONFIGURE;", + "EXEC SP_CONFIGURE 'SHOW ADVANCED OPTIONS',0;", + "RECONFIGURE;", + } + // 内存分配加载到实例上 + for _, port := range i.InsPorts { + var dbWork *sqlserver.DbWorker + if dbWork, err = sqlserver.NewDbWorker( + i.GeneralParam.RuntimeAccountParam.SAUser, + i.GeneralParam.RuntimeAccountParam.SAPwd, + i.Params.Host, + port, + ); err != nil { + logger.Error("connenct by %s failed,err:%s", port, err.Error()) + return err + } + // 到最后回收db连接 + defer dbWork.Stop() + + if _, err := dbWork.ExecMore(cmds); err != nil { + logger.Error("exec SERVER MEMORY failed %v", err) + return err + } + + } + + return nil +} + +// WriteInitSQLFile TODO +// 把初始化的sql文件写入到本地 +func WriteInitSQLFile() ([]string, error) { + var dealFiles []string + sqls := []string{ + staticembed.MonitorFileName, + staticembed.BackupFileName, + staticembed.AutoSwitchFileName, + staticembed.SqlSettingFileName, + } + + for _, sqlFile := range sqls { + data, err := staticembed.SQLScript.ReadFile(sqlFile) + if err != nil { + logger.Error("read sql script failed %s", err.Error()) + return nil, err + } + tmpScriptName := fmt.Sprintf("%s\\%s", cst.BASE_DATA_PATH, sqlFile) + if err = os.WriteFile(tmpScriptName, data, 0755); err != nil { + logger.Error("write sql script failed %s", err.Error()) + return nil, err + } + dealFiles = append(dealFiles, tmpScriptName) + } + return dealFiles, nil +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/sqlserver/sqlserver.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/sqlserver/sqlserver.go new file mode 100644 index 0000000000..d3009aee0c --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/sqlserver/sqlserver.go @@ -0,0 +1,12 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +// Package sqlserver TODO +package sqlserver diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/sqlserver/uninstall_sqlserver.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/sqlserver/uninstall_sqlserver.go new file mode 100644 index 0000000000..75aa203e3d --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/sqlserver/uninstall_sqlserver.go @@ -0,0 +1,130 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package sqlserver + +import ( + "fmt" + + "dbm-services/common/go-pubpkg/logger" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/components" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/util/sqlserver" +) + +// UnInstallSQLServerComp 卸载SQLServer +type UnInstallSQLServerComp struct { + GeneralParam *components.GeneralParam + Params *UnInstallSQLServerParam + runTimeCtx +} + +// UnInstallSQLServerParam 参数 +type UnInstallSQLServerParam struct { + Host string `json:"host" validate:"required,ip" ` + Force bool `json:"force"` // 是否强制下架 + Ports []int `json:"ports" validate:"required,gt=0,dive"` // 被监控机器的上所有需要监控的端口 + +} + +// 运行是需要的必须参数,可以提前计算 +type runTimeCtx struct { + insObj map[Port]*obj +} + +// obj 每个实例当前状态 +type obj struct { + InstanceName string + IsShutdown bool // 标记卸载的实例是否已经是关闭/不能访问的状态 +} + +// Init 初始化 +func (u *UnInstallSQLServerComp) Init() error { + u.insObj = make(map[int]*obj) + for _, port := range u.Params.Ports { + u.insObj[port] = &obj{ + InstanceName: "", + IsShutdown: false, // 初始化给个默认值,后续判断实例是否正常才变更 + } + } + return nil + +} + +// PreCheck 预检查 +// 检查实例连接 +func (u *UnInstallSQLServerComp) PreCheck() error { + var isPass bool = true + checkCmd := "SELECT count(0) FROM SYS.SYSPROCESSES WHERE LOGINAME NOT LIKE '%\\%' " + + "AND LOGINAME NOT LIKE '%#%' AND LOGINAME NOT LIKE 'distributor%' AND LOGINAME not in('sa','monitor')" + for _, port := range u.Params.Ports { + var dbWork *sqlserver.DbWorker + var err error + var cnt int + if dbWork, err = sqlserver.NewDbWorker( + u.GeneralParam.RuntimeAccountParam.SAUser, + u.GeneralParam.RuntimeAccountParam.SAPwd, + u.Params.Host, + port, + ); err != nil { + logger.Warn("connenct by %d failed,err:%s", port, err.Error()) + logger.Warn("this port [%d] is considered closed", port) + // 连接不上标记为实例已关闭状态 + u.insObj[port].IsShutdown = true + continue + } + // 到最后回收db连接 + defer dbWork.Stop() + + if err := dbWork.Queryxs(&cnt, checkCmd); err != nil { + logger.Error("check processlist failed %v", err) + isPass = false + } + if cnt != 0 && !u.Params.Force { + // 存在用户连接且安全下架情况,退出异常 + logger.Error("There is a business connections [%d] on this port [%d]", cnt, port) + isPass = false + + } else { + // 检测通过,获取实例名称 + if err := dbWork.Queryxs( + &u.insObj[port].InstanceName, + "SELECT SERVERPROPERTY('InstanceName') ;"); err != nil { + return fmt.Errorf("[%s] check InstanceName failed %v", port, err) + } + } + } + if !isPass { + return fmt.Errorf("prechek failed") + } + return nil +} + +// ShutDownMSSQL TODO +// PreCheck 关闭MSSQL进程 +func (u *UnInstallSQLServerComp) ShutDownMSSQL() error { + // 按照实例关闭进程 + for _, port := range u.Params.Ports { + if u.insObj[port].IsShutdown { + logger.Info(" The port [%d] skips closing ", port) + continue + } + cmds := []string{ + fmt.Sprintf("Stop-Service -Name \"SQLAGENT`$%s\"", u.insObj[port].InstanceName), + fmt.Sprintf("Stop-Service -Name \"MSSQL`$%s\"", u.insObj[port].InstanceName), + fmt.Sprintf("Set-Service -Name \"SQLAGENT`$%s\" -StartupType Disabled ", u.insObj[port].InstanceName), + fmt.Sprintf("Set-Service -Name \"MSSQL`$%s\" -StartupType Disabled ", u.insObj[port].InstanceName), + } + if _, err := osutil.StandardPowerShellCommands(cmds); err != nil { + return err + } + } + return nil +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/sysinit/sysinit.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/sysinit/sysinit.go new file mode 100644 index 0000000000..7fb3b0d9ad --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/components/sysinit/sysinit.go @@ -0,0 +1,210 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +// Package sysinit TODO +package sysinit + +import ( + "fmt" + "os" + + "dbm-services/common/go-pubpkg/logger" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/core/cst" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil" + + "github.com/shirou/gopsutil/mem" +) + +// SysInitParam TODO +type SysInitParam struct { + OSMssqlUser string `json:"mssql_user"` + OSMssqlPwd string `json:"mssql_pwd"` + SQLServerUser string `json:"sqlserver_user"` + SQLServerPwd string `json:"sqlserver_pwd"` +} + +/* + 执行系统初始化脚本 原来的sysinit.sh + 创建mssql账户等操作 +*/ + +// PreCheck 初始化的预检测 +func (s *SysInitParam) PreCheck() error { + // 判断机器是否数据盘D盘,如果没有存在则异常 + d := osutil.WINSFile{FileName: cst.BASE_DATA_PATH} + err, check := d.FileExists() + if err != nil { + return err + } + if !check { + return fmt.Errorf("data dir [%s] not exists!", cst.BASE_DATA_PATH) + } + logger.Info("data dir [%s] exists, pass", cst.BASE_DATA_PATH) + + // 检查SQLserver的安装目录是否存在, 如果存在证明机器部署SQLserver实例 + dirGroup := []string{ + cst.INSTALL_SHARED_DIR, + cst.INSTALL_SHARED_WOW_DIR, + cst.INSTALL_SQL_DATA_DIR, + } + isErr := false + for _, dir := range dirGroup { + d := osutil.WINSFile{FileName: dir} + err, check := d.FileExists() + if err != nil { + logger.Error(err.Error()) + isErr = true + } + if check { + logger.Error("dir [%s] exists, check!", dir) + isErr = true + } + logger.Info("The dir [%s] not exists , pass", dir) + } + if isErr { + return fmt.Errorf("percheck failed") + } + + // 检测机器内存容量,低于2GB不允许安装SqlServer + mem, err := mem.VirtualMemory() + if err != nil { + return err + } + if mem.Total < 2*1024*1024*2024 { + return fmt.Errorf("System memory does not exceed 2GB") + } + logger.Info("System memory exceed 2GB, pass") + return nil +} + +// CreateSysUser 创建需要的系统账号 +func (s *SysInitParam) CreateSysUser() error { + logger.Info("start exec createSysUser ...") + // 创建mssql账号 + mssql := osutil.WINSOSUser{ + User: s.OSMssqlUser, + Pass: s.OSMssqlPwd, + Comment: "SQL SERVER ACCOUNT", + } + if mssql.UserExists() { + if err := mssql.SetUerPass(); err != nil { + return err + } + } else { + if err := mssql.CreateUser(false); err != nil { + return err + } + } + if err := mssql.AddGroupMember("Administrators"); err != nil { + return err + } + if err := mssql.RemoveGroupMember("Users"); err != nil { + return err + } + logger.Info("create system-user [%s] successfully ", s.OSMssqlUser) + + // 创建sqlserver账号 + sqlserver := osutil.WINSOSUser{ + User: s.SQLServerUser, + Pass: s.SQLServerPwd, + Comment: "SQL SERVER SERVICE ACCOUNT", + } + if sqlserver.UserExists() { + if err := sqlserver.SetUerPass(); err != nil { + return err + } + } else { + if err := sqlserver.CreateUser(false); err != nil { + return err + } + } + if err := sqlserver.AddGroupMember("Administrators"); err != nil { + return err + } + if err := sqlserver.RemoveGroupMember("Users"); err != nil { + return err + } + logger.Info("create system-user [%s] successfully ", s.SQLServerUser) + + return nil +} + +// CreateSysDir TODO +func (s *SysInitParam) CreateSysDir() error { + logger.Info("start exec createSysDir ...") + createDir := []string{ + fmt.Sprintf("%s\\%s", cst.BASE_DATA_PATH, cst.BK_PKG_INSTALL_NAME), + fmt.Sprintf("%s\\%s", cst.BASE_DATA_PATH, cst.MSSQL_DATA_NAME), + fmt.Sprintf("%s\\%s", cst.BASE_DATA_PATH, cst.MSSQL_BACKUP_NAME), + fmt.Sprintf("%s\\%s", cst.BASE_DATA_PATH, cst.IEOD_FILE_BACKUP), + fmt.Sprintf("%s\\%s\\%s", cst.BASE_DATA_PATH, cst.MSSQL_BACKUP_NAME, "full"), + fmt.Sprintf("%s\\%s\\%s", cst.BASE_DATA_PATH, cst.MSSQL_BACKUP_NAME, "log"), + } + // 判断机器是否存在E盘,如果有在创建必要目录 + e := osutil.WINSFile{FileName: cst.BASE_BACKUP_PATH} + err, check := e.FileExists() + if err != nil { + logger.Warn(err.Error()) + } + if check { + // 添加E盘必须创建的目录 + createDir = append(createDir, fmt.Sprintf("%s\\%s", cst.BASE_DATA_PATH, cst.BASE_BACKUP_PATH)) + createDir = append(createDir, fmt.Sprintf("%s\\%s\\%s", cst.BASE_DATA_PATH, cst.BASE_BACKUP_PATH, "full")) + createDir = append(createDir, fmt.Sprintf("%s\\%s\\%s", cst.BASE_DATA_PATH, cst.BASE_BACKUP_PATH, "log")) + } + + // 循环创建目录 + for _, dirName := range createDir { + dir := osutil.WINSFile{FileName: dirName} + err, check := dir.FileExists() + if check && err == nil { + // 表示目录在系统存在,先跳过 + continue + } + if err != nil { + // 表示检查目录是否存在出现异常,报错 + return err + } + // 创建目录 + if !dir.Create(0777) { + return fmt.Errorf("create dir [%s] failed", dirName) + } + logger.Info("create system-dir [%s] successfully", dirName) + } + return nil +} + +// SysInitMachine TODO +func (s *SysInitParam) SysInitMachine() error { + logger.Info("start exec sysinit ...") + data, err := staticembed.SysInitScript.ReadFile(staticembed.SysInitScriptFileName) + if err != nil { + logger.Error("read sysinit script failed %s", err.Error()) + return err + } + tmpScriptName := fmt.Sprintf("%s\\%s\\sysinit.ps1", cst.BASE_DATA_PATH, cst.BK_PKG_INSTALL_NAME) + if err = os.WriteFile(tmpScriptName, data, 0755); err != nil { + logger.Error("write tmp script failed %s", err.Error()) + return err + } + _, err = osutil.StandardPowerShellCommand( + fmt.Sprintf("& %s ", tmpScriptName), + ) + if err != nil { + return err + } + if err := os.RemoveAll(tmpScriptName); err != nil { + logger.Warn("delete sysinit-file failed :[%s]", err.Error()) + } else { + logger.Info("delete sysinit-file success") + } + return nil +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/codes/codes.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/codes/codes.go new file mode 100644 index 0000000000..6d19c52388 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/codes/codes.go @@ -0,0 +1,72 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +// Package codes TODO +package codes + +/* +@description: 相关错误码及对应错误类型 +@rules: +1. 初始化类的错误码使用 30000-39999 +2. 操作系统的错误码使用 40000-49999 +3. MySQL、Redis、Mongo实例操作的错误码 50000-59999 +*/ + +const ( + // Unauthorized TODO + Unauthorized = 10001 + // UnmarshalFailed TODO + UnmarshalFailed = 10002 + // NotExistMountPoint TODO + NotExistMountPoint = 20001 + // NotExistUser TODO + NotExistUser = 20002 + // PermissionDeny TODO + PermissionDeny = 20003 + + // RenderConfigFailed TODO + RenderConfigFailed = 30001 + // InitParamFailed TODO + InitParamFailed = 30002 + // InitMySQLDirFailed TODO + InitMySQLDirFailed = 30003 + + // InstallMySQLFailed TODO + InstallMySQLFailed = 40001 + // ExecuteShellFailed TODO + ExecuteShellFailed = 40002 + // DecompressPkgFailed TODO + DecompressPkgFailed = 40003 + // StartMySQLFailed TODO + StartMySQLFailed = 40004 + // NotAvailableMem TODO + NotAvailableMem = 40005 + + // ImportPrivAndSchemaFailed TODO + ImportPrivAndSchemaFailed = 50001 +) + +// ErrorCodes TODO +var ErrorCodes = map[int]string{ + Unauthorized: "没有进行用户认证", + UnmarshalFailed: "反序列化失败", + NotExistMountPoint: "没有可用的挂载点", + NotExistUser: "用户不存在", + PermissionDeny: "权限不足", + RenderConfigFailed: "初始化配置失败", + InitParamFailed: "初始化参数失败", + InitMySQLDirFailed: "初始化MySQL目录失败", + InstallMySQLFailed: "安装实例失败", + ExecuteShellFailed: "执行Shell脚本失败", + DecompressPkgFailed: "解压文件失败", + StartMySQLFailed: "启动MySQL失败", + NotAvailableMem: "内存不可用", + ImportPrivAndSchemaFailed: "导入权限和库失败", +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/cst/const.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/cst/const.go new file mode 100644 index 0000000000..462079f6f9 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/cst/const.go @@ -0,0 +1,84 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package cst + +const ( + // Environment TODO + Environment = "enviroment" + // Test TODO + Test = "test" +) + +const ( + // TIMELAYOUT TODO + TIMELAYOUT = "2006-01-02 15:04:05" + // TIMELAYOUTSEQ TODO + TIMELAYOUTSEQ = "2006-01-02_15:04:05" + // TimeLayoutDir TODO + TimeLayoutDir = "20060102150405" +) + +const ( + // BASE_DATA_PATH 默认基础数据盘符,默认D盘 + BASE_DATA_PATH = "D:\\" + // BASE_BACKUP_PATH 默认基础备份盘符,默认E盘 + BASE_BACKUP_PATH = "E:\\" + // BK_PKG_INSTALL_NAME 默认可执行文件的目录名称 + BK_PKG_INSTALL_NAME = "install" + // MSSQL_DATA_NAME 默认存储数据的目录名称 + MSSQL_DATA_NAME = "gamedb" + // MSSQL_BACKUP_NAME 默认存储日志的目录名称 + MSSQL_BACKUP_NAME = "dbbak" + // CONFIGURATION_FILE_NAME 实例安装文件名称 + CONFIGURATION_FILE_NAME = "configuationfile" + // DB_PORT_INIT 默认DB起始端口 + DB_PORT_INIT = 48322 + // MIRRORING_PORT_INIT 镜像服务起始端口 + MIRRORING_PORT_INIT = 37022 + // INSTALL_SHARED_DIR TODO + INSTALL_SHARED_DIR = "C:\\Program Files\\Microsoft SQL Server" + // INSTALL_SHARED_WOW_DIR TODO + INSTALL_SHARED_WOW_DIR = "C:\\Program Files (x86)\\Microsoft SQL Server" + // INSTANCE_DIR TODO + INSTANCE_DIR = "C:\\Program Files\\Microsoft SQL Server" + // INSTALL_SQL_DATA_DIR TODO + INSTALL_SQL_DATA_DIR = "D:\\Microsoft SQL Server" + // IEOD_FILE_BACKUP 备份系统上传的必需目录 + IEOD_FILE_BACKUP = "IEOD_FILE_BACKUP" + // SQLSERVER_UNZIP_TOOL TODO + // SQLserver安装包解压工具,默认初始化会有7z解压工具 + SQLSERVER_UNZIP_TOOL = "C:\\Program Files\\7-Zip\\7z" +) + +// 定义一些sqlserver专用的注册表信息 +const ( + MASTER_KEY_SHORT = "HKLM:\\SOFTWARE\\Microsoft\\Microsoft SQL Server\\" + MASTER_KEY = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SQL Server\\" + DETAIL_KEY = "\\MSSQLServer\\SuperSocketNetLib\\Tcp" + DETAIL_HADR_KEY = "\\MSSQLServer" +) + +// 定义不同mssql版本的sqlcmd的文件路径 + +const ( + // SQLCMD_2019 TODO + SQLCMD_2019 = "C:\\Program Files\\Microsoft SQL Server\\Client SDK\\ODBC\170\\Tools\\Binn\\SQLCMD.EXE" + // SQLCMD_2017 TODO + SQLCMD_2017 = "C:\\Program Files\\Microsoft SQL Server\\Client SDK\\ODBC\150\\Tools\\Binn\\SQLCMD.EXE" + // SQLCMD_2016 TODO + SQLCMD_2016 = "C:\\Program Files\\Microsoft SQL Server\\Client SDK\\ODBC\130\\Tools\\Binn\\SQLCMD.EXE" + // SQLCMD_2014 TODO + SQLCMD_2014 = "C:\\Program Files\\Microsoft SQL Server\\Client SDK\\ODBC\110\\Tools\\Binn\\SQLCMD.EXE" + // SQLCMD_2012 TODO + SQLCMD_2012 = "C:\\Program Files\\Microsoft SQL Server\\110\\Tools\\Binn\\SQLCMD.EXE" + // SQLCMD_2008 TODO + SQLCMD_2008 = "C:\\Program Files\\Microsoft SQL Server\\100\\Tools\\Binn\\SQLCMD.EXE" +) diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/cst/cst.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/cst/cst.go new file mode 100644 index 0000000000..03298c4389 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/cst/cst.go @@ -0,0 +1,12 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +// Package cst TODO +package cst diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/cst/os.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/cst/os.go new file mode 100644 index 0000000000..baedbd9bd8 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/cst/os.go @@ -0,0 +1,18 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package cst + +// bits +const ( + Bit64 = "64" + Bit32 = "32" + OSBits = 32 << uintptr(^uintptr(0)>>63) +) diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/01_monitor.sql b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/01_monitor.sql new file mode 100644 index 0000000000..096293e66c --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/01_monitor.sql @@ -0,0 +1,2491 @@ +USE MASTER +SET QUOTED_IDENTIFIER ON +SET NOCOUNT ON +GO +--**************************************** 结束当前启用的跟踪 ******************************* +DECLARE @SQL VARCHAR(8000) +SELECT @SQL = ISNULL(@SQL+' +','')+'EXEC SP_TRACE_SETSTATUS '+LTRIM(ID)+',0;EXEC SP_TRACE_SETSTATUS '+LTRIM(ID)+',2;' +FROM SYS.TRACES A +WHERE A.IS_DEFAULT = 0 +--PRINT(@SQL) +EXEC(@SQL) +GO + +--****************************************** 结束连接 ************************************ +DECLARE @SQL VARCHAR(MAX) +SELECT @SQL = ISNULL(@SQL+CHAR(13),'')+'KILL '+LTRIM(SPID) +FROM SYS.SYSPROCESSES +WHERE DBID = DB_ID('Monitor') + AND SPID > 50 +--PRINT(@SQL) +EXEC(@SQL) +GO + +IF DB_ID('Monitor') IS NOT NULL +BEGIN + ALTER DATABASE Monitor SET SINGLE_USER WITH ROLLBACK IMMEDIATE + DROP DATABASE Monitor +END + +--****************************************** DATABASE **************************************** +DECLARE @SQL VARCHAR(MAX) = ' +CREATE DATABASE Monitor +ON PRIMARY +(NAME = ''Monitor'',FILENAME = ''D:\gamedb\Monitor_'+@@SERVICENAME+'.mdf'',SIZE = 100MB,MAXSIZE = UNLIMITED,FILEGROWTH = 100MB) +LOG ON +(NAME = ''Monitor_log'',FILENAME = ''D:\gamedb\Monitor_'+@@SERVICENAME+'.ldf'',SIZE = 100MB,MAXSIZE = 2048GB,FILEGROWTH = 100MB) +COLLATE Chinese_PRC_CI_AS' +--PRINT(@SQL) +EXEC(@SQL) +GO +ALTER DATABASE [Monitor] SET COMPATIBILITY_LEVEL = 100 +GO +ALTER DATABASE [Monitor] SET ANSI_NULL_DEFAULT OFF +ALTER DATABASE [Monitor] SET ANSI_NULLS OFF +ALTER DATABASE [Monitor] SET ANSI_PADDING OFF +ALTER DATABASE [Monitor] SET ANSI_WARNINGS OFF +ALTER DATABASE [Monitor] SET ARITHABORT OFF +ALTER DATABASE [Monitor] SET AUTO_CLOSE OFF +ALTER DATABASE [Monitor] SET AUTO_CREATE_STATISTICS ON +ALTER DATABASE [Monitor] SET AUTO_SHRINK OFF +ALTER DATABASE [Monitor] SET AUTO_UPDATE_STATISTICS ON +ALTER DATABASE [Monitor] SET CURSOR_CLOSE_ON_COMMIT OFF +ALTER DATABASE [Monitor] SET CURSOR_DEFAULT GLOBAL +ALTER DATABASE [Monitor] SET CONCAT_NULL_YIELDS_NULL OFF +ALTER DATABASE [Monitor] SET NUMERIC_ROUNDABORT OFF +ALTER DATABASE [Monitor] SET QUOTED_IDENTIFIER ON +ALTER DATABASE [Monitor] SET RECURSIVE_TRIGGERS OFF +ALTER DATABASE [Monitor] SET DISABLE_BROKER +ALTER DATABASE [Monitor] SET AUTO_UPDATE_STATISTICS_ASYNC ON +ALTER DATABASE [Monitor] SET DATE_CORRELATION_OPTIMIZATION OFF +ALTER DATABASE [Monitor] SET TRUSTWORTHY OFF +ALTER DATABASE [Monitor] SET ALLOW_SNAPSHOT_ISOLATION OFF +ALTER DATABASE [Monitor] SET PARAMETERIZATION SIMPLE +ALTER DATABASE [Monitor] SET READ_COMMITTED_SNAPSHOT OFF +ALTER DATABASE [Monitor] SET HONOR_BROKER_PRIORITY OFF +ALTER DATABASE [Monitor] SET READ_WRITE +ALTER DATABASE [Monitor] SET RECOVERY SIMPLE +ALTER DATABASE [Monitor] SET MULTI_USER +ALTER DATABASE [Monitor] SET PAGE_VERIFY CHECKSUM +ALTER DATABASE [Monitor] SET DB_CHAINING OFF +GO + +--****************************************** LOGIN **************************************** +IF SUSER_SID('monitor') IS NOT NULL + DROP LOGIN monitor +CREATE LOGIN monitor WITH PASSWORD=N'2zhlmcNdffff',DEFAULT_DATABASE=[MASTER],SID=0xADDEFF187E19CB4593D2DB00A0D287B1,CHECK_POLICY=OFF; +GO + + +--****************************************** PRINCIPAL **************************************** +USE Monitor +GO +IF DATABASE_PRINCIPAL_ID('monitor') IS NOT NULL + DROP USER monitor +GO +CREATE USER monitor FOR LOGIN monitor WITH DEFAULT_SCHEMA=[dbo] +GO +EXEC SP_ADDROLEMEMBER N'db_owner',N'monitor' +GO + +--****************************************** TABLE **************************************** + +--监控_实例名(默认实例的监控名比较特殊,为SQLSERVER,非默认为MSSQL$INSTANCENAME) +IF OBJECT_ID('DBO.MONITOR_SERVICE','U') IS NULL +CREATE TABLE DBO.MONITOR_SERVICE +( + NAME VARCHAR(100) NULL, + MONITOR_SERVICE_NAME VARCHAR(100) NULL, + PORT INT NULL +) +GO + +--监控_监控项的明细路径 +IF OBJECT_ID('DBO.MONITOR_COUNTERPATH','U') IS NULL +CREATE TABLE DBO.MONITOR_COUNTERPATH +( + TYPE INT NULL, --0.OS/1.DB + COUNTERPATH VARCHAR(1000) NULL +) +GO + +--不需要备份的数据库 +IF OBJECT_ID('DBO.BACKUP_FILTER','U') IS NULL +CREATE TABLE DBO.BACKUP_FILTER +( + NAME VARCHAR(100) NOT NULL +) +GO + +IF OBJECT_ID('DBO.MONITOR_SERVER_SETTING','U') IS NULL +CREATE TABLE DBO.MONITOR_SERVER_SETTING +( + INDEXNO INT NOT NULL, + IP VARCHAR(100) NOT NULL, + PORT VARCHAR(100) NOT NULL, + DBNAME VARCHAR(100) NOT NULL, + ACCOUNT VARCHAR(100) NOT NULL, + PWD VARCHAR(100) NOT NULL, + [STATE] INT NOT NULL +) +GO +IF OBJECT_ID('DBO.MONITOR_SERVER_UNAVAILABLE_HISTORY','U') IS NULL +CREATE TABLE DBO.MONITOR_SERVER_UNAVAILABLE_HISTORY +( + IP VARCHAR(100) NOT NULL, + PORT VARCHAR(100) NOT NULL, + DBNAME VARCHAR(100) NOT NULL, + ACCOUNT VARCHAR(100) NOT NULL, + PWD VARCHAR(100) NOT NULL, + WRITETIME DATETIME NOT NULL +) +GO + +IF OBJECT_ID('DBO.BACKUP_SETTING','U') IS NULL +CREATE TABLE DBO.BACKUP_SETTING +( + APP VARCHAR(100) NOT NULL, + FULL_BACKUP_PATH VARCHAR(100) NOT NULL, + LOG_BACKUP_PATH VARCHAR(100) NOT NULL, + KEEP_FULL_BACKUP_DAYS INT NOT NULL, + KEEP_LOG_BACKUP_DAYS INT NOT NULL, + FULL_BACKUP_MIN_SIZE_MB INT NOT NULL, + LOG_BACKUP_MIN_SIZE_MB INT NOT NULL, + UPLOAD INT NOT NULL, + MD5 INT NOT NULL, + CONSTRAINT CK_FULLBACKUPMINSIZEMB CHECK(FULL_BACKUP_MIN_SIZE_MB > 10240), + CONSTRAINT CK_LOGBACKUPMINSIZEMB CHECK(LOG_BACKUP_MIN_SIZE_MB > 10240) +) +GO + + +IF OBJECT_ID('DBO.BACKUP_TRACE','U') IS NULL +CREATE TABLE DBO.BACKUP_TRACE +( + DBNAME VARCHAR(100) NOT NULL, + PATH VARCHAR(1000) NOT NULL, + FILENAME VARCHAR(1000) NOT NULL, + TYPE INT NOT NULL, + STARTTIME DATETIME NOT NULL, + ENDTIME DATETIME NOT NULL, + DURATION AS DATEDIFF(SECOND,STARTTIME,ENDTIME), + FILESIZE [BIGINT] NULL, + MD5CODE VARCHAR(100) NOT NULL, + SUCCESS INT NOT NULL, + UPLOADED INT NOT NULL, + WRITETIME DATETIME NOT NULL, + CONSTRAINT PK_BACKUP_TRACE_FILENAME PRIMARY KEY NONCLUSTERED(FILENAME) +) +GO +IF NOT EXISTS(SELECT 1 FROM SYS.INDEXES WHERE NAME = 'IDX_CL_BACKUP_TRACE_STARTTIME') + CREATE CLUSTERED INDEX IDX_CL_BACKUP_TRACE_STARTTIME ON DBO.BACKUP_TRACE(STARTTIME) +GO + + +--公用表,用于记录文件大小和MD5值 +IF OBJECT_ID('DBO.BACKUP_COMMON_TABLE','U') IS NULL +CREATE TABLE DBO.BACKUP_COMMON_TABLE +( + BLOCK VARCHAR(8000) +) +GO + +--跟踪设置 +IF OBJECT_ID('DBO.TRACE_SETTING','U') IS NULL +CREATE TABLE DBO.TRACE_SETTING +( + NAME VARCHAR(100) NOT NULL, + VALUE INT NOT NULL +) +GO + +--存放当前运行的跟踪信息 +IF OBJECT_ID('DBO.TRACE_CURRENT_TRACEINFO','U') IS NULL +CREATE TABLE DBO.TRACE_CURRENT_TRACEINFO +( + STARTTIME DATETIME NOT NULL, + TRACEID INT NOT NULL, + TRACEFILE VARCHAR(100) NOT NULL +) +GO + +--存放跟踪出的SQL +IF OBJECT_ID('DBO.TRACE_TSQL','U') IS NULL +CREATE TABLE DBO.TRACE_TSQL +( + SQLTXT VARCHAR(8000) NULL, + SQLCHECKSUM BIGINT NULL, + TEXTDATA VARCHAR(8000) NULL, + APPLICATIONNAME VARCHAR(5000) NULL, + NTUSERNAME VARCHAR(5000) NULL, + LOGINNAME VARCHAR(5000) NULL, + DURATION BIGINT NOT NULL, + STARTTIME DATETIME NULL, + ENDTIME DATETIME NULL, + READS BIGINT NULL, + WRITES BIGINT NULL, + CPU INT NULL, + SERVERNAME VARCHAR(500) NULL, + ERROR BIGINT NULL, + OBJECTID BIGINT NULL, + OBJECTNAME VARCHAR(5000) NULL, + DATABASENAME VARCHAR(1000) NULL, + ROWCOUNTS BIGINT NULL +) +IF NOT EXISTS(SELECT 1 FROM SYS.INDEXES WHERE NAME = 'IDX_CL_TRACETSQL_STARTTIME') + CREATE CLUSTERED INDEX IDX_CL_TRACETSQL_STARTTIME ON DBO.TRACE_TSQL(STARTTIME) + +IF NOT EXISTS(SELECT 1 FROM SYS.INDEXES WHERE NAME = 'IDX_NC_TRACETSQL_SQLCHECKSUM') + CREATE NONCLUSTERED INDEX IDX_NC_TRACETSQL_SQLCHECKSUM ON DBO.TRACE_TSQL(SQLCHECKSUM) +GO + +IF OBJECT_ID('DBO.COUNTERDATA','U') IS NULL +CREATE TABLE DBO.COUNTERDATA +( + [GUID] [uniqueidentifier] NOT NULL, + [CounterID] [int] NOT NULL, + [RecordIndex] [int] NOT NULL, + [CounterDateTime] [char](24) NOT NULL, + [CounterValue] [float] NOT NULL, + [FirstValueA] [int] NULL, + [FirstValueB] [int] NULL, + [SecondValueA] [int] NULL, + [SecondValueB] [int] NULL, + [MultiCount] [int] NULL, + CONSTRAINT PK_COUNTERDATA_GUID_COUNTERID_RECORDINDEX PRIMARY KEY CLUSTERED ([GUID] ASC,[CounterID] ASC,[RecordIndex] ASC) +) +GO +IF NOT EXISTS(SELECT 1 FROM SYS.INDEXES WHERE NAME = 'IDX_NC_COUNTERDATA_COUNTERID_I_COUNTERDATETIME_COUNTERVALUE') + CREATE NONCLUSTERED INDEX IDX_NC_COUNTERDATA_COUNTERID_I_COUNTERDATETIME_COUNTERVALUE ON DBO.COUNTERDATA(COUNTERID) INCLUDE(COUNTERDATETIME,COUNTERVALUE) +GO + +--性能数据设置 +IF OBJECT_ID('DBO.COUNTER_SETTING','U') IS NULL +CREATE TABLE DBO.COUNTER_SETTING +( + NAME VARCHAR(100) NOT NULL, + VALUE INT NOT NULL +) +GO + +IF OBJECT_ID('DBO.COUNTERDETAILS','U') IS NULL +CREATE TABLE DBO.COUNTERDETAILS +( + [CounterID] [int] IDENTITY(1,1) NOT NULL, + [MachineName] [varchar](1024) NOT NULL, + [ObjectName] [varchar](1024) NOT NULL, + [CounterName] [varchar](1024) NOT NULL, + [CounterType] [int] NOT NULL, + [DefaultScale] [int] NOT NULL, + [InstanceName] [varchar](1024) NULL, + [InstanceIndex] [int] NULL, + [ParentName] [varchar](1024) NULL, + [ParentObjectID] [int] NULL, + [TimeBaseA] [int] NULL, + [TimeBaseB] [int] NULL, + CONSTRAINT PK_COUNTERDETAILS PRIMARY KEY CLUSTERED (CounterID) +) +GO + +IF OBJECT_ID('DBO.DISPLAYTOID','U') IS NULL +CREATE TABLE DBO.DISPLAYTOID +( + [GUID] [uniqueidentifier] NOT NULL, + [RunID] [int] NULL, + [DisplayString] [varchar](1024) NOT NULL, + [LogStartTime] [char](24) NULL, + [LogStopTime] [char](24) NULL, + [NumberOfRecords] [int] NULL, + [MinutesToUTC] [int] NULL, + [TimeZoneName] [char](32) NULL, + CONSTRAINT PK_DISPLAYTOID PRIMARY KEY CLUSTERED ([GUID] ASC) +) +IF NOT EXISTS(SELECT 1 FROM SYS.INDEXES WHERE NAME = 'IDX_UQ_DISPLAYTOID_DISPLAYSTRING') + CREATE UNIQUE INDEX IDX_UQ_DISPLAYTOID_DISPLAYSTRING ON DISPLAYTOID(DISPLAYSTRING) +GO + +IF OBJECT_ID('DBO.MONITOR_FILTER_SETTING','U') IS NULL +CREATE TABLE DBO.MONITOR_FILTER_SETTING +( + NAME VARCHAR(100) NOT NULL, + VALUE INT NOT NULL +) +GO + +USE [Monitor] +GO + + +IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[APP_SETTING]') AND type in (N'U')) +DROP TABLE [dbo].[APP_SETTING] +GO + + +IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[MIRRORING_FILTER]') AND type in (N'U')) +DROP TABLE [dbo].[MIRRORING_FILTER] +GO + +USE [Monitor] +GO + + +SET ANSI_NULLS ON +GO + +SET QUOTED_IDENTIFIER ON +GO + +SET ANSI_PADDING ON +GO + +CREATE TABLE [dbo].[APP_SETTING]( + [APP] [varchar](100) NOT NULL, + CONSTRAINT [PK_APP_SETTING] PRIMARY KEY CLUSTERED +( + [APP] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +) ON [PRIMARY] + +GO + +SET ANSI_PADDING OFF +GO + +USE [Monitor] +GO + +/****** Object: Table [dbo].[MIRRORING_FILTER] Script Date: 11/10/2021 14:25:56 ******/ +SET ANSI_NULLS ON +GO + +SET QUOTED_IDENTIFIER ON +GO + +SET ANSI_PADDING ON +GO + +CREATE TABLE [dbo].[MIRRORING_FILTER]( + [NAME] [varchar](100) NOT NULL, + CONSTRAINT [PK_MIRRORING_FILTER] PRIMARY KEY CLUSTERED +( + [NAME] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +) ON [PRIMARY] + +GO + +SET ANSI_PADDING OFF +GO + + +--****************************************** VIEW **************************************** +IF OBJECT_ID('DBO.PERFORMANCESLOG','V') IS NOT NULL + DROP VIEW DBO.PERFORMANCESLOG +GO +CREATE VIEW DBO.PERFORMANCESLOG +AS +SELECT A.OBJECTNAME AS CATEGORYNAME,A.COUNTERNAME,A.INSTANCENAME,B.COUNTERVALUE AS NEXTVALUE,CAST(LEFT(B.COUNTERDATETIME,23) AS DATETIME) AS WRITETIME +FROM Monitor.DBO.COUNTERDETAILS A,Monitor.DBO.COUNTERDATA B +WHERE A.COUNTERID = B.COUNTERID +GO +IF OBJECT_ID('DBO.BACKUP_DBLIST','V') IS NOT NULL + DROP VIEW DBO.BACKUP_DBLIST +GO +CREATE VIEW DBO.BACKUP_DBLIST +AS + SELECT A.DATABASE_ID,A.NAME + FROM SYS.DATABASES A + WHERE A.DATABASE_ID > 4 + AND A.IS_READ_ONLY = 0 + AND A.IS_DISTRIBUTOR = 0 + AND A.STATE = 0 + AND A.NAME NOT LIKE '%AUTOREST' + AND NOT EXISTS(SELECT 1 FROM DBO.BACKUP_FILTER B + WHERE A.NAME = B.NAME) +GO + +IF OBJECT_ID('DBO.CUSTOMER_DBLIST','V') IS NOT NULL + DROP VIEW DBO.CUSTOMER_DBLIST +GO +CREATE VIEW DBO.CUSTOMER_DBLIST +AS + SELECT A.DATABASE_ID,A.NAME + FROM SYS.DATABASES A + WHERE A.DATABASE_ID > 4 + AND A.IS_READ_ONLY = 0 + AND A.IS_DISTRIBUTOR = 0 + AND A.STATE = 0 + AND A.NAME <> 'MONITOR' +GO + +--****************************************** FUN **************************************** +IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[funConvertVarCharToVarBinary]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT')) +DROP FUNCTION [dbo].[funConvertVarCharToVarBinary] +GO + +IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[funConvertVarBinaryToVarChar]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT')) +DROP FUNCTION [dbo].[funConvertVarBinaryToVarChar] +GO + +SET ANSI_NULLS ON +GO + +SET QUOTED_IDENTIFIER ON +GO + + +CREATE FUNCTION [dbo].[funConvertVarBinaryToVarChar] +(@vbnInput varbinary(512)) +RETURNS varchar(1024) +AS +BEGIN + declare @chvOutput varchar(1024) + set @chvOutput = '' + declare @intLen int + set @intLen = datalength(@vbnInput) + declare @intPos int + set @intPos = 1 + declare @bytByte binary + declare @intTmp tinyint + declare @chvTmp varchar(2) + while @intPos <= @intLen + begin + set @bytByte = substring(@vbnInput, @intPos, 1) + -- 第一个字符 + set @intTmp = @bytByte / 16 + if @intTmp >= 10 + set @chvTmp = + case @intTmp + when 10 then 'A' + when 11 then 'B' + when 12 then 'C' + when 13 then 'D' + when 14 then 'E' + when 15 then 'F' + end + else + set @chvTmp = cast(@intTmp as char(1)) + -- 第二个字符 + set @intTmp = @bytByte - @intTmp * 16 + if @intTmp >= 10 + set @chvTmp = @chvTmp + + case @intTmp + when 10 then 'A' + when 11 then 'B' + when 12 then 'C' + when 13 then 'D' + when 14 then 'E' + when 15 then 'F' + end + else + set @chvTmp = @chvTmp + cast(@intTmp as char(1)) + set @chvOutput = @chvOutput + @chvTmp + set @intPos = @intPos + 1 + end + return @chvOutput +END +GO + +/****** Object: UserDefinedFunction [dbo].[funConvertVarCharToVarBinary] Script Date: 2021/11/8 15:06:20 ******/ +SET ANSI_NULLS ON +GO + +SET QUOTED_IDENTIFIER ON +GO + + +CREATE FUNCTION [dbo].[funConvertVarCharToVarBinary] +(@chvInput varchar(1024)) +RETURNS varbinary(512)--- varchar(20) +AS +BEGIN + declare @binOutput varbinary(512) + if substring(@chvInput,1,2)='0x' + set @chvInput = substring(@chvInput,3,datalength(@chvInput)-2) --去掉0x + ---set @binOutput = '' + declare @intLen int + set @intLen = datalength(@chvInput) + declare @intPos int + set @intPos = 1 + declare @tinyint1 tinyint + declare @tinyint2 tinyint + declare @tinyintBin binary(1) + declare @intTmp tinyint + declare @chvTmp varchar(2) + declare @charTmp1 varchar(1) + declare @charTmp2 varchar(1) + while @intPos <= @intLen + begin + set @chvTmp = substring(@chvInput, @intPos, 2) + + set @charTmp1=substring(@chvTmp,1,1) + set @tinyint1= + case @charTmp1 + when '' then 0 + when 'A' then 10*16 + when 'B' then 11*16 + when 'C' then 12*16 + when 'D' then 13*16 + when 'E' then 14*16 + when 'F' then 15*16 + else cast(@charTmp1 as tinyint)*16 + end + + set @charTmp2=substring(@chvTmp,2,1) + set @tinyint2= + case @charTmp2 + when 'A' then 10 + when 'B' then 11 + when 'C' then 12 + when 'D' then 13 + when 'E' then 14 + when 'F' then 15 + else cast(@charTmp2 as tinyint) + end + set @tinyintBin=cast(@tinyint1+@tinyint2 as binary(1)) + if @intPos=1 set @binOutput=@tinyintBin + else set @binOutput=@binOutput+@tinyintBin + set @intPos = @intPos + 2 + end + return @binOutput +END +GO + +--****************************************** SP **************************************** +IF OBJECT_ID('DBO.TOOL_GET_IPPORT','P') IS NOT NULL + DROP PROC DBO.TOOL_GET_IPPORT +GO +CREATE PROC DBO.TOOL_GET_IPPORT +@IP VARCHAR(50) OUTPUT, +@PORT VARCHAR(10) OUTPUT +AS +BEGIN + DECLARE @LISTENONALLIPS INT + DECLARE @REGEDITKEY VARCHAR(8000),@VERSIONKEY VARCHAR(100),@IPKEY VARCHAR(100) = 'IP1' + IF @@VERSION LIKE 'Microsoft SQL Server 2021%' + SET @VERSIONKEY = 'MSSQL16.' + ELSE IF @@VERSION LIKE 'Microsoft SQL Server 2019%' + SET @VERSIONKEY = 'MSSQL15.' + ELSE IF @@VERSION LIKE 'Microsoft SQL Server 2017%' + SET @VERSIONKEY = 'MSSQL14.' + ELSE IF @@VERSION LIKE 'Microsoft SQL Server 2016%' + SET @VERSIONKEY = 'MSSQL13.' + ELSE IF @@VERSION LIKE 'Microsoft SQL Server 2014%' + SET @VERSIONKEY = 'MSSQL12.' + ELSE IF @@VERSION LIKE 'Microsoft SQL Server 2012%' + SET @VERSIONKEY = 'MSSQL11.' + ELSE IF @@VERSION LIKE 'Microsoft SQL Server 2008%' + SET @VERSIONKEY = 'MSSQL10_50.' + ELSE + RAISERROR('contact dba to find out the version of sqlserver and modify the sp:Monitor.dbo.TOOL_GET_IPPORT',11,1) + + SET @REGEDITKEY = 'SOFTWARE\Microsoft\Microsoft SQL Server\'+@VERSIONKEY+@@SERVICENAME+'\MSSQLServer\SuperSocketNetLib\Tcp' + EXEC MASTER.DBO.XP_REGREAD @ROOTKEY = 'HKEY_LOCAL_MACHINE',@KEY = @REGEDITKEY,@VALUE_NAME = 'ListenOnAllIPs',@VALUE = @LISTENONALLIPS OUTPUT + IF @LISTENONALLIPS = 0 + BEGIN + SET @REGEDITKEY = 'SOFTWARE\Microsoft\Microsoft SQL Server\'+@VERSIONKEY+@@SERVICENAME+'\MSSQLServer\SuperSocketNetLib\Tcp\'+@IPKEY + EXEC MASTER.DBO.XP_REGREAD @ROOTKEY = 'HKEY_LOCAL_MACHINE',@KEY = @REGEDITKEY,@VALUE_NAME = 'TcpPort',@VALUE = @PORT OUTPUT + EXEC MASTER.DBO.XP_REGREAD @ROOTKEY = 'HKEY_LOCAL_MACHINE',@KEY = @REGEDITKEY,@VALUE_NAME = 'IpAddress',@VALUE = @IP OUTPUT + END + ELSE + BEGIN + --RAISERROR('IP1 IP,PORT NOT BANDING',10,1) + SET @IPKEY = 'IPAll' + SET @REGEDITKEY = 'SOFTWARE\Microsoft\Microsoft SQL Server\'+@VERSIONKEY+@@SERVICENAME+'\MSSQLServer\SuperSocketNetLib\Tcp\'+@IPKEY + EXEC MASTER.DBO.XP_REGREAD @ROOTKEY = 'HKEY_LOCAL_MACHINE',@KEY = @REGEDITKEY,@VALUE_NAME = 'TcpPort',@VALUE = @PORT OUTPUT + + declare @tb_output TABLE + ( + ip varchar(2000) + ) + INSERT INTO @tb_output + exec xp_cmdshell 'ipconfig /all' + + select top 1 @ip=SUBSTRING(ip,CHARINDEX(':',ip)+2,1000) + FROM @tb_output + WHERE ip LIKE '%IP Address%' and (ip like '%: 11.%' or ip like '%: 30.%' or ip like '%: 9.%' or ip like '%: 172.%' or ip like '%: 10.%' or ip like '%: 100.%') and ip not like '%: 169.%' + select @ip=left(@ip,DATALENGTH(@ip)-1) + if (@ip is null) --win server 2008 + begin + select top 1 @ip=SUBSTRING(ip,CHARINDEX(':',ip)+2,1000) + FROM @tb_output + WHERE ip LIKE '%IPv4 Address%' and (ip like '%: 11.%' or ip like '%: 30.%' or ip like '%: 9.%' or ip like '%: 172.%' or ip like '%: 10.%' or ip like '%: 100.%') and ip not like '%: 169.%' + select @ip=left(@ip,DATALENGTH(@ip)-1) + select @ip=SUBSTRING(@ip,0,CHARINDEX('(',@ip)) + end + END +END +GO + +-- ============================================= +-- Description: 生成sqlserver服务器负载数据上报的xml +-- ============================================= +IF OBJECT_ID('DBO.JOB_REPORT_LOAD','P') IS NOT NULL + DROP PROC DBO.JOB_REPORT_LOAD +GO +CREATE PROCEDURE DBO.[JOB_REPORT_LOAD] +AS +BEGIN + SET NOCOUNT ON; + + + DECLARE @IP SYSNAME,@PORT SYSNAME,@CPU INT,@DISKUSEDPERCENT INT,@STATDATE VARCHAR(20),@IO DECIMAL(10,2),@TIMEMIN INT, + @DATE CHAR(8),@DISKQUEUELENGTH DECIMAL(10,2),@USERCONNECTIONS BIGINT,@BATCHREQUESTS BIGINT, + @SQLCOMPILATIONSSEC DECIMAL(10,2),@AVGDISKBYTESREAD DECIMAL(10,2),@AVGDISKBYTESWRITE DECIMAL(10,2), + @FULLSACNSEC DECIMAL(10,2),@BUFFERCACHEHITRATIO INT,@SQLRECOMPILATIONSEC DECIMAL(10,2), + @REQUESTSCOMPLETEDSEC INT,@CACHEHITRATIO DECIMAL(10,2),@SLOWQUERIES BIGINT,@CMD VARCHAR(4000) + DECLARE @MONITOR_SERVICE_NAME VARCHAR(100) + SET @MONITOR_SERVICE_NAME = CASE WHEN @@SERVICENAME = 'MSSQLSERVER' THEN 'SQLServer' ELSE @@SERVICENAME END + --IP + EXEC Monitor.DBO.TOOL_GET_IPPORT @IP OUT,@PORT OUT + + --DATE + SELECT @STATDATE = convert(varchar,GETDATE(),120) + SELECT @DATE = CONVERT(CHAR(8),GETDATE(),112),@TIMEMIN = DATEDIFF(MI,CONVERT(CHAR(8),GETDATE(),112),GETDATE()) + + IF NOT EXISTS(select 1 from Monitor.DBO.PERFORMANCESLOG WHERE WRITETIME >= DATEADD(SS,-59,GETDATE())) + AND EXISTS(select 1 from sys.dm_os_sys_info where sqlserver_start_time>'2021-11-10 09:00:00') AND @@SERVICENAME IN('MSSQLSERVER','S1') + BEGIN + SET @CMD='call D:\sql_install\dba_tools\Monitor\rebuildLogman.bat' + EXEC XP_CMDSHELL @CMD + SET @CMD='call D:\sql_install\dba_tools\Monitor\rebuildLogman.bat' + EXEC XP_CMDSHELL @CMD + END + + IF @MONITOR_SERVICE_NAME in('S1','SQLServer') + BEGIN + --CPU id_1001 + SELECT @CPU = ISNULL((CASE WHEN MAX(NEXTVALUE)> 100 THEN 100 ELSE CEILING(MAX(NEXTVALUE)) END),0) + FROM Monitor.DBO.PERFORMANCESLOG + WHERE WRITETIME >= DATEADD(SS,-59,GETDATE()) + AND CATEGORYNAME = 'Processor' + AND COUNTERNAME = '% Processor Time' + AND INSTANCENAME = '_Total' + + --磁盘IO负载 id_12947 + SELECT @IO = ISNULL((CASE WHEN MIN(NEXTVALUE)> 100 THEN 0 ELSE 100-CEILING(MIN(NEXTVALUE)) END),0) + FROM Monitor.DBO.PERFORMANCESLOG + WHERE WRITETIME >= DATEADD(SS,-59,GETDATE()) + AND CATEGORYNAME = 'LogicalDisk' + AND COUNTERNAME = '% Idle Time' + AND INSTANCENAME = 'D:' + + --磁盘等待队列 id_12952 + SELECT @DISKQUEUELENGTH = ISNULL(MAX(NEXTVALUE),0) + FROM Monitor.DBO.PERFORMANCESLOG + WHERE WRITETIME >= DATEADD(SS,-59,GETDATE()) + AND CATEGORYNAME = 'LogicalDisk' + AND COUNTERNAME = 'Avg. Disk Queue Length' + AND INSTANCENAME = 'D:' + + --用户连接数 id_12951 + SELECT @USERCONNECTIONS = ISNULL(MAX(NEXTVALUE),0) + FROM Monitor.DBO.PERFORMANCESLOG + WHERE WRITETIME >= DATEADD(SS,-59,GETDATE()) + AND CATEGORYNAME LIKE '%'+@MONITOR_SERVICE_NAME+':General Statistics' + AND COUNTERNAME = 'User Connections' + + --请求数 id_12948 + SELECT @BATCHREQUESTS = ISNULL(MAX(NEXTVALUE),0) + FROM Monitor.DBO.PERFORMANCESLOG + WHERE WRITETIME >= DATEADD(SS,-59,GETDATE()) + AND CATEGORYNAME LIKE '%'+@MONITOR_SERVICE_NAME+':SQL Statistics' + AND COUNTERNAME = 'Batch Requests/sec' + + --SQL_Compilations/sec id_12968 + SELECT @SQLCOMPILATIONSSEC = ISNULL(MAX(NEXTVALUE),0) + FROM Monitor.DBO.PERFORMANCESLOG + WHERE WRITETIME >= DATEADD(SS,-59,GETDATE()) + AND CATEGORYNAME LIKE '%'+@MONITOR_SERVICE_NAME+':SQL Statistics' + AND COUNTERNAME = 'SQL Compilations/sec' + + + -- Avg_Disk_Bytes/Read 0 id_12955 + SELECT @AVGDISKBYTESREAD = ISNULL(MAX(NEXTVALUE),0) + FROM Monitor.DBO.PERFORMANCESLOG + WHERE WRITETIME >= DATEADD(SS,-59,GETDATE()) + AND CATEGORYNAME = 'LogicalDisk' + AND COUNTERNAME = 'Avg. Disk Bytes/Read' + AND INSTANCENAME = 'D:' + + -- Avg_Disk_Bytes/Write(平均读写) 0 id_12956 + SELECT @AVGDISKBYTESWRITE = ISNULL(MAX(NEXTVALUE),0) + FROM Monitor.DBO.PERFORMANCESLOG + WHERE WRITETIME >= DATEADD(SS,-59,GETDATE()) + AND CATEGORYNAME = 'LogicalDisk' + AND COUNTERNAME = 'Avg. Disk Bytes/Write' + AND INSTANCENAME = 'D:' + + --Full_Scans/sec(全表扫描) 0 id_12958 + SELECT @FULLSACNSEC = ISNULL(MAX(NEXTVALUE),0) + FROM Monitor.DBO.PERFORMANCESLOG + WHERE WRITETIME >= DATEADD(SS,-59,GETDATE()) + AND CATEGORYNAME LIKE '%'+@MONITOR_SERVICE_NAME+':Access Methods' + AND COUNTERNAME = 'Full Scans/sec' + + --Buffer_cache_hit_ratio(高速缓存查 0 id_12949 + SELECT @BUFFERCACHEHITRATIO = ISNULL(MAX(NEXTVALUE),0) + FROM Monitor.DBO.PERFORMANCESLOG + WHERE WRITETIME >= DATEADD(SS,-59,GETDATE()) + AND CATEGORYNAME LIKE '%'+@MONITOR_SERVICE_NAME+':Buffer Manager' + AND COUNTERNAME = 'Buffer cache hit ratio' + + --SQL_Re-Compilations/sec 0 id_12950 + SELECT @SQLRECOMPILATIONSEC = ISNULL(MAX(NEXTVALUE),0) + FROM Monitor.DBO.PERFORMANCESLOG + WHERE WRITETIME >= DATEADD(SS,-59,GETDATE()) + AND CATEGORYNAME LIKE '%'+@MONITOR_SERVICE_NAME+':SQL Statistics' + AND COUNTERNAME = 'SQL Re-Compilations/sec' + + --Requests_completed/sec 0 id_12967 + SELECT @REQUESTSCOMPLETEDSEC = ISNULL(MAX(NEXTVALUE),0) + FROM Monitor.DBO.PERFORMANCESLOG + WHERE WRITETIME >= DATEADD(SS,-59,GETDATE()) + AND CATEGORYNAME LIKE '%'+@MONITOR_SERVICE_NAME+':Workload Group Stats' + AND COUNTERNAME = 'Requests completed/sec' + + --Cache_Hit_Ratio 0 id_12965 + SELECT @CACHEHITRATIO = ISNULL(MAX(NEXTVALUE),0) + FROM Monitor.DBO.PERFORMANCESLOG + WHERE WRITETIME >= DATEADD(SS,-59,GETDATE()) + AND CATEGORYNAME LIKE '%'+@MONITOR_SERVICE_NAME+':Plan Cache' + AND COUNTERNAME = 'Cache Hit Ratio' + + --DISK USED PERCENT 0 id_874095 + IF OBJECT_ID('TEMPDB.DBO.#DISKTOTALSIZE','U') IS NOT NULL + DROP TABLE #DISKTOTALSIZE + IF OBJECT_ID('TEMPDB.DBO.#DISKFREESIZE','U') IS NOT NULL + DROP TABLE #DISKFREESIZE + CREATE TABLE #DISKTOTALSIZE(INDEXNO INT IDENTITY,SIZEKB NVARCHAR(100)) + INSERT INTO #DISKTOTALSIZE EXEC MASTER.DBO.XP_CMDSHELL 'WMIC LOGICALDISK WHERE NAME=''D:'' GET SIZE' + CREATE TABLE #DISKFREESIZE(NAME VARCHAR(10),FREESIZEMB INT) + INSERT INTO #DISKFREESIZE EXEC MASTER.DBO.XP_FIXEDDRIVES; + + --部分旧服务器无法使用WMIC(老A5统一计算为680GB) + IF NOT EXISTS(SELECT 1 FROM #DISKTOTALSIZE WHERE INDEXNO = 2 AND ISNUMERIC(LEFT(SIZEKB,LEN(SIZEKB)-1)) = 1) + SET @DISKUSEDPERCENT =CEILING(100*(680-(SELECT FREESIZEMB/1024.0 FROM #DISKFREESIZE WHERE NAME = 'D'))/680) + ELSE + SELECT @DISKUSEDPERCENT = CEILING(100*(SELECT CAST(LEFT(SIZEKB,LEN(SIZEKB)-1) AS BIGINT)/1024.0/1024/1024-(SELECT FREESIZEMB/1024.0 FROM #DISKFREESIZE WHERE NAME = 'D') FROM #DISKTOTALSIZE WHERE INDEXNO = 2)/(SELECT CAST(LEFT(SIZEKB,LEN(SIZEKB)-1) AS BIGINT)/1024.0/1024/1024 FROM #DISKTOTALSIZE WHERE INDEXNO = 2)) + + + --mssql_slow_queries 0 id_12970 + IF OBJECT_ID('DBO.TRACE_TSQL','U') IS NULL + SET @SLOWQUERIES = 0 + ELSE + SELECT @SLOWQUERIES = COUNT(1) + FROM Monitor.DBO.TRACE_TSQL + WHERE STARTTIME >= DATEADD(SS,-59,GETDATE()) + AND DATABASENAME <> 'Monitor' + AND ISNULL(APPLICATIONNAME,'') NOT LIKE 'SQLAgent%' + AND ISNULL(APPLICATIONNAME,'') <> 'SQLCMD' + + SET @CMD = 'echo ^ >d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+isnull(@IP,'127.0.0.1')+'^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+isnull(@PORT,'48322')+'^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+LTRIM(isnull(@DATE,'20220816'))+'^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+LTRIM(isnull(@TIMEMIN,'863'))+'^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+LTRIM(isnull(@CPU,'0'))+'^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+LTRIM(isnull(@IO,'0'))+'^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+LTRIM(isnull(@DISKQUEUELENGTH,'0'))+'^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+LTRIM(isnull(@USERCONNECTIONS,'0'))+'^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+LTRIM(isnull(@BATCHREQUESTS,'0'))+'^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+LTRIM(isnull(@SQLCOMPILATIONSSEC,'0'))+'^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+LTRIM(isnull(@AVGDISKBYTESREAD,'0'))+'^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+LTRIM(isnull(@AVGDISKBYTESWRITE,'0'))+'^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+LTRIM(isnull(@FULLSACNSEC,'0'))+'^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+LTRIM(isnull(@BUFFERCACHEHITRATIO,'0'))+'^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+LTRIM(isnull(@SQLRECOMPILATIONSEC,'0'))+'^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+LTRIM(isnull(@REQUESTSCOMPLETEDSEC,'0'))+'^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+LTRIM(isnull(@CACHEHITRATIO,'0'))+'^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+LTRIM(isnull(@DISKUSEDPERCENT,'0'))+'^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+LTRIM(isnull(@SLOWQUERIES,'0'))+'^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+LTRIM(isnull(@STATDATE,''))+'^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + SET @CMD = 'echo ^ >>d:\dbbak\mssql_spes_new.xml' EXEC MASTER.DBO.XP_CMDSHELL @CMD + + --SEND + --SET @CMD='cd d:\dbbak && d: && d:\perl\bin\perl.exe send_xml.pl -c mssql_spes_new.xml -t 60' + SET @CMD='cd d:\dbbak && d: && C:\cygwinroot\bin\sh.exe send_xml.sh mssql_spes_new mssql_spes_new.xml' + EXEC MASTER.DBO.XP_CMDSHELL @CMD + END + + --DELETE OLD DATA + DECLARE @KEEPDATADAYS INT + SELECT @KEEPDATADAYS = VALUE FROM DBO.COUNTER_SETTING WHERE NAME = 'KEEP_DATA_DAYS' + DELETE DBO.COUNTERDATA WHERE LEFT(COUNTERDATETIME,23) < CONVERT(CHAR(23),GETDATE()-@KEEPDATADAYS,121) +END + +GO + + +-- ============================================= +-- AUTHOR: +-- CREATE DATE: <2010/07/01> +-- DESCRIPTION: <代理执行:每5分钟,加载数据到Monitor内> +-- EXEC Monitor.DBO.JOB_TRACE 1 +-- 查看当前活动的跟踪:SELECT * FROM DBO.TRACE_CURRENT_TRACEINFO +-- 查看当前跟踪的数据:SELECT * FROM FN_TRACE_GETTABLE(@TRACEFILE,DEFAULT) +-- ============================================= +IF OBJECT_ID('DBO.JOB_TRACE','P') IS NOT NULL + DROP PROC DBO.JOB_TRACE +GO +CREATE PROCEDURE DBO.JOB_TRACE +@DELETE_OLD_TRACE_FILE INT --是否删除旧跟踪文件 1:删除/0:保留 +AS +BEGIN + SET NOCOUNT ON + + --定义启动跟踪的失败的代码 + DECLARE @RESULT_CODE INT + --定义跟踪ID + DECLARE @TRACEID INT + --定义跟踪文件的最大容量 + DECLARE @MAXFILESIZE BIGINT + --定义跟踪文件存放的路径 + DECLARE @TRACEFILE NVARCHAR(1000) + --定义旧跟踪文件存放的路径 + DECLARE @OLDTRACEFILE NVARCHAR(1000) + --定义命令变量 + DECLARE @CMD VARCHAR(100) + --定义SQL执行时长筛选值(微秒) + DECLARE @FILTERDURATION BIGINT,@KEEPDATADAYS INT + + IF OBJECT_ID('DBO.TRACE_SETTING','U') IS NOT NULL + BEGIN + SELECT @FILTERDURATION = VALUE*1000000 FROM DBO.TRACE_SETTING WHERE NAME = 'FILTER_DURATION' + SELECT @KEEPDATADAYS = VALUE FROM DBO.TRACE_SETTING WHERE NAME = 'KEEP_DATA_DAYS' + END + SELECT @FILTERDURATION = ISNULL(@FILTERDURATION,1000000),@KEEPDATADAYS = ISNULL(@KEEPDATADAYS,60) + + + --停止当前跟踪 + IF EXISTS(SELECT 1 FROM DBO.TRACE_CURRENT_TRACEINFO) + BEGIN + IF EXISTS(SELECT 1 FROM SYS.TRACES A,DBO.TRACE_CURRENT_TRACEINFO B WHERE A.ID = B.TRACEID) + BEGIN + SELECT @TRACEID = TRACEID,@OLDTRACEFILE = TRACEFILE FROM DBO.TRACE_CURRENT_TRACEINFO + + EXEC SP_TRACE_SETSTATUS @TRACEID,0 + EXEC SP_TRACE_SETSTATUS @TRACEID,2 + END + TRUNCATE TABLE DBO.TRACE_CURRENT_TRACEINFO + END + --建立文件夹 + EXEC XP_CMDSHELL 'MD C:\TRACE',NO_OUTPUT + + --开始新的跟踪 + BEGIN + --对变量赋值,单位:MB + SET @MAXFILESIZE = 20000 + SET @TRACEFILE = N'C:\TRACE\TRACE_'+@@SERVICENAME+'_'+REPLACE(REPLACE(REPLACE(CONVERT(NVARCHAR(20),GETDATE(),120),'-',''),' ',''),':','') + + --初始化跟踪 + EXEC @RESULT_CODE = SP_TRACE_CREATE @TRACEID OUTPUT,2,@TRACEFILE,@MAXFILESIZE,NULL + --出错则回显错误代码 + IF (@RESULT_CODE != 0) GOTO ERROR + + --定义跟踪的事件 + DECLARE @ON BIT + SET @ON = 1 + + exec sp_trace_setevent @TraceID,17,1,@on + exec sp_trace_setevent @TraceID,17,9,@on + exec sp_trace_setevent @TraceID,17,6,@on + exec sp_trace_setevent @TraceID,17,10,@on + exec sp_trace_setevent @TraceID,17,14,@on + exec sp_trace_setevent @TraceID,17,11,@on + exec sp_trace_setevent @TraceID,17,35,@on + exec sp_trace_setevent @TraceID,17,12,@on + exec sp_trace_setevent @TraceID,10,15,@on + exec sp_trace_setevent @TraceID,10,16,@on + exec sp_trace_setevent @TraceID,10,1,@on + exec sp_trace_setevent @TraceID,10,9,@on + exec sp_trace_setevent @TraceID,10,17,@on + exec sp_trace_setevent @TraceID,10,2,@on + exec sp_trace_setevent @TraceID,10,10,@on + exec sp_trace_setevent @TraceID,10,18,@on + exec sp_trace_setevent @TraceID,10,11,@on + exec sp_trace_setevent @TraceID,10,35,@on + exec sp_trace_setevent @TraceID,10,12,@on + exec sp_trace_setevent @TraceID,10,13,@on + exec sp_trace_setevent @TraceID,10,6,@on + exec sp_trace_setevent @TraceID,10,14,@on + exec sp_trace_setevent @TraceID,12,15,@on + exec sp_trace_setevent @TraceID,12,16,@on + exec sp_trace_setevent @TraceID,12,1,@on + exec sp_trace_setevent @TraceID,12,9,@on + exec sp_trace_setevent @TraceID,12,17,@on + exec sp_trace_setevent @TraceID,12,6,@on + exec sp_trace_setevent @TraceID,12,10,@on + exec sp_trace_setevent @TraceID,12,14,@on + exec sp_trace_setevent @TraceID,12,18,@on + exec sp_trace_setevent @TraceID,12,11,@on + exec sp_trace_setevent @TraceID,12,35,@on + exec sp_trace_setevent @TraceID,12,12,@on + exec sp_trace_setevent @TraceID,12,13,@on + exec sp_trace_setevent @TraceID,13,1,@on + exec sp_trace_setevent @TraceID,13,9,@on + exec sp_trace_setevent @TraceID,13,6,@on + exec sp_trace_setevent @TraceID,13,10,@on + exec sp_trace_setevent @TraceID,13,14,@on + exec sp_trace_setevent @TraceID,13,11,@on + exec sp_trace_setevent @TraceID,13,35,@on + exec sp_trace_setevent @TraceID,13,12,@on + + --跟踪的列: + -- TEXTDATA 与跟踪内捕获的事件类相关的文本值 + -- APPLICATIONNAME 创建与 SQL Server 实例的连接的客户端应用程序的名称 + -- NTUSERNAME Microsoft Windows 用户名。 + -- LOGINNAME 客户端的 SQL Server 登录名 + -- DURATION 事件所花费的实耗时间(毫秒) + -- STARTTIME 事件开始的时间(如果可用) + -- ENDTIME 事件结束的时间 + -- READS 服务器代表事件所执行的逻辑磁盘读取次数 + -- WRITES 服务器代表事件所执行的物理磁盘写入次数 + -- CPU 事件所使用的 CPU 时间(微秒) + -- SERVERNAME 被跟踪的 SQL Server 实例的名称 + -- ERROR 错误号 + -- OBJECTNAME 被访问的对象的名称 + -- DATABASENAME 语句中指定的数据库名称 + -- ROWCOUNTS 批处理中的行数 + + --设置筛选器 + --TEXTDATA 不能为空 + exec sp_trace_setfilter @TraceID,1,0,1,NULL + --排除SQL Server Profiler自身 + exec sp_trace_setfilter @TraceID,10,0,7,N'SQL Server Profiler%' + --排除ApplicationName:Microsoft SQL Server Management Studio - 查询 + exec sp_trace_setfilter @TraceID,10,0,7,N'%Microsoft SQL Server Management Studio%' + --排除ApplicationName:SQLAgent 作业 + exec sp_trace_setfilter @TraceID,10,0,7,N'SQLAgent%' + exec sp_trace_setfilter @TraceID,10,0,7,N'SQLCMD' + + --LoginName不能为空 + exec sp_trace_setfilter @TraceID,11,0,1,NULL + --排除复制/GCS变更类跟踪 + exec sp_trace_setfilter @TraceID,11,0,7,N'sa' + exec sp_trace_setfilter @TraceID,11,0,7,N'distributor_admin' + exec sp_trace_setfilter @TraceID,11,0,7,N'%\sqlserver' + + --Duration大于等于设定的值 + exec sp_trace_setfilter @TraceID,13,0,4,@FILTERDURATION + --Duration不能为空 + exec sp_trace_setfilter @TraceID,13,0,1,NULL + --CPU不能为空 + exec sp_trace_setfilter @TraceID,18,0,1,NULL + --DatabaseName不能为空 + exec sp_trace_setfilter @TraceID,35,0,1,NULL + --DatabaseName不能为系统库或者监控库 + exec sp_trace_setfilter @TraceID,35,0,1,N'master' + exec sp_trace_setfilter @TraceID,35,0,1,N'temp' + exec sp_trace_setfilter @TraceID,35,0,1,N'msdb' + exec sp_trace_setfilter @TraceID,35,0,1,N'model' + exec sp_trace_setfilter @TraceID,35,0,1,N'monitor' + + --启动跟踪 + EXEC SP_TRACE_SETSTATUS @TRACEID,1 + --存入新建的跟踪ID到DBO.TRACE_CURRENT_TRACEINFO,以便下次停用 + SET @TRACEFILE = @TRACEFILE+'.trc' + + INSERT INTO DBO.TRACE_CURRENT_TRACEINFO + SELECT GETDATE(),@TRACEID,@TRACEFILE + GOTO FINISH + ERROR: + EXEC SP_TRACE_SETSTATUS @TRACEID,0 + EXEC SP_TRACE_SETSTATUS @TRACEID,2 + SELECT ERRORCODE=@RESULT_CODE + FINISH: + END + + --导入跟踪数据 + IF LEN(@OLDTRACEFILE) > 1 + BEGIN + INSERT INTO DBO.TRACE_TSQL(SQLTXT,SQLCHECKSUM,TEXTDATA,APPLICATIONNAME,NTUSERNAME,LOGINNAME,DURATION,STARTTIME,ENDTIME,READS,WRITES,CPU,SERVERNAME,ERROR,OBJECTID,OBJECTNAME,DATABASENAME,ROWCOUNTS) + SELECT LEFT(REPLACE(CASE WHEN CHARINDEX('@',TEXTDATA) > 0 THEN SUBSTRING(TEXTDATA,CHARINDEX('EXEC ',TEXTDATA),CHARINDEX(' ',TEXTDATA,CHARINDEX('EXEC ',TEXTDATA)+5)-CHARINDEX('EXEC ',TEXTDATA)) ELSE CAST(SUBSTRING(TEXTDATA,1,4000) AS VARCHAR(4000)) END,'EXEC ',''),4000), + CHECKSUM(REPLACE(CASE WHEN CHARINDEX('@',TEXTDATA) > 0 THEN SUBSTRING(TEXTDATA,CHARINDEX('EXEC ',TEXTDATA),CHARINDEX(' ',TEXTDATA,CHARINDEX('EXEC ',TEXTDATA)+5)-CHARINDEX('EXEC ',TEXTDATA)) ELSE CAST(SUBSTRING(TEXTDATA,1,8000) AS VARCHAR(8000)) END,'EXEC ','')), + SUBSTRING(TEXTDATA,1,4000),APPLICATIONNAME,NTUSERNAME,LOGINNAME,DURATION,STARTTIME,ENDTIME,READS,WRITES,CPU,SERVERNAME,ERROR,OBJECTID,OBJECTNAME,DATABASENAME,ROWCOUNTS + FROM FN_TRACE_GETTABLE(@OLDTRACEFILE,DEFAULT) + WHERE TEXTDATA IS NOT NULL + + IF @DELETE_OLD_TRACE_FILE = 1 + BEGIN + SET @CMD = 'DEL '+@OLDTRACEFILE + EXEC XP_CMDSHELL @CMD,NO_OUTPUT + END + END + + --删除数据 + DELETE DBO.TRACE_TSQL WHERE STARTTIME < CONVERT(CHAR(8),GETDATE()-@KEEPDATADAYS,112) +END +GO + + +-- ============================================= +--功能:DB故障进行验证并切换到DR +--不能切换的场景: +--1.DB待发送日志大于10MB +--2.DR待重做日志大于1MB +--切换方式: +--USE MASTER ALTER DATABASE DBNAME SET PARTNER FORCE_SERVICE_ALLOW_DATA_LOSS; +--检测镜像是否都切换为主 +-- ============================================= +IF OBJECT_ID('DBO.TOOL_DR2DB','P') IS NOT NULL + DROP PROC DBO.TOOL_DR2DB +GO +CREATE PROCEDURE DBO.TOOL_DR2DB +AS +BEGIN + + SET NOCOUNT ON; + DECLARE @SQL VARCHAR(MAX),@PORT VARCHAR(100) + + + BEGIN TRY + --获取多实例的端口 + EXEC Monitor.DBO.TOOL_GET_IPPORT NULL,@PORT OUT + IF @PORT IS NULL + RAISERROR(N'GAMEDR SWITCH ERROR',11,1); + + --不能切换的场景 + --1.DB待发送日志大于10MB + IF EXISTS(SELECT 1 FROM SYS.DM_OS_PERFORMANCE_COUNTERS + WHERE OBJECT_NAME LIKE '%Database Mirroring%' + AND COUNTER_NAME = 'Log Send Queue KB' + AND CNTR_VALUE > 10240) + BEGIN + SELECT -1 AS STATUS,'GAMEDB LOG SEND QUEUE MORE THAN 10MB' AS MSG + RETURN -1 + END + + --2.DR待重做日志大于1MB + IF EXISTS(SELECT 1 FROM SYS.DM_OS_PERFORMANCE_COUNTERS + WHERE OBJECT_NAME LIKE '%Database Mirroring%' + AND COUNTER_NAME = 'Redo Queue KB' + AND CNTR_VALUE > 1024) + BEGIN + SELECT -1 AS STATUS,'GAMEDR REDO QUEUE MORE THAN 1MB' AS MSG + RETURN -1 + END + + --记录需要切换的数据库 + IF OBJECT_ID('TEMPDB.DBO.#DBLIST','U') IS NOT NULL + DROP TABLE #DBLIST + SELECT A.NAME INTO #DBLIST + FROM SYS.DATABASES A,SYS.DATABASE_MIRRORING B + WHERE A.DATABASE_ID = B.DATABASE_ID + AND A.DATABASE_ID > 4 + AND A.NAME <> 'Monitor' + AND B.MIRRORING_ROLE = 2 + AND B.MIRRORING_STATE IS NOT NULL + + --切换 + --1.DR断开/删除ENDPOINT + IF EXISTS(SELECT 1 FROM SYS.ENDPOINTS WHERE NAME = N'endpoint_mirroring') + DROP ENDPOINT endpoint_mirroring + --2.DR切换 + SET @SQL = NULL + SELECT @SQL=ISNULL(@SQL+'','')+'ALTER DATABASE ['+NAME+'] SET PARTNER FORCE_SERVICE_ALLOW_DATA_LOSS;' + FROM #DBLIST + --PRINT(@SQL) + EXEC(@SQL) + --3.重新建立ENDPOINT + SET @SQL = 'CREATE ENDPOINT endpoint_mirroring STATE = STARTED AS TCP ( LISTENER_PORT = '+LTRIM(37022+RIGHT(@PORT/10,1)-2)+' ) FOR DATABASE_MIRRORING (ROLE=PARTNER);' + --PRINT(@SQL) + EXEC(@SQL) + + --检查镜像是否都切换为主 + IF EXISTS(SELECT 1 FROM SYS.DATABASE_MIRRORING WHERE MIRRORING_ROLE = 2) + RAISERROR(N'gamedr switch failed',11,1); + + SELECT 1 AS STATUS,'gamedr switch success' AS MSG + END TRY + + BEGIN CATCH + SELECT -1 AS STATUS,'gamedr switch exception' AS MSG + END CATCH + +END +GO + + +-- ============================================= +-- Description: 业务公用-生成镜像数据库快照 +-- ============================================= +IF OBJECT_ID('DBO.JOB_SNAPSHOT','P') IS NOT NULL + DROP PROC DBO.JOB_SNAPSHOT +GO +CREATE PROCEDURE DBO.JOB_SNAPSHOT +AS +BEGIN + + SET NOCOUNT ON + + declare @dbid int,@db sysname,@dr sysname, @logic sysname,@has_monitor tinyint,@msg varchar(2000),@cmd varchar(max),@cmd2 varchar(max) + + declare @port sysname + exec monitor.dbo.TOOL_GET_IPPORT null,@port output + + declare @exec_time datetime + set @exec_time=getdate() + + declare @version bigint,@is_alwayson_flag tinyint + set @version=convert(bigint,DATABASEPROPERTYEX('master','version')) + set @is_alwayson_flag=0 + + IF OBJECT_ID('TEMPDB.DBO.#tmp_alwayson','U') IS NOT NULL + DROP TABLE #tmp_alwayson + create table #tmp_alwayson(name varchar(200)) + + IF OBJECT_ID('TEMPDB.DBO.#tmp_dblist','U') IS NOT NULL + DROP TABLE #tmp_dblist + create table #tmp_dblist(dbid int,name varchar(200),flag tinyint) + + IF @version>=869 + exec('insert into #tmp_alwayson select name from sys.availability_groups') + + IF exists(select 1 from #tmp_alwayson) + set @is_alwayson_flag=1 + + if @is_alwayson_flag=1 + exec('insert into #tmp_dblist select database_id,name,0 from master.sys.databases where database_id>4 and name not in(''monitor'') and name not like ''%_dr'' and database_id in(SELECT database_id from sys.dm_hadr_database_replica_states where is_local=1 and synchronization_state=1)') + else + insert into #tmp_dblist select database_id,name,0 from master.sys.databases where database_id>4 and name not in('monitor') and name not like '%_dr' and database_id in(select database_id from master.sys.database_mirroring where mirroring_guid is not null and mirroring_state=4) + + declare @i int,@fileid int + declare @filename sysname + set @i=1 + while @i<=10 + begin + declare cur cursor for + select dbid,name from #tmp_dblist where flag=0 + open cur + while 1=1 + begin + fetch next from cur into @dbid,@db + if @@FETCH_STATUS<>0 break + set @dr=@db+'_dr' + + IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = @dr and create_date>=@exec_time) + BEGIN + IF EXISTS (SELECT name FROM sys.databases WHERE name = @dr) + BEGIN + SET @cmd='DROP DATABASE '+@dr + EXEC (@cmd) + + SET @cmd2='EXEC MASTER.DBO.xp_cmdshell ''del /q d:\gamedb\'+@dr+'.'+@port+'.*.spst'';' + EXEC (@cmd2) + END + + select @filename=null,@cmd='',@fileid=0,@cmd='CREATE DATABASE '+@dr+' ON ' + declare cur1 cursor for select name from sys.master_files where database_id=@dbid and type_desc='ROWS' and state_desc='ONLINE' + open cur1 + while 1=1 + begin + set @filename=null + fetch next from cur1 into @filename + if @@FETCH_STATUS<>0 break + select @cmd=@cmd+'(NAME='''+@filename+''',FILENAME='''+'D:\gamedb\'+@dr+'.'+@port+'.'+CONVERT(varchar,@fileid)+'.spst'+'''),' + ,@fileid=@fileid+1 + end + close cur1 + deallocate cur1 + + set @cmd=left(@cmd,len(@cmd)-1)+' AS SNAPSHOT OF '+@db + + BEGIN TRY + EXEC (@cmd) + END TRY + BEGIN CATCH + SET @cmd2='EXEC MASTER.DBO.xp_cmdshell ''del /q d:\gamedb\'+@dr+'.'+@port+'.*.spst'';' + EXEC (@cmd2) + + EXEC (@cmd) + END CATCH + END + ELSE + BEGIN + update #tmp_dblist set flag=1 where dbid=@dbid + END + END + close cur + deallocate cur + + set @i=@i+1 + + waitfor delay '00:00:02' + end +END + +GO + +-- ============================================= +-- Description: 自动部署服务器的复制监控 +-- ============================================= +IF OBJECT_ID('DBO.TOOL_DEPLOY_REPL_MONITOR','P') IS NOT NULL + DROP PROC DBO.TOOL_DEPLOY_REPL_MONITOR +GO +CREATE PROCEDURE DBO.TOOL_DEPLOY_REPL_MONITOR +AS +BEGIN + SET NOCOUNT ON + + DECLARE @SQL VARCHAR(MAX) + SELECT @SQL = ISNULL(@SQL+' + ','')+' + USE MSDB + DECLARE @JOBNAME'+UPPER(NAME)+' VARCHAR(2000)=''TC_REPL_MONITOR_'+UPPER(NAME)+''' + IF EXISTS(SELECT 1 FROM MSDB.DBO.SYSJOBS WHERE NAME=@JOBNAME'+UPPER(NAME)+') + BEGIN + EXEC MSDB.DBO.SP_DELETE_JOB @job_name=@JOBNAME'+UPPER(NAME)+',@delete_unused_schedule=1 + END + + USE ['+A.NAME+'] + IF OBJECT_ID(''DBO.TC_REPL_CHECK_LOG'',''U'') IS NULL + CREATE TABLE DBO.TC_REPL_CHECK_LOG + ( + WRITETIME DATETIME NULL, + [TYPE] INT NULL + ) + + DECLARE @SQLINSIDE'+UPPER(NAME)+' VARCHAR(MAX) + SET @SQLINSIDE'+UPPER(NAME)+'= + CASE WHEN OBJECT_ID(''DBO.TC_JOB_REPL_MONITOR'',''P'') IS NOT NULL THEN ''ALTER'' ELSE ''CREATE'' END+'' PROC [DBO].[TC_JOB_REPL_MONITOR] + @PUB SYSNAME = '''''+A.NAME+''''', + @MAXLATENCYSECONDS INT = 15 + AS + BEGIN + SET NOCOUNT ON + + IF NOT EXISTS(SELECT 1 FROM SYS.DATABASES WHERE IS_PUBLISHED = 1 AND NAME = '''''+A.NAME+''''') + RETURN + + SET XACT_ABORT ON + DECLARE @MESSAGE VARCHAR(8000) + DECLARE @DOS_CMD VARCHAR(8000) + + DECLARE @IP VARCHAR(100),@PORT VARCHAR(100),@APPCODE VARCHAR(100) + EXEC MONITOR.DBO.TOOL_GET_IPPORT @IP OUTPUT,@PORT OUTPUT + SELECT @APPCODE = APP FROM Monitor.DBO.BACKUP_SETTING + + IF OBJECT_ID('''''+A.NAME+'.DBO.TC_REPL_LATENCY_STATS'''') IS NULL + CREATE TABLE '+A.NAME+'.DBO.TC_REPL_LATENCY_STATS + ( + DISTRIBUTOR_LATENCY INT NULL, + SUBSCRIBER VARCHAR(1000) NULL, + SUBSCRIBER_DB VARCHAR(1000) NULL, + SUBSCRIBER_LATENCY INT NULL, + OVERALL_LATENCY INT NULL + ) + TRUNCATE TABLE '+A.NAME+'.DBO.TC_REPL_LATENCY_STATS + + DECLARE @TOKENHANDLE BIGINT + EXEC SP_POSTTRACERTOKEN @PUBLICATION = @PUB,@TRACER_TOKEN_ID = @TOKENHANDLE OUTPUT; + + IF @TOKENHANDLE IS NULL OR @@ERROR<>0 + BEGIN + INSERT INTO '+A.NAME+'.DBO.TC_REPL_CHECK_LOG VALUES(GETDATE(),1) + IF EXISTS(SELECT 1 FROM '+A.NAME+'.DBO.TC_REPL_CHECK_LOG WHERE TYPE=1 GROUP BY TYPE HAVING COUNT(1)>=5) + BEGIN + DELETE '+A.NAME+'.DBO.TC_REPL_CHECK_LOG WHERE TYPE=1 + INSERT INTO OPENROWSET(''''SQLNCLI'''','''''+B.IP+','+B.PORT+''''';'''''+B.ACCOUNT+''''';'''''+B.PWD+''''','+B.DBNAME+'.DBO.PRIMITIVELOG)(APPCODE,IP,PORT,TYPE,VALUE) + SELECT @APPCODE,@IP,@PORT,''''REPL_TOKEN'''',1 + END + RETURN -1 + END + ELSE + BEGIN + DELETE '+A.NAME+'.DBO.TC_REPL_CHECK_LOG WHERE TYPE=1 + END + + DECLARE @MAXWAIT INT = @MAXLATENCYSECONDS * 2; + IF @MAXWAIT > 30 + BEGIN + SET @MAXWAIT = 30; + END + DECLARE @WAITFOR VARCHAR(10) = ''''00:00:'''' + CAST((@MAXWAIT) AS VARCHAR(2)); + WAITFOR DELAY @WAITFOR; + + INSERT '+A.NAME+'.DBO.TC_REPL_LATENCY_STATS (DISTRIBUTOR_LATENCY,SUBSCRIBER,SUBSCRIBER_DB,SUBSCRIBER_LATENCY,OVERALL_LATENCY) + EXEC SP_HELPTRACERTOKENHISTORY @PUB,@TOKENHANDLE; + + IF @@ROWCOUNT=0 OR @@ERROR<>0 + BEGIN + INSERT INTO '+A.NAME+'.DBO.TC_REPL_CHECK_LOG VALUES(GETDATE(),2) + IF EXISTS(SELECT 1 FROM '+A.NAME+'.DBO.TC_REPL_CHECK_LOG WHERE TYPE=2 GROUP BY TYPE HAVING COUNT(1)>=5) + BEGIN + DELETE '+A.NAME+'.DBO.TC_REPL_CHECK_LOG WHERE TYPE=2 + INSERT INTO OPENROWSET(''''SQLNCLI'''','''''+B.IP+','+B.PORT+''''';'''''+B.ACCOUNT+''''';'''''+B.PWD+''''','+B.DBNAME+'.DBO.PRIMITIVELOG)(APPCODE,IP,PORT,TYPE,VALUE) + SELECT @APPCODE,@IP,@PORT,''''REPL_TOKEN'''',1 + END + RETURN -1 + END + ELSE + BEGIN + DELETE '+A.NAME+'.DBO.TC_REPL_CHECK_LOG WHERE TYPE=2 + END + + DECLARE @CUTOFF DATETIME = GETDATE(); + EXEC SP_DELETETRACERTOKENHISTORY @PUBLICATION = @PUB,@CUTOFF_DATE = @CUTOFF; + + IF EXISTS(SELECT 1 FROM '+A.NAME+'.DBO.TC_REPL_LATENCY_STATS WHERE OVERALL_LATENCY IS NULL) OR NOT EXISTS(SELECT 1 FROM '+A.NAME+'.DBO.TC_REPL_LATENCY_STATS) + BEGIN + INSERT INTO '+A.NAME+'.DBO.TC_REPL_CHECK_LOG VALUES(GETDATE(),3) + IF (EXISTS(SELECT 1 FROM '+A.NAME+'.DBO.TC_REPL_CHECK_LOG WHERE TYPE=3 GROUP BY TYPE HAVING COUNT(1)>=5)) + BEGIN + DELETE '+A.NAME+'.DBO.TC_REPL_CHECK_LOG WHERE TYPE=3 + INSERT INTO OPENROWSET(''''SQLNCLI'''','''''+B.IP+','+B.PORT+''''';'''''+B.ACCOUNT+''''';'''''+B.PWD+''''','+B.DBNAME+'.DBO.PRIMITIVELOG)(APPCODE,IP,PORT,TYPE,VALUE) + SELECT @APPCODE,@IP,@PORT,''''REPL_SEND_LOG'''',1 + END + RETURN -1 + END + ELSE + BEGIN + DELETE '+A.NAME+'.DBO.TC_REPL_CHECK_LOG WHERE TYPE=3 + END + + IF EXISTS(SELECT 1 FROM '+A.NAME+'.DBO.TC_REPL_LATENCY_STATS WHERE OVERALL_LATENCY > @MAXLATENCYSECONDS) + BEGIN + INSERT INTO '+A.NAME+'.DBO.TC_REPL_CHECK_LOG VALUES(GETDATE(),5) + + IF (EXISTS(SELECT 1 FROM '+A.NAME+'.DBO.TC_REPL_CHECK_LOG WHERE TYPE=5 GROUP BY TYPE HAVING COUNT(1)>=5)) + BEGIN + DELETE '+A.NAME+'.DBO.TC_REPL_CHECK_LOG WHERE TYPE=5 + INSERT INTO OPENROWSET(''''SQLNCLI'''','''''+B.IP+','+B.PORT+''''';'''''+B.ACCOUNT+''''';'''''+B.PWD+''''','+B.DBNAME+'.DBO.PRIMITIVELOG)(APPCODE,IP,PORT,TYPE,VALUE) + SELECT @APPCODE,@IP,@PORT,''''REPL_LATENCY'''',1 + RETURN -1 + END + END + ELSE + BEGIN + DELETE '+A.NAME+'.DBO.TC_REPL_CHECK_LOG WHERE TYPE=5 + END + END''; + EXEC(@SQLINSIDE'+UPPER(NAME)+') + + USE MSDB + DECLARE @jobId'+UPPER(NAME)+' BINARY(16) + + DECLARE @SERVERNAME'+UPPER(NAME)+' VARCHAR(2000)=CAST(SERVERPROPERTY(''SERVERNAME'') AS SYSNAME) + DECLARE @SCHEDULENAME'+UPPER(NAME)+' VARCHAR(2000)=''REPLCHECK_'+UPPER(NAME)+''' + DECLARE @CMD'+UPPER(NAME)+' VARCHAR(2000)=''EXEC DBO.TC_JOB_REPL_MONITOR'' + DECLARE @STEPNAME'+UPPER(NAME)+' VARCHAR(2000)=''REPLCHECK_'+UPPER(NAME)+''' + DECLARE @DBNAME'+UPPER(NAME)+' VARCHAR(2000)='''+UPPER(NAME)+''' + + EXEC msdb.dbo.sp_add_job @job_name=@JOBNAME'+UPPER(NAME)+', + @enabled=1, + @notify_level_eventlog=0, + @notify_level_email=2, + @notify_level_netsend=2, + @notify_level_page=2, + @delete_level=0, + @category_name=N''[Uncategorized (Local)]'', + @owner_login_name=''sa'',@job_id = @jobId'+UPPER(NAME)+' OUTPUT + EXEC msdb.dbo.sp_add_jobserver @job_name=@JOBNAME'+UPPER(NAME)+',@server_name = @SERVERNAME'+UPPER(NAME)+' + EXEC msdb.dbo.sp_add_jobstep @job_name=@JOBNAME'+UPPER(NAME)+',@step_name=@STEPNAME'+UPPER(NAME)+', + @step_id=1, + @cmdexec_success_code=0, + @on_success_action=1, + @on_fail_action=2, + @retry_attempts=0, + @retry_interval=0, + @os_run_priority=0,@subsystem=N''TSQL'', + @command=@CMD'+UPPER(NAME)+', + @database_name=@DBNAME'+UPPER(NAME)+', + @flags=0 + EXEC msdb.dbo.sp_update_job @job_name=@JOBNAME'+UPPER(NAME)+', + @enabled=1, + @start_step_id=1, + @notify_level_eventlog=0, + @notify_level_email=2, + @notify_level_netsend=2, + @notify_level_page=2, + @delete_level=0, + @description=N'''', + @category_name=N''[Uncategorized (Local)]'', + @owner_login_name=''sa'', + @notify_email_operator_name=N'''', + @notify_netsend_operator_name=N'''', + @notify_page_operator_name=N'''' + DECLARE @schedule_id'+UPPER(NAME)+' int + EXEC msdb.dbo.sp_add_jobschedule @job_name=@JOBNAME'+UPPER(NAME)+',@name=@SCHEDULENAME'+UPPER(NAME)+', + @enabled=1, + @freq_type=4, + @freq_interval=1, + @freq_subday_type=4, + @freq_subday_interval=1, + @freq_relative_interval=0, + @freq_recurrence_factor=0, + @active_start_date=20130509, + @active_end_date=99991231, + @active_start_time=0, + @active_end_time=235959, + @schedule_id = @schedule_id'+UPPER(NAME)+' OUTPUT + SELECT @jobId'+UPPER(NAME)+' AS JOBID,@schedule_id'+UPPER(NAME)+' AS SCHEDULE_ID;' + FROM SYS.DATABASES A,MONITOR.DBO.MONITOR_SERVER_SETTING B + WHERE A.DATABASE_ID > 4 + AND A.STATE = 0 + AND A.IS_READ_ONLY = 0 + AND A.IS_DISTRIBUTOR = 0 + AND A.IS_PUBLISHED = 1 + AND B.STATE = 1 + --PRINT(@SQL) + EXEC(@SQL) +END +GO + +IF OBJECT_ID('DBO.TOOL_DEPLOY_SNAPSHOT','P') IS NOT NULL + DROP PROC DBO.TOOL_DEPLOY_SNAPSHOT +GO +CREATE PROCEDURE DBO.TOOL_DEPLOY_SNAPSHOT +@JOBNAME VARCHAR(100) = 'TC_SNAPSHOT', +@JOBSTARTTIME INT = 0 +AS +BEGIN + SET NOCOUNT ON; + + DECLARE @jobId BINARY(16) + + DECLARE @SERVERNAME VARCHAR(2000) + DECLARE @STEPNAME VARCHAR(2000),@DBNAME VARCHAR(2000) + DECLARE @SCHEDULENAME VARCHAR(2000),@CMD VARCHAR(2000) + + SELECT @CMD='EXEC MONITOR.DBO.JOB_SNAPSHOT' + + SELECT @STEPNAME=@JOBNAME+'_1', + @SCHEDULENAME=@JOBNAME+'_1', + @DBNAME='MASTER', + @SERVERNAME=CAST(SERVERPROPERTY('SERVERNAME') AS SYSNAME) + + IF EXISTS(SELECT 1 FROM MSDB.dbo.sysjobs WHERE NAME=@JOBNAME) + BEGIN + EXEC msdb.dbo.sp_delete_job @job_name=@JOBNAME,@delete_unused_schedule=1 + END + EXEC msdb.dbo.sp_add_job @job_name=@JOBNAME, + @enabled=1, + @notify_level_eventlog=0, + @notify_level_email=2, + @notify_level_netsend=2, + @notify_level_page=2, + @delete_level=0, + @category_name=N'[Uncategorized (Local)]', + @owner_login_name='sa',@job_id = @jobId OUTPUT + + EXEC msdb.dbo.sp_add_jobserver @job_name=@JOBNAME,@server_name = @SERVERNAME + + EXEC msdb.dbo.sp_add_jobstep @job_name=@JOBNAME,@step_name=@STEPNAME, + @step_id=1, + @cmdexec_success_code=0, + @on_success_action=1, + @on_fail_action=2, + @retry_attempts=0, + @retry_interval=0, + @os_run_priority=0,@subsystem=N'TSQL', + @command=@CMD, + @database_name=@DBNAME, + @flags=0 + EXEC msdb.dbo.sp_update_job @job_name=@JOBNAME, + @enabled=1, + @start_step_id=1, + @notify_level_eventlog=0, + @notify_level_email=2, + @notify_level_netsend=2, + @notify_level_page=2, + @delete_level=0, + @description=N'', + @category_name=N'[Uncategorized (Local)]', + @owner_login_name='sa', + @notify_email_operator_name=N'', + @notify_netsend_operator_name=N'', + @notify_page_operator_name=N'' + DECLARE @schedule_id int + EXEC msdb.dbo.sp_add_jobschedule @job_name=@JOBNAME,@name=@SCHEDULENAME, + @enabled=1, + @freq_type=4, + @freq_interval=1, + @freq_subday_type=1, + @freq_subday_interval=0, + @freq_relative_interval=0, + @freq_recurrence_factor=1, + @active_start_date=20130723, + @active_end_date=99991231, + @active_start_time=@JOBSTARTTIME, + @active_end_time=235959,@schedule_id = @schedule_id OUTPUT + SELECT @jobId AS JOBID,@schedule_id AS SCHEDULE_ID +END +GO + +IF OBJECT_ID('DBO.JOB_MONITOR_FILTER','P') IS NOT NULL + DROP PROC DBO.JOB_MONITOR_FILTER +GO +CREATE PROC DBO.JOB_MONITOR_FILTER +WITH RECOMPILE +AS +BEGIN + SET NOCOUNT ON + DECLARE @APPCODE VARCHAR(100),@CONNECT_FAIL_TIMES INT + + --UPLOAD DATA + DECLARE @IP VARCHAR(20),@PORT VARCHAR(20),@SQL VARCHAR(MAX) + EXEC MONITOR.DBO.TOOL_GET_IPPORT @IP OUTPUT,@PORT OUTPUT + + SELECT @APPCODE = APP FROM DBO.BACKUP_SETTING + SELECT @CONNECT_FAIL_TIMES = COUNT(1) + FROM DBO.MONITOR_SERVER_UNAVAILABLE_HISTORY A,DBO.MONITOR_SERVER_SETTING B + WHERE A.WRITETIME >= DATEADD(MI,-3,GETDATE()) + AND A.IP = B.IP AND A.PORT = B.PORT AND A.DBNAME = B.DBNAME AND A.PWD = B.PWD + AND B.[STATE] = 1 + IF @CONNECT_FAIL_TIMES >= 2 + BEGIN + UPDATE DBO.MONITOR_SERVER_SETTING SET [STATE] = [STATE]^1 + END + + IF EXISTS(SELECT 1 FROM [Monitor].[dbo].[BACKUP_SETTING] where APP in(SELECT APP FROM MONITOR.DBO.APP_SETTING)) + BEGIN + IF EXISTS(select 1 from sys.dm_os_sys_info where datediff(mi,sqlserver_start_time,getdate())<=5) + BEGIN + IF OBJECT_ID('TEMPDB.DBO.#TMP_TRACESTATUS','U') IS NOT NULL + DROP TABLE #TMP_TRACESTATUS + + CREATE TABLE #TMP_TRACESTATUS(traceflag bigint,status bigint,global bigint,session bigint) + + INSERT INTO #TMP_TRACESTATUS + EXEC('DBCC TRACESTATUS (1118,1204,1222,3605, -1);') + + IF NOT EXISTS(SELECT 1 FROM #TMP_TRACESTATUS where global=1) + DBCC TRACEON (1118,1204,1222,3605, -1); + END + END + + IF EXISTS(SELECT 1 FROM SYS.DATABASE_MIRRORING where mirroring_safety_level=2) + BEGIN + SELECT @SQL = ISNULL(@SQL+'','')+'ALTER DATABASE ['+b.name+'] SET SAFETY OFF;' + FROM SYS.DATABASE_MIRRORING a left join sys.databases b on a.database_id=b.database_id + where mirroring_safety_level=2 + EXEC(@SQL) + END + + /* + IF EXISTS(SELECT 1 FROM SYS.DATABASE_MIRRORING WHERE MIRRORING_STATE IN (0,2)) + BEGIN + exec monitor.dbo.Sys_AutoSwitch_Suspend null + exec monitor.dbo.Sys_AutoSwitch_Resume null + END + + IF EXISTS(SELECT 1 FROM master.sys.dm_os_performance_counters + WHERE object_name LIKE '%Database Mirroring%' + AND counter_name='Redo Queue KB' and cntr_value>1048576) + OR EXISTS(SELECT 1 + FROM SYS.MASTER_FILES A,MONITOR.DBO.BACKUP_DBLIST B + WHERE A.DATABASE_ID = B.DATABASE_ID + AND A.TYPE = 1 + AND SIZE > 30*1024*1024/8) + BEGIN + IF EXISTS(select 1 from [master].[sys].[database_mirroring_endpoints]) + BEGIN + ALTER ENDPOINT [endpoint_mirroring] STATE = STOPPED + ALTER ENDPOINT [endpoint_mirroring] STATE = STARTED + END + END + */ + /* self-healing MIRRORING_LOG_SEND_QUEUE_KB */ + SET @SQL = NULL + SELECT @SQL = ISNULL(@SQL+';'+CHAR(13),'')+' + + IF EXISTS(SELECT 1 FROM master.sys.database_mirroring where database_id='+convert(varchar,A.database_id)+') + + + ALTER DATABASE ['+A.NAME+'] set partner off; + USE MASTER ALTER DATABASE ['+A.NAME+'] SET RECOVERY SIMPLE WITH NO_WAIT; + USE ['+A.NAME+'] DBCC SHRINKFILE ('''+B.NAME+''',0,TRUNCATEONLY); + USE MASTER ALTER DATABASE ['+A.NAME+'] SET RECOVERY FULL WITH NO_WAIT; + ' + FROM MASTER.SYS.DATABASES A,MASTER.SYS.MASTER_FILES B + WHERE A.DATABASE_ID > 4 + AND A.NAME in ( + SELECT a.instance_name + FROM MASTER.SYS.DM_OS_PERFORMANCE_COUNTERS A,monitor.DBO.MONITOR_FILTER_SETTING B + WHERE B.NAME = 'MIRRORING_LOG_SEND_QUEUE_KB' + AND A.OBJECT_NAME LIKE '%DATABASE MIRRORING%' + AND A.COUNTER_NAME='LOG SEND QUEUE KB' + AND A.INSTANCE_NAME != '_TOTAL' + AND A.CNTR_VALUE > B.VALUE*10 + AND EXISTS(SELECT 1 FROM MASTER.SYS.DATABASE_MIRRORING C WHERE C.MIRRORING_ROLE = 1) + ) + + AND A.DATABASE_ID = B.DATABASE_ID + AND B.TYPE = 1 + -- print(@SQL) + EXEC(@SQL) + + SET @SQL = NULL + SELECT @SQL = ' + --SERVICE_AVAILABLE + INSERT INTO OPENROWSET(''SQLNCLI'','''+IP+','+PORT+''';'''+ACCOUNT+''';'''+PWD+''','+DBNAME+'.DBO.INSTANCE_AVAILABLE_HISTORY)(APPCODE,IP,PORT) VALUES('''+@APPCODE+''','''+@IP+''','+@PORT+') + INSERT INTO OPENROWSET(''SQLNCLI'','''+IP+','+PORT+''';'''+ACCOUNT+''';'''+PWD+''','+DBNAME+'.DBO.PRIMITIVELOG)(APPCODE,IP,PORT,TYPE,VALUE) + --DISK_D_FREE_MB + SELECT '''+@APPCODE+''','''+@IP+''','+@PORT+',B.NAME,A.NEXTVALUE + FROM DBO.PERFORMANCESLOG A,DBO.MONITOR_FILTER_SETTING B + WHERE B.NAME = ''DISK_D_FREE_MB'' + AND A.CATEGORYNAME = ''LOGICALDISK'' + AND A.INSTANCENAME = ''D:'' + AND A.COUNTERNAME = ''Free Megabytes'' + AND A.WRITETIME > DATEADD(MI,-1,GETDATE()) + AND A.NEXTVALUE < B.VALUE + UNION ALL + --DISK_C_FREE_MB + SELECT '''+@APPCODE+''','''+@IP+''','+@PORT+',B.NAME,A.NEXTVALUE + FROM DBO.PERFORMANCESLOG A,DBO.MONITOR_FILTER_SETTING B + WHERE B.NAME = ''DISK_C_FREE_MB'' + AND A.CATEGORYNAME = ''LOGICALDISK'' + AND A.INSTANCENAME = ''C:'' + AND A.COUNTERNAME = ''Free Megabytes'' + AND A.WRITETIME > DATEADD(MI,-1,GETDATE()) + AND A.NEXTVALUE < B.VALUE + UNION ALL + --CPU_USE_PERCENT + SELECT '''+@APPCODE+''','''+@IP+''','+@PORT+',B.NAME,A.NEXTVALUE + FROM DBO.PERFORMANCESLOG A,DBO.MONITOR_FILTER_SETTING B + WHERE B.NAME = ''CPU_USE_PERCENT'' + AND A.CATEGORYNAME = ''PROCESSOR'' + AND A.COUNTERNAME = ''% Processor Time'' + AND A.WRITETIME > DATEADD(MI,-1,GETDATE()) + AND A.NEXTVALUE > B.VALUE + UNION ALL + --IO_IDLE_PERCENT + SELECT '''+@APPCODE+''','''+@IP+''','+@PORT+',B.NAME,A.NEXTVALUE + FROM DBO.PERFORMANCESLOG A,DBO.MONITOR_FILTER_SETTING B + WHERE B.NAME = ''IO_IDLE_PERCENT'' + AND A.CATEGORYNAME = ''LogicalDisk'' + AND A.INSTANCENAME = ''D:'' + AND A.COUNTERNAME = ''% Idle Time'' + AND A.WRITETIME > DATEADD(MI,-1,GETDATE()) + AND A.NEXTVALUE < B.VALUE + AND EXISTS(SELECT 1 FROM DBO.BACKUP_DBLIST) + AND NOT EXISTS(SELECT 1 FROM SYS.DM_EXEC_REQUESTS WHERE COMMAND LIKE ''BACKUP%'') + UNION ALL + --MEMORY_FREE_MB + SELECT '''+@APPCODE+''','''+@IP+''','+@PORT+',B.NAME,A.NEXTVALUE + FROM DBO.PERFORMANCESLOG A,DBO.MONITOR_FILTER_SETTING B + WHERE B.NAME = ''MEMORY_FREE_MB'' + AND A.CATEGORYNAME = ''Memory'' + AND A.COUNTERNAME = ''Available MBytes'' + AND A.WRITETIME > DATEADD(MI,-1,GETDATE()) + AND A.NEXTVALUE < B.VALUE + UNION ALL + --MIRRORING_LOG_SEND_QUEUE_KB + SELECT '''+@APPCODE+''','''+@IP+''','+@PORT+',B.NAME,A.CNTR_VALUE + FROM MASTER.SYS.DM_OS_PERFORMANCE_COUNTERS A,DBO.MONITOR_FILTER_SETTING B + WHERE B.NAME = ''MIRRORING_LOG_SEND_QUEUE_KB'' + AND A.OBJECT_NAME LIKE ''%DATABASE MIRRORING%'' + AND A.COUNTER_NAME=''LOG SEND QUEUE KB'' + AND A.INSTANCE_NAME != ''_TOTAL'' + AND A.CNTR_VALUE > B.VALUE*10 + AND EXISTS(SELECT 1 FROM SYS.DATABASE_MIRRORING C WHERE C.MIRRORING_ROLE = 1) + UNION ALL + --USER_CONNECTION_NUMBER + SELECT '''+@APPCODE+''','''+@IP+''','+@PORT+',B.NAME,A.NEXTVALUE + FROM DBO.PERFORMANCESLOG A,DBO.MONITOR_FILTER_SETTING B + WHERE B.NAME = ''USER_CONNECTION_NUMBER'' + AND A.CATEGORYNAME LIKE ''%General Statistics'' + AND A.COUNTERNAME = ''User Connections'' + AND A.WRITETIME > DATEADD(MI,-1,GETDATE()) + AND A.NEXTVALUE > B.VALUE + UNION ALL + --SLOW_QUERY_IN_5MI + SELECT '''+@APPCODE+''','''+@IP+''','+@PORT+',B.NAME,COUNT(1) + FROM MONITOR.DBO.TRACE_TSQL A,DBO.MONITOR_FILTER_SETTING B + WHERE B.NAME = ''SLOW_QUERY_IN_5MI'' + AND A.STARTTIME >= DATEADD(MI,-1*B.VALUE,GETDATE()) + AND A.DATABASENAME <> ''MONITOR'' + AND ISNULL(A.APPLICATIONNAME,'''') NOT LIKE ''SQLAgent%'' + AND ISNULL(A.APPLICATIONNAME,'''') <> ''SQLCMD'' + AND A.LOGINNAME NOT IN( ''sa'',''distributor_admin'') + AND A.LOGINNAME NOT LIKE ''%\sqlserver'' + GROUP BY B.NAME + HAVING COUNT(1) > 0' + FROM DBO.MONITOR_SERVER_SETTING + WHERE [STATE] = 1 + --PRINT(@SQL) + EXEC(@SQL) + + + SET @SQL = NULL + SELECT @SQL = ' + --MIRRORING_STATUS + IF EXISTS(SELECT 1 + FROM SYS.DATABASE_MIRRORING + WHERE ISNULL(MIRRORING_STATE,4) NOT IN (2,4) + AND EXISTS(SELECT 1 FROM DBO.BACKUP_DBLIST)) + INSERT INTO OPENROWSET(''SQLNCLI'','''+IP+','+PORT+''';'''+ACCOUNT+''';'''+PWD+''','+DBNAME+'.DBO.PRIMITIVELOG)(APPCODE,IP,PORT,TYPE,VALUE) + SELECT '''+@APPCODE+''','''+@IP+''','+@PORT+',''MIRRORING_STATUS'',1 + + ----MIRRORING_DEPLOY + IF EXISTS(SELECT 1 + FROM master.sys.DATABASES A LEFT JOIN SYS.DATABASE_MIRRORING B + ON A.DATABASE_ID = B.DATABASE_ID + WHERE A.DATABASE_ID > 4 + AND A.IS_READ_ONLY = 0 + AND A.IS_DISTRIBUTOR = 0 + AND A.STATE = 0 + AND B.MIRRORING_STATE IS NULL + AND A.recovery_model=1 + AND A.name not in(''monitor'') + AND A.name not in(select name from monitor.dbo.MIRRORING_FILTER)) + AND NOT EXISTS(select 1 from master.SYS.DATABASE_MIRRORING where mirroring_role=2 ) + INSERT INTO OPENROWSET(''SQLNCLI'','''+IP+','+PORT+''';'''+ACCOUNT+''';'''+PWD+''','+DBNAME+'.DBO.PRIMITIVELOG)(APPCODE,IP,PORT,TYPE,VALUE) + SELECT '''+@APPCODE+''','''+@IP+''','+@PORT+',''MIRRORING_DEPLOY'',1 + + --SNAPSHOT_DEPLOY + IF EXISTS(SELECT 1 + FROM SYS.DATABASE_MIRRORING A LEFT JOIN SYS.DATABASES B + ON DB_NAME(A.DATABASE_ID)+''_DR'' = B.NAME + AND B.IS_READ_ONLY = 1 + WHERE A.MIRRORING_STATE = 4 + AND A.MIRRORING_ROLE = 2 + AND (B.NAME IS NULL + OR B.STATE = 4)) + INSERT INTO OPENROWSET(''SQLNCLI'','''+IP+','+PORT+''';'''+ACCOUNT+''';'''+PWD+''','+DBNAME+'.DBO.PRIMITIVELOG)(APPCODE,IP,PORT,TYPE,VALUE) + SELECT '''+@APPCODE+''','''+@IP+''','+@PORT+',''SNAPSHOT_DEPLOY'',1 + + + --LOGFILE_SIZE_GB + IF EXISTS(SELECT 1 + FROM SYS.MASTER_FILES A,MONITOR.DBO.BACKUP_DBLIST B,DBO.MONITOR_FILTER_SETTING C + WHERE C.NAME = ''LOGFILE_SIZE_GB'' + AND A.DATABASE_ID = B.DATABASE_ID + AND A.TYPE = 1 + AND SIZE > C.VALUE*1024*1024/8) + INSERT INTO OPENROWSET(''SQLNCLI'','''+IP+','+PORT+''';'''+ACCOUNT+''';'''+PWD+''','+DBNAME+'.DBO.PRIMITIVELOG)(APPCODE,IP,PORT,TYPE,VALUE) + SELECT '''+@APPCODE+''','''+@IP+''','+@PORT+',''LOGFILE_SIZE_GB'',1 + + --FULL_BACKUP_FAIL + IF EXISTS(SELECT 1 + FROM DBO.BACKUP_TRACE A,DBO.MONITOR_FILTER_SETTING B + WHERE A.TYPE = 1 + AND SUCCESS = 0 + AND B.NAME = ''FULL_BACKUP_FAIL'' + AND A.WRITETIME > DATEADD(MI,-1,GETDATE())) + INSERT INTO OPENROWSET(''SQLNCLI'','''+IP+','+PORT+''';'''+ACCOUNT+''';'''+PWD+''','+DBNAME+'.DBO.PRIMITIVELOG)(APPCODE,IP,PORT,TYPE,VALUE) + SELECT '''+@APPCODE+''','''+@IP+''','+@PORT+',''FULL_BACKUP_FAIL'',1 + + --LOG_BACKUP_FAIL + IF EXISTS(SELECT 1 + FROM DBO.BACKUP_TRACE A,DBO.MONITOR_FILTER_SETTING B + WHERE A.TYPE = 2 + AND SUCCESS = 0 + AND B.NAME = ''LOG_BACKUP_FAIL'' + AND A.WRITETIME > DATEADD(MI,-1,GETDATE())) + INSERT INTO OPENROWSET(''SQLNCLI'','''+IP+','+PORT+''';'''+ACCOUNT+''';'''+PWD+''','+DBNAME+'.DBO.PRIMITIVELOG)(APPCODE,IP,PORT,TYPE,VALUE) + SELECT '''+@APPCODE+''','''+@IP+''','+@PORT+',''LOG_BACKUP_FAIL'',1 + + --LOGMAN_STATUS + IF NOT EXISTS(SELECT 1 + FROM DBO.PERFORMANCESLOG + WHERE CATEGORYNAME = ''Processor'' + AND COUNTERNAME = ''% Processor Time'' + AND INSTANCENAME = ''_Total'' + AND WRITETIME > DATEADD(MI,-1,GETDATE())) + AND @@SERVICENAME IN(''MSSQLSERVER'',''S1'') + INSERT INTO OPENROWSET(''SQLNCLI'','''+IP+','+PORT+''';'''+ACCOUNT+''';'''+PWD+''','+DBNAME+'.DBO.PRIMITIVELOG)(APPCODE,IP,PORT,TYPE,VALUE) + SELECT '''+@APPCODE+''','''+@IP+''','+@PORT+',''LOGMAN_STATUS'',1 + + --JOB_FAIL + IF EXISTS(SELECT 1 + FROM MSDB.DBO.SYSJOBHISTORY A,MSDB.DBO.SYSJOBS B + WHERE A.JOB_ID = B.JOB_ID + AND A.RUN_DATE = CONVERT(CHAR(8),GETDATE(),112) + AND RIGHT(''000000''+LTRIM(A.RUN_TIME),6) >= LEFT(REPLACE(CONVERT(CHAR(30),DATEADD(MI,-5,GETDATE()),114),'':'',''''),LEN(REPLACE(CONVERT(CHAR(30),DATEADD(MI,-5,GETDATE()),114),'':'',''''))-3) + AND A.RUN_STATUS = 0) AND NOT EXISTS(select 1 from master.sys.database_mirroring where mirroring_guid is not null and mirroring_role=2) + INSERT INTO OPENROWSET(''SQLNCLI'','''+IP+','+PORT+''';'''+ACCOUNT+''';'''+PWD+''','+DBNAME+'.DBO.PRIMITIVELOG)(APPCODE,IP,PORT,TYPE,VALUE) + SELECT '''+@APPCODE+''','''+@IP+''','+@PORT+',''JOB_FAIL'',1' + FROM DBO.MONITOR_SERVER_SETTING + WHERE [STATE] = 1 + --PRINT(@SQL) + EXEC(@SQL) + +END +GO + +USE [Monitor] +GO + +IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[JOB_UPDATESTATS]') AND type in (N'P')) +DROP PROCEDURE [dbo].[JOB_UPDATESTATS] +GO + +SET ANSI_NULLS ON +GO + +SET QUOTED_IDENTIFIER ON +GO + + +CREATE PROCEDURE [dbo].[JOB_UPDATESTATS] +AS +BEGIN + + SET NOCOUNT ON + DECLARE @SQL VARCHAR(MAX) + SELECT @SQL = ISNULL(@SQL+'','')+'EXEC ['+name+'].dbo.SP_UPDATESTATS;' + FROM MASTER.SYS.DATABASES + WHERE DATABASE_ID > 4 + AND STATE = 0 + AND IS_READ_ONLY = 0 + AND IS_DISTRIBUTOR = 0 + AND recovery_model=1 + AND NAME <> 'MONITOR' + EXEC(@SQL) + +END +GO + +USE [Monitor] +GO +IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[JOB_SNAPSHOT_DAY]') AND type in (N'P', N'PC')) +DROP PROCEDURE [dbo].[JOB_SNAPSHOT_DAY] +GO + +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE PROCEDURE [dbo].[JOB_SNAPSHOT_DAY] +AS +BEGIN + + SET NOCOUNT ON + DECLARE @PORT VARCHAR(10) + EXEC MONITOR.DBO.TOOL_GET_IPPORT NULL,@PORT OUTPUT + + DECLARE @D1 varchar(10),@D2 varchar(10) + SET @D1=CONVERT(varchar(10),getdate(),112) + SET @D2=CONVERT(varchar(10),getdate()-3,112) + + --删除dr库 + DECLARE @DELETEDR VARCHAR(MAX) + SELECT @DELETEDR =ISNULL(@DELETEDR+'','')+'DROP DATABASE '+NAME+';' + FROM SYS.DATABASES + WHERE (name like '%_'+@D2 or name like '%_'+@D1) + AND snapshot_isolation_state=1 + --PRINT(@DELETEDR) + EXEC(@DELETEDR) + + IF OBJECT_ID('TEMPDB.DBO.#SNAPSHOTDB','U') IS NOT NULL + DROP TABLE #SNAPSHOTDB + + SELECT A.NAME AS MIRROR_DBNAME,A.NAME+'_'+@D1 AS SNAPSHOT_DBNAME + INTO #SNAPSHOTDB + FROM SYS.DATABASES A,SYS.DATABASE_MIRRORING B + WHERE A.DATABASE_ID > 4 + AND A.DATABASE_ID = B.DATABASE_ID + AND A.STATE = 1 + AND A.IS_READ_ONLY = 0 + AND B.MIRRORING_STATE IS NOT NULL + AND A.snapshot_isolation_state=0 + + --删除遗留的快照文件 + DECLARE @DELETEDRFILES VARCHAR(MAX) + SELECT @DELETEDRFILES = ISNULL(@DELETEDRFILES+'','')+'EXEC MASTER.DBO.xp_cmdshell ''del /q d:\gamedb\'+SNAPSHOT_DBNAME+'.'+@PORT+'.*.spst'';' + FROM #SNAPSHOTDB + --PRINT(@DELETEDRFILES) + EXEC(@DELETEDRFILES) + + --生成快照(镜像状态正常) + DECLARE @SQL VARCHAR(MAX) + + SELECT @SQL =ISNULL(@SQL+'','')+' + DECLARE @SQL_'+UPPER(A.NAME)+' VARCHAR(MAX) + SELECT @SQL_'+UPPER(A.NAME)+' = ISNULL(@SQL_'+UPPER(A.NAME)+'+'','','''')+''(NAME=''''''+B.NAME+'''''',FILENAME = ''''D:\GAMEDB\'+C.SNAPSHOT_DBNAME+'.'+LTRIM(@PORT)+'.''+LTRIM(B.FILE_ID)+''.spst'''')'' + FROM SYS.DATABASES A,SYS.MASTER_FILES B + WHERE A.DATABASE_ID = B.DATABASE_ID + AND A.NAME = '''+A.NAME+''' + AND B.TYPE = 0 + SET @SQL_'+UPPER(A.NAME)+' = ''CREATE DATABASE '+C.SNAPSHOT_DBNAME+' ON ''+@SQL_'+UPPER(A.NAME)+'+'' AS SNAPSHOT OF '+A.NAME+'''; + EXEC(@SQL_'+UPPER(A.NAME)+');' + FROM SYS.DATABASES A,SYS.DATABASE_MIRRORING B,#SNAPSHOTDB C + WHERE A.DATABASE_ID > 4 + AND A.DATABASE_ID = B.DATABASE_ID + AND A.NAME = C.MIRROR_DBNAME + AND A.STATE = 1 + AND A.IS_READ_ONLY = 0 + AND B.MIRRORING_STATE IN (4,6) + --PRINT(@SQL) + EXEC(@SQL) +END +GO +--***************************************** INIT DATA *********************************** +DECLARE @PORT VARCHAR(100) +EXEC DBO.TOOL_GET_IPPORT NULL,@PORT OUTPUT + +IF NOT EXISTS(SELECT 1 FROM DBO.BACKUP_SETTING) + INSERT INTO DBO.BACKUP_SETTING(APP,FULL_BACKUP_PATH,LOG_BACKUP_PATH,KEEP_FULL_BACKUP_DAYS,KEEP_LOG_BACKUP_DAYS,FULL_BACKUP_MIN_SIZE_MB,LOG_BACKUP_MIN_SIZE_MB,UPLOAD,MD5) VALUES('sqlserver','D:\dbbak\full\','D:\dbbak\log\',2,2,40960,30720,1,1) + +TRUNCATE TABLE DBO.MONITOR_COUNTERPATH +INSERT INTO DBO.MONITOR_COUNTERPATH(TYPE,COUNTERPATH) +SELECT 0,'"\Processor(_Total)\% Processor Time"' UNION ALL +SELECT 0,'"\Memory\Available MBytes"' UNION ALL +SELECT 0,'"\LogicalDisk(C:)\Free Megabytes"' UNION ALL +SELECT 0,'"\LogicalDisk(D:)\Free Megabytes"' UNION ALL +SELECT 0,'"\LogicalDisk(E:)\Free Megabytes"' UNION ALL +SELECT 0,'"\LogicalDisk(D:)\% Idle Time"' UNION ALL +SELECT 0,'"\LogicalDisk(D:)\% Disk Time"' UNION ALL +SELECT 0,'"\LogicalDisk(D:)\Avg. Disk sec/Read"' UNION ALL +SELECT 0,'"\LogicalDisk(D:)\Avg. Disk sec/Write"' UNION ALL +SELECT 0,'"\LogicalDisk(D:)\Avg. Disk Bytes/Read"' UNION ALL +SELECT 0,'"\LogicalDisk(D:)\Avg. Disk Bytes/Write"' UNION ALL +SELECT 0,'"\LogicalDisk(D:)\Avg. Disk Queue Length"' UNION ALL + +--COUNTER最长两级,第三级移动至第一级,并加入(),譬如"\LogicalDisk\% Idle Time\1 D:"应该更改为"\LogicalDisk(1 D:)\% Idle Time" +SELECT 1,'"\:DataBases(_Total)\Data File(s) Size (KB)"' UNION ALL +SELECT 1,'"\:DataBases(_Total)\Log File(s) Size (KB)"' UNION ALL +SELECT 1,'"\:Databases(_Total)\Transactions/sec"' UNION ALL --TPS +SELECT 1,'"\:General Statistics\User Connections"' UNION ALL +SELECT 1,'"\:Access Methods\Full Scans/sec"' UNION ALL --全表扫描每秒 +SELECT 1,'"\:Buffer Manager\Buffer cache hit ratio"' UNION ALL --缓存命中率 +SELECT 1,'"\:Memory Manager\Total Server Memory (KB)"' UNION ALL +SELECT 1,'"\:Latches\Latch Waits/sec"' UNION ALL +SELECT 1,'"\:Locks(_Total)\Lock Requests/sec"' UNION ALL +SELECT 1,'"\:Plan Cache(_Total)\Cache Hit Ratio"' UNION ALL +SELECT 1,'"\:SQL Errors(User Errors)\Errors/sec"' UNION ALL +SELECT 1,'"\:SQL Statistics\Batch Requests/sec"' UNION ALL --QPS +SELECT 1,'"\:SQL Statistics\SQL Compilations/sec"' UNION ALL +SELECT 1,'"\:SQL Statistics\SQL Re-Compilations/sec"' UNION ALL +SELECT 1,'"\:Wait Statistics(Average wait time (ms))\Lock waits"' UNION ALL +SELECT 1,'"\:Wait Statistics(Average wait time (ms))\Network IO waits"' UNION ALL +SELECT 1,'"\:Wait Statistics(Average wait time (ms))\Page IO latch waits"' UNION ALL +SELECT 1,'"\:Workload Group Stats(default)\Requests completed/sec"' + +TRUNCATE TABLE DBO.BACKUP_FILTER +INSERT INTO DBO.BACKUP_FILTER(NAME) VALUES('Monitor') + +TRUNCATE TABLE DBO.TRACE_SETTING +INSERT INTO DBO.TRACE_SETTING(NAME,VALUE) +SELECT 'FILTER_DURATION',1 UNION ALL --筛选执行时间大于等于?秒 +SELECT 'KEEP_DATA_DAYS',60 --跟踪的数据保留多少天(数据量可能会比较大,虐心SQL) + + + +TRUNCATE TABLE DBO.COUNTER_SETTING +INSERT INTO DBO.COUNTER_SETTING(NAME,VALUE) +SELECT 'KEEP_DATA_DAYS',60 --性能数据保留多少天 + +--性能数据筛选器 +TRUNCATE TABLE DBO.MONITOR_FILTER_SETTING +INSERT INTO DBO.MONITOR_FILTER_SETTING(NAME,VALUE) +SELECT 'DISK_C_FREE_MB', 10240 UNION ALL +SELECT 'DISK_D_FREE_MB', 40960 UNION ALL +SELECT 'DISK_E_FREE_MB', 10240 UNION ALL +SELECT 'CPU_USE_PERCENT', 60 UNION ALL +SELECT 'IO_IDLE_PERCENT', 50 UNION ALL +SELECT 'MEMORY_FREE_MB', 512 UNION ALL +SELECT 'MIRRORING_LOG_SEND_QUEUE_KB',1048576 UNION ALL +SELECT 'LOGFILE_SIZE_GB', 40 UNION ALL +SELECT 'USER_CONNECTION_NUMBER',10000 UNION ALL +SELECT 'SLOW_QUERY_IN_5MI',5 UNION ALL +SELECT 'FULL_BACKUP_FAIL',1 UNION ALL +SELECT 'LOG_BACKUP_FAIL',1 UNION ALL +SELECT 'LOGMAN_STATUS',1 + +TRUNCATE TABLE DBO.MONITOR_SERVICE +INSERT INTO DBO.MONITOR_SERVICE(NAME,MONITOR_SERVICE_NAME,PORT) +SELECT @@SERVICENAME,CASE WHEN @@SERVICENAME = 'MSSQLSERVER' THEN 'SQLSERVER' ELSE 'MSSQL$'+@@SERVICENAME END,@PORT +GO + +delete from MONITOR.DBO.APP_SETTING +insert into MONITOR.DBO.APP_SETTING values('blackdesert') +insert into MONITOR.DBO.APP_SETTING values('hssmpc') +GO +--****************************************** JOB **************************************** +DECLARE @SQL VARCHAR(8000) +SELECT @SQL = ISNULL(@SQL+' +','')+'EXEC MSDB.DBO.SP_DELETE_JOB @JOB_NAME='''+NAME+''',@DELETE_UNUSED_SCHEDULE=1' +FROM MSDB.DBO.SYSJOBS +WHERE NAME IN('[dbo]-backup-day','[dbo]-backup-time','snapshot','Sys_CheckPorcess','PRIVATE_QQHX_SNAPSHOT_ONE','snapshot_qqhx','PUBLIC_SNAPSHOT','slow_query_catch') + OR NAME LIKE 'JOB_BUILDXML%' + OR NAME LIKE 'REPLCHECK%' + OR NAME LIKE 'TC%' +--PRINT(@SQL) +EXEC(@SQL) +GO + + + +--如果存在镜像db,那么创建TC_SNAPSHOT +USE MASTER +GO +IF EXISTS(SELECT 1 FROM SYS.DATABASE_MIRRORING WHERE MIRRORING_STATE IS NOT NULL AND MIRRORING_ROLE = 2) + EXEC MONITOR.DBO.TOOL_DEPLOY_SNAPSHOT 'TC_SNAPSHOT',0 +GO + +--如果存在复制,那么执行DBO.TOOL_DEPLOY_REPL_MONITOR +IF EXISTS(SELECT 1 FROM SYS.DATABASES WHERE STATE = 0 AND IS_DISTRIBUTOR = 0 AND IS_PUBLISHED = 1) + EXEC MONITOR.DBO.TOOL_DEPLOY_REPL_MONITOR +GO +USE MSDB +GO + +DECLARE @jobId BINARY(16) + +DECLARE @JOBNAME VARCHAR(2000),@SERVERNAME VARCHAR(2000) +DECLARE @STEPNAME VARCHAR(2000),@DBNAME VARCHAR(2000) +DECLARE @SCHEDULENAME VARCHAR(2000),@CMD VARCHAR(2000) + +SELECT @JOBNAME='TC_REPORT_LOAD', + @STEPNAME='step_1',@DBNAME='master', + @SCHEDULENAME='schedule_1',@CMD='EXEC MONITOR.DBO.JOB_REPORT_LOAD', + @SERVERNAME=CAST(SERVERPROPERTY('SERVERNAME') AS SYSNAME) + +IF EXISTS(SELECT 1 FROM dbo.sysjobs WHERE NAME=@JOBNAME) +BEGIN + EXEC msdb.dbo.sp_delete_job @job_name=@JOBNAME,@delete_unused_schedule=1 +END +EXEC msdb.dbo.sp_add_job @job_name=@JOBNAME, + @enabled=1, + @notify_level_eventlog=0, + @notify_level_email=2, + @notify_level_netsend=2, + @notify_level_page=2, + @delete_level=0, + @category_name=N'[Uncategorized (Local)]', + @owner_login_name='sa',@job_id = @jobId OUTPUT + + +EXEC msdb.dbo.sp_add_jobserver @job_name=@JOBNAME,@server_name = @SERVERNAME + +USE [msdb] + +EXEC msdb.dbo.sp_add_jobstep @job_name=@JOBNAME,@step_name=@STEPNAME, + @step_id=1, + @cmdexec_success_code=0, + @on_success_action=1, + @on_fail_action=2, + @retry_attempts=0, + @retry_interval=0, + @os_run_priority=0,@subsystem=N'TSQL', + @command=@CMD, + @database_name=@DBNAME, + @flags=0 + +USE [msdb] + +EXEC msdb.dbo.sp_update_job @job_name=@JOBNAME, + @enabled=1, + @start_step_id=1, + @notify_level_eventlog=0, + @notify_level_email=2, + @notify_level_netsend=2, + @notify_level_page=2, + @delete_level=0, + @description=N'', + @category_name=N'[Uncategorized (Local)]', + @owner_login_name='sa', + @notify_email_operator_name=N'', + @notify_netsend_operator_name=N'', + @notify_page_operator_name=N'' + +USE [msdb] + +DECLARE @schedule_id int +EXEC msdb.dbo.sp_add_jobschedule @job_name=@JOBNAME,@name=@SCHEDULENAME, + @enabled=1, + @freq_type=4, + @freq_interval=1, + @freq_subday_type=4, + @freq_subday_interval=1,--5分钟一次 + @freq_relative_interval=0, + @freq_recurrence_factor=1, + @active_start_date=20130723, + @active_end_date=99991231, + @active_start_time=0, + @active_end_time=235959,@schedule_id = @schedule_id OUTPUT +SELECT @jobId AS JOBID,@schedule_id AS SCHEDULE_ID + +GO + +DECLARE @jobId BINARY(16) + +DECLARE @JOBNAME VARCHAR(2000),@SERVERNAME VARCHAR(2000) +DECLARE @STEPNAME VARCHAR(2000),@DBNAME VARCHAR(2000) +DECLARE @SCHEDULENAME VARCHAR(2000),@CMD VARCHAR(2000) + +SELECT @JOBNAME='TC_TRACE', + @STEPNAME='step_1',@DBNAME='MASTER', + @SCHEDULENAME='schedule_1',@CMD='EXEC MONITOR.DBO.JOB_TRACE 1', + @SERVERNAME=CAST(SERVERPROPERTY('SERVERNAME') AS SYSNAME) + +IF EXISTS(SELECT 1 FROM MSDB.DBO.SYSJOBS WHERE NAME=@JOBNAME) +BEGIN + EXEC msdb.dbo.sp_delete_job @job_name=@JOBNAME,@delete_unused_schedule=1 +END +EXEC msdb.dbo.sp_add_job @job_name=@JOBNAME, + @enabled=1, + @notify_level_eventlog=0, + @notify_level_email=2, + @notify_level_netsend=2, + @notify_level_page=2, + @delete_level=0, + @category_name=N'[Uncategorized (Local)]', + @owner_login_name='sa',@job_id = @jobId OUTPUT + +EXEC msdb.dbo.sp_add_jobserver @job_name=@JOBNAME,@server_name = @SERVERNAME + +USE [msdb] + +EXEC msdb.dbo.sp_add_jobstep @job_name=@JOBNAME,@step_name=@STEPNAME, + @step_id=1, + @cmdexec_success_code=0, + @on_success_action=1, + @on_fail_action=2, + @retry_attempts=0, + @retry_interval=0, + @os_run_priority=0,@subsystem=N'TSQL', + @command=@CMD, + @database_name=@DBNAME, + @flags=0 + +USE [msdb] + +EXEC msdb.dbo.sp_update_job @job_name=@JOBNAME, + @enabled=1, + @start_step_id=1, + @notify_level_eventlog=0, + @notify_level_email=2, + @notify_level_netsend=2, + @notify_level_page=2, + @delete_level=0, + @description=N'', + @category_name=N'[Uncategorized (Local)]', + @owner_login_name='sa', + @notify_email_operator_name=N'', + @notify_netsend_operator_name=N'', + @notify_page_operator_name=N'' + +USE [msdb] + +DECLARE @schedule_id int +EXEC msdb.dbo.sp_add_jobschedule @job_name=@JOBNAME,@name=@SCHEDULENAME, + @enabled=1, + @freq_type=4, + @freq_interval=1, + @freq_subday_type=4, + @freq_subday_interval=5, + @freq_relative_interval=0, + @freq_recurrence_factor=0, + @active_start_date=20130723, + @active_end_date=99991231, + @active_start_time=0, + @active_end_time=235959,@schedule_id = @schedule_id OUTPUT +SELECT @jobId AS JOBID,@schedule_id AS SCHEDULE_ID + +GO + +DECLARE @jobId BINARY(16) +IF EXISTS(SELECT 1 FROM MSDB.DBO.SYSJOBS WHERE NAME=N'TC_BACKUP_FULL') +BEGIN + EXEC msdb.dbo.sp_delete_job @job_name=N'TC_BACKUP_FULL',@delete_unused_schedule=1 +END +EXEC msdb.dbo.sp_add_job @job_name=N'TC_BACKUP_FULL', + @enabled=1, + @notify_level_eventlog=0, + @notify_level_email=0, + @notify_level_netsend=0, + @notify_level_page=0, + @delete_level=0, + @description=N'No description available.', + @category_name=N'[Uncategorized (Local)]', + @owner_login_name=N'sa',@job_id = @jobId OUTPUT + +DECLARE @ON_SUCCESS_ACTION INT = 1,@ON_FAIL_ACTION INT = 2 + +EXEC msdb.dbo.sp_add_jobstep @job_id=@jobId,@step_name=N'TC_BACKUP_FULL_1', + @step_id=1, + @cmdexec_success_code=0, + @on_success_action=@ON_SUCCESS_ACTION, + @on_success_step_id=0, + @on_fail_action=@ON_FAIL_ACTION, + @on_fail_step_id=0, + @retry_attempts=0, + @retry_interval=0, + @os_run_priority=0,@subsystem=N'TSQL', + @command=N'EXEC MONITOR.DBO.TOOL_BACKUP_DATABASE 1', + @database_name=N'master', + @flags=0 + +EXEC msdb.dbo.sp_update_job @job_id = @jobId,@start_step_id = 1 + +EXEC msdb.dbo.sp_add_jobschedule @job_id=@jobId,@name=N'TC_BACKUP_FULL_1', + @enabled=1, + @freq_type=4, + @freq_interval=1, + @freq_subday_type=1, + @freq_subday_interval=26, + @freq_relative_interval=0, + @freq_recurrence_factor=0, + @active_start_date=20071220, + @active_end_date=99991231, + @active_start_time=32600, + @active_end_time=235959 +EXEC msdb.dbo.sp_add_jobserver @job_id = @jobId,@server_name = N'(local)' +SELECT @jobId AS JOBID +GO + + +DECLARE @jobId BINARY(16) +IF EXISTS(SELECT 1 FROM MSDB.DBO.SYSJOBS WHERE NAME=N'TC_BACKUP_LOG') +BEGIN + EXEC msdb.dbo.sp_delete_job @job_name=N'TC_BACKUP_LOG',@delete_unused_schedule=1 +END +EXEC msdb.dbo.sp_add_job @job_name=N'TC_BACKUP_LOG', + @enabled=1, + @notify_level_eventlog=0, + @notify_level_email=0, + @notify_level_netsend=0, + @notify_level_page=0, + @delete_level=0, + @description=N'No description available.', + @category_name=N'[Uncategorized (Local)]', + @owner_login_name=N'sa',@job_id = @jobId OUTPUT + +EXEC msdb.dbo.sp_add_jobstep @job_id=@jobId,@step_name=N'TC_BACKUP_LOG_1', + @step_id=1, + @cmdexec_success_code=0, + @on_success_action=1, + @on_success_step_id=0, + @on_fail_action=2, + @on_fail_step_id=0, + @retry_attempts=0, + @retry_interval=0, + @os_run_priority=0,@subsystem=N'TSQL', + @command=N'EXEC MONITOR.DBO.TOOL_BACKUP_DATABASE 2', + @database_name=N'master', + @flags=0 + +EXEC msdb.dbo.sp_update_job @job_id = @jobId,@start_step_id = 1 + +EXEC msdb.dbo.sp_add_jobschedule @job_id=@jobId,@name=N'TC_BACKUP_LOG_1', + @enabled=1, + @freq_type=4, + @freq_interval=1, + @freq_subday_type=4, + @freq_subday_interval=30, + @freq_relative_interval=0, + @freq_recurrence_factor=0, + @active_start_date=20101013, + @active_end_date=99991231, + @active_start_time=0, + @active_end_time=235959 +EXEC msdb.dbo.sp_add_jobserver @job_id = @jobId,@server_name = N'(local)' +SELECT @jobId AS JOBID +GO + + +DECLARE @jobId BINARY(16) +IF EXISTS(SELECT 1 FROM MSDB.DBO.SYSJOBS WHERE NAME=N'TC_MONITOR_FILTER') +BEGIN + EXEC msdb.dbo.sp_delete_job @job_name=N'TC_MONITOR_FILTER',@delete_unused_schedule=1 +END +EXEC msdb.dbo.sp_add_job @job_name=N'TC_MONITOR_FILTER', + @enabled=1, + @notify_level_eventlog=0, + @notify_level_email=0, + @notify_level_netsend=0, + @notify_level_page=0, + @delete_level=0, + @description=N'No description available.', + @category_name=N'[Uncategorized (Local)]', + @owner_login_name=N'sa',@job_id = @jobId OUTPUT + +EXEC msdb.dbo.sp_add_jobstep @job_id=@jobId,@step_name=N'TC_MONITOR_FILTER_1', + @step_id=1, + @cmdexec_success_code=0, + @on_success_action=1, + @on_success_step_id=0, + @on_fail_action=2, + @on_fail_step_id=0, + @retry_attempts=0, + @retry_interval=0, + @os_run_priority=0,@subsystem=N'TSQL', + @command=N'EXEC DBO.JOB_MONITOR_FILTER', + @database_name=N'MONITOR', + @flags=0 + +EXEC msdb.dbo.sp_update_job @job_id = @jobId,@start_step_id = 1 + +EXEC msdb.dbo.sp_add_jobschedule @job_id=@jobId,@name=N'TC_MONITOR_FILTER_1', + @enabled=1, + @freq_type=4, + @freq_interval=1, + @freq_subday_type=4, + @freq_subday_interval=1, + @freq_relative_interval=0, + @freq_recurrence_factor=0, + @active_start_date=20130821, + @active_end_date=99991231, + @active_start_time=0, + @active_end_time=235959 + +EXEC msdb.dbo.sp_add_jobserver @job_id = @jobId,@server_name = N'(local)' +SELECT @jobId AS JOBID +GO + +USE [msdb] +GO + +IF EXISTS (SELECT job_id FROM msdb.dbo.sysjobs_view WHERE name = N'TC_SNAPSHOT_DAY') +EXEC msdb.dbo.sp_delete_job @job_name=N'TC_SNAPSHOT_DAY', @delete_unused_schedule=1 +GO + +USE [msdb] +GO + +/****** Object: Job [TC_SNAPSHOT_DAY] Script Date: 11/02/2021 15:21:45 ******/ +BEGIN TRANSACTION +DECLARE @ReturnCode INT +SELECT @ReturnCode = 0 +/****** Object: JobCategory [[Uncategorized (Local)]]] Script Date: 11/02/2021 15:21:45 ******/ +IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'[Uncategorized (Local)]' AND category_class=1) +BEGIN +EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'[Uncategorized (Local)]' +IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback + +END + +DECLARE @jobId BINARY(16) +EXEC @ReturnCode = msdb.dbo.sp_add_job @job_name=N'TC_SNAPSHOT_DAY', + @enabled=0, + @notify_level_eventlog=0, + @notify_level_email=0, + @notify_level_netsend=0, + @notify_level_page=0, + @delete_level=0, + @description=N'No description available.', + @category_name=N'[Uncategorized (Local)]', + @owner_login_name=N'sa', @job_id = @jobId OUTPUT +IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback +/****** Object: Step [TC_SNAPSHOT_1] Script Date: 11/02/2021 15:21:45 ******/ +EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'TC_SNAPSHOT_1', + @step_id=1, + @cmdexec_success_code=0, + @on_success_action=1, + @on_success_step_id=0, + @on_fail_action=2, + @on_fail_step_id=0, + @retry_attempts=0, + @retry_interval=0, + @os_run_priority=0, @subsystem=N'TSQL', + @command=N'EXEC MONITOR.DBO.JOB_SNAPSHOT_DAY', + @database_name=N'MASTER', + @flags=0 +IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback +EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1 +IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback +EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N'TC_SNAPSHOT_DAY', + @enabled=1, + @freq_type=4, + @freq_interval=1, + @freq_subday_type=1, + @freq_subday_interval=0, + @freq_relative_interval=0, + @freq_recurrence_factor=0, + @active_start_date=20130723, + @active_end_date=99991231, + @active_start_time=0, + @active_end_time=235959 +IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback +EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)' +IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback +COMMIT TRANSACTION +GOTO EndSave +QuitWithRollback: + IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION +EndSave: + +GO + + +USE [msdb] +GO + +IF EXISTS (SELECT job_id FROM msdb.dbo.sysjobs_view WHERE name = N'TC_UPDATESTATS') +EXEC msdb.dbo.sp_delete_job @job_name=N'TC_UPDATESTATS', @delete_unused_schedule=1 +GO + +BEGIN TRANSACTION +DECLARE @ReturnCode INT +SELECT @ReturnCode = 0 +/****** Object: JobCategory [[Uncategorized (Local)]] Script Date: 2021/11/9 23:25:07 ******/ +IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'[Uncategorized (Local)]' AND category_class=1) +BEGIN +EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'[Uncategorized (Local)]' +IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback + +END + +DECLARE @jobId BINARY(16) +EXEC @ReturnCode = msdb.dbo.sp_add_job @job_name=N'TC_UPDATESTATS', + @enabled=0, + @notify_level_eventlog=0, + @notify_level_email=0, + @notify_level_netsend=0, + @notify_level_page=0, + @delete_level=0, + @description=N'No description available.', + @category_name=N'[Uncategorized (Local)]', + @owner_login_name=N'sa', @job_id = @jobId OUTPUT +IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback +/****** Object: Step [TC_UPDATESTATS_1] Script Date: 2021/11/9 23:25:07 ******/ +EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'TC_UPDATESTATS_1', + @step_id=1, + @cmdexec_success_code=0, + @on_success_action=1, + @on_success_step_id=0, + @on_fail_action=2, + @on_fail_step_id=0, + @retry_attempts=0, + @retry_interval=0, + @os_run_priority=0, @subsystem=N'TSQL', + @command=N'EXEC MONITOR.DBO.JOB_UPDATESTATS +', + @database_name=N'master', + @flags=0 +IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback +EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1 +IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback +EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N'TC_UPDATESTATS_1', + @enabled=1, + @freq_type=4, + @freq_interval=1, + @freq_subday_type=1, + @freq_subday_interval=0, + @freq_relative_interval=0, + @freq_recurrence_factor=0, + @active_start_date=20211018, + @active_end_date=99991231, + @active_start_time=10000, + @active_end_time=235959 +IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback +EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N'TC_UPDATESTATS_7', + @enabled=1, + @freq_type=4, + @freq_interval=1, + @freq_subday_type=1, + @freq_subday_interval=0, + @freq_relative_interval=0, + @freq_recurrence_factor=0, + @active_start_date=20211018, + @active_end_date=99991231, + @active_start_time=70000, + @active_end_time=235959 +IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback +EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)' +IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback +COMMIT TRANSACTION +GOTO EndSave +QuitWithRollback: + IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION +EndSave: + +GO diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/02_backup.sql b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/02_backup.sql new file mode 100644 index 0000000000..b3cab6c985 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/02_backup.sql @@ -0,0 +1,524 @@ +USE Monitor +SET QUOTED_IDENTIFIER ON +SET NOCOUNT ON +GO +IF OBJECT_ID('DBO.TOOL_BACKUP_DATABASE','P') IS NOT NULL + DROP PROC DBO.TOOL_BACKUP_DATABASE +GO +IF OBJECT_ID('DBO.TOOL_BACKUP_DATABASE_OPERATOR','P') IS NOT NULL + DROP PROC DBO.TOOL_BACKUP_DATABASE_OPERATOR +GO +IF OBJECT_ID('DBO.TOOL_CHECK_DISK_FREE_SIZE','P') IS NOT NULL + DROP PROC DBO.TOOL_CHECK_DISK_FREE_SIZE +GO +IF OBJECT_ID('DBO.sp_dbo_do_log_backup','P') IS NOT NULL + DROP PROC DBO.sp_dbo_do_log_backup +GO +IF OBJECT_ID('DBO.sp_dbo_do_diff_backup','P') IS NOT NULL + DROP PROC DBO.sp_dbo_do_diff_backup +GO +IF OBJECT_ID('DBO.sp_dbo_dbbackup','P') IS NOT NULL + DROP PROC DBO.sp_dbo_dbbackup +GO + +IF OBJECT_ID('DBO.TOOL_BACKUP_XML','P') IS NOT NULL + DROP PROC DBO.TOOL_BACKUP_XML +GO + +IF OBJECT_ID('DBO.TOOL_BACKUP_XML_LOG_DAILY','P') IS NOT NULL + DROP PROC DBO.TOOL_BACKUP_XML_LOG_DAILY +GO + +CREATE PROCEDURE DBO.TOOL_BACKUP_XML +@FILENAME VARCHAR(1000), +@IP VARCHAR(100), +@PORT VARCHAR(100) +AS +BEGIN + DECLARE @CMD VARCHAR(8000), + @XML VARCHAR(8000), + + @APP VARCHAR(100), + @TYPE INT, + @DBNAME VARCHAR(1000), + @PATH VARCHAR(1000), + @STARTTIME VARCHAR(100), + @ENDTIME VARCHAR(100), + + @FILESIZE BIGINT = 0, + @MD5CODE VARCHAR(100) = 'nocheck', + @INSTANCE_DBNAME_LIST VARCHAR(8000) + + SELECT @TYPE = TYPE,@DBNAME = DBNAME,@PATH = PATH,@STARTTIME = CONVERT(CHAR(19),STARTTIME,120),@ENDTIME = CONVERT(CHAR(19),ENDTIME,120) + FROM MONITOR.DBO.BACKUP_TRACE + WHERE FILENAME = @FILENAME + + SELECT @APP = APP FROM MONITOR.DBO.BACKUP_SETTING + SELECT @INSTANCE_DBNAME_LIST = ISNULL(@INSTANCE_DBNAME_LIST+',','')+NAME FROM MONITOR.DBO.BACKUP_DBLIST + + --get filesize + SET @CMD = LEFT(@PATH,2)+' && CD '+@PATH+' && FOR /F %I IN (''DIR /B '+@PATH+@FILENAME+''') DO ECHO %~ZI' + TRUNCATE TABLE DBO.BACKUP_COMMON_TABLE + INSERT INTO DBO.BACKUP_COMMON_TABLE EXEC XP_CMDSHELL @CMD + DELETE DBO.BACKUP_COMMON_TABLE + WHERE BLOCK IS NULL + OR BLOCK LIKE '%ECHO%' + OR BLOCK LIKE '%recognized as an internal%' + OR BLOCK LIKE '%or batch file%' + OR BLOCK LIKE '%File Not Found%' + OR BLOCK LIKE '%The system cannot find%' + + IF EXISTS(SELECT 1 FROM DBO.BACKUP_COMMON_TABLE) + SELECT @FILESIZE = BLOCK FROM DBO.BACKUP_COMMON_TABLE + + --get md5 + SET @CMD = 'CERTUTIL -HASHFILE '+@PATH+@FILENAME+' MD5' + TRUNCATE TABLE DBO.BACKUP_COMMON_TABLE + INSERT INTO DBO.BACKUP_COMMON_TABLE EXEC XP_CMDSHELL @CMD + DELETE DBO.BACKUP_COMMON_TABLE WHERE BLOCK LIKE 'MD5 HASH%' OR BLOCK LIKE 'CERTUTIL:%' OR BLOCK IS NULL + IF EXISTS(SELECT 1 FROM .DBO.BACKUP_COMMON_TABLE) + SELECT @MD5CODE = REPLACE(BLOCK,' ','') FROM DBO.BACKUP_COMMON_TABLE + + --build pub file + SET @CMD = 'echo NAME='+@PATH+@FILENAME+'> D:\IEOD_FILE_BACKUP\'+@FILENAME+'.PUB' + EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo MD5='+@MD5CODE+'>>'+'D:\IEOD_FILE_BACKUP\'+@FILENAME+'.PUB' + EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo BINDIP='+@IP+'>>'+'D:\IEOD_FILE_BACKUP\'+@FILENAME+'.PUB' + EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo TAG='+CASE WHEN @TYPE = 1 THEN 'MSSQL_FULL_BACKUP' ELSE 'INCREMENT_BACKUP' END+'>>'+'D:\IEOD_FILE_BACKUP\'+@FILENAME+'.PUB' + EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo BUNAME=dbo>>'+'D:\IEOD_FILE_BACKUP\'+@FILENAME+'.PUB' + EXEC XP_CMDSHELL @CMD + + --update history + UPDATE DBO.BACKUP_TRACE SET FILESIZE = @FILESIZE,MD5CODE = @MD5CODE,UPLOADED = 1 WHERE FILENAME = @FILENAME + + --build xml file + DECLARE @DATETIME VARCHAR(23) = CONVERT(VARCHAR(19),GETDATE(),120) + SET @XML = NULL + IF @TYPE = 1 + BEGIN + SET @XML = 'D:\dbbak\backup_report_'+@@SERVICENAME+'.'+@DBNAME+'.xml' + + SET @CMD = 'echo ^ >'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@IP+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@DATETIME+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^dbbackup_port^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@PORT+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@IP+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@DATETIME+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^dbbackup_Btime1^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@STARTTIME+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@IP+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@DATETIME+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^dbbackup_Btime2^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@ENDTIME+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@IP+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@DATETIME+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^dbbackup_BtypeID^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^256^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@IP+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@DATETIME+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^dbbackup_Bfname^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@FILENAME+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@IP+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@DATETIME+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^dbbackup_Bfsize^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+LTRIM(@FILESIZE)+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@IP+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@DATETIME+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^dbbackup_dblist^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@DBNAME+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + + --send xml + IF LEN(@XML) > 0 + BEGIN + --SET @CMD = 'cd d:\dbbak && d: && d:\perl\bin\perl.exe send_xml.pl -c '+@XML+' -t 60' + SET @CMD='cd d:\dbbak && d: && C:\cygwinroot\bin\sh.exe send_xml.sh general_log '+@XML+'' + EXEC XP_CMDSHELL @CMD + END + + --NEW XML + SET @XML = 'D:\dbbak\backup_report_'+@@SERVICENAME+'_NEWXML.'+@DBNAME+'.xml' + + SET @CMD = 'echo ^ >'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@IP+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@PORT+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@PORT+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@IP+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@ENDTIME+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@STARTTIME+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+LTRIM(@FILESIZE)+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+REPLACE(@PATH,'\','\\')+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@INSTANCE_DBNAME_LIST+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + --SET @CMD = 'echo ^NONE^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@APP+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + --SET @CMD = 'echo ^NONE^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^S^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^'+@FILENAME+'^ >>'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + + --send xml + IF LEN(@XML) > 0 + BEGIN + --SET @CMD = 'cd d:\dbbak && d: && d:\perl\bin\perl.exe send_xml.pl -c '+@XML+' -t 60' + SET @CMD='cd d:\dbbak && d: && C:\cygwinroot\bin\sh.exe send_xml.sh dbbackup_info_other '+@XML+'' + EXEC XP_CMDSHELL @CMD + END + END + +END + +GO + +CREATE PROCEDURE DBO.TOOL_BACKUP_XML_LOG_DAILY +@IP VARCHAR(100), +@PORT VARCHAR(100) +AS +BEGIN + + SET NOCOUNT ON + DECLARE @CMD VARCHAR(8000), + @XML VARCHAR(8000), + @SQL_FIRST VARCHAR(MAX), + @SQL_LAST VARCHAR(MAX) + + DECLARE @DATETIME VARCHAR(23) = GETDATE() + + SET @XML = NULL + + SET @XML = 'D:\dbbak\backup_report_'+@@SERVICENAME+'_daylog.xml' + + SET @CMD = 'echo ^ >'+@XML EXEC XP_CMDSHELL @CMD + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + + SET @SQL_FIRST = NULL + --设置addmi的原因:入库表PRIMARY KEY (`report_time`,`ip`,`port`,`name`) 限制,如果不加那么会出现重复键而入库失败. + ;WITH T_FIRST AS + ( + SELECT ROW_NUMBER()OVER(PARTITION BY A.DBNAME ORDER BY A.WRITETIME) AS INDEXNO,DB_ID(DBNAME) AS ADDMI,* + FROM MONITOR.DBO.BACKUP_TRACE A,MONITOR.DBO.BACKUP_DBLIST B + WHERE TYPE > 1 + AND STARTTIME >= CONVERT(CHAR(19),GETDATE(),112) + AND A.DBNAME = B.NAME + ) + SELECT @SQL_FIRST = ISNULL(@SQL_FIRST+CHAR(13),'')+' + SET @CMD = ''echo ^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^'+@IP+'^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^'+@PORT+'^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^'+CONVERT(VARCHAR(19),DATEADD(MI,ADDMI,@DATETIME),120)+'^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^backup_FirstBinLogName^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^'+FILENAME+'^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + + SET @CMD = ''echo ^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^'+@IP+'^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^'+@PORT+'^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^'+CONVERT(VARCHAR(19),DATEADD(MI,ADDMI,@DATETIME),120)+'^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^backup_FirstBinLogTime^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^'+FILENAME+' '+CONVERT(CHAR(19),STARTTIME,120)+'^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD' + FROM T_FIRST WHERE INDEXNO = 1 + SET @SQL_FIRST = 'DECLARE @CMD VARCHAR(8000) '+@SQL_FIRST + --PRINT(@SQL_FIRST) + EXEC(@SQL_FIRST) + + SET @SQL_LAST = NULL + ;WITH T_LAST AS + ( + SELECT ROW_NUMBER()OVER(PARTITION BY A.DBNAME ORDER BY A.WRITETIME DESC) AS INDEXNO,DB_ID(DBNAME) AS ADDMI,* + FROM MONITOR.DBO.BACKUP_TRACE A,MONITOR.DBO.BACKUP_DBLIST B + WHERE TYPE > 1 + AND STARTTIME >= CONVERT(CHAR(19),GETDATE(),112) + AND A.DBNAME = B.NAME + ) + SELECT @SQL_LAST = ISNULL(@SQL_LAST+CHAR(13),'')+' + SET @CMD = ''echo ^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^'+@IP+'^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^'+@PORT+'^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^'+CONVERT(VARCHAR(19),DATEADD(MI,ADDMI,@DATETIME),120)+'^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^backup_LastBinLogName^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^'+FILENAME+'^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + + SET @CMD = ''echo ^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^'+@IP+'^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^'+@PORT+'^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^'+CONVERT(VARCHAR(19),DATEADD(MI,ADDMI,@DATETIME),120)+'^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^backup_LastBinLogTime^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^'++FILENAME+' '+CONVERT(CHAR(19),STARTTIME,120)+'^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD + SET @CMD = ''echo ^ >>'+@XML+''' EXEC XP_CMDSHELL @CMD' + FROM T_LAST WHERE INDEXNO = 1 + SET @SQL_LAST = 'DECLARE @CMD VARCHAR(8000) '+@SQL_LAST + --PRINT(@SQL_LAST) + EXEC(@SQL_LAST) + + SET @CMD = 'echo ^ >>'+@XML EXEC XP_CMDSHELL @CMD + + --send xml + IF LEN(@XML) > 0 + BEGIN + --SET @CMD = 'cd d:\dbbak && d: && d:\perl\bin\perl.exe send_xml.pl -c '+@XML+' -t 60' + SET @CMD='cd d:\dbbak && d: && C:\cygwinroot\bin\sh.exe send_xml.sh rotate_report '+@XML+'' + PRINT @CMD + EXEC XP_CMDSHELL @CMD + END +END + +GO + +CREATE PROCEDURE DBO.TOOL_BACKUP_DATABASE_OPERATOR +@TYPE INT, +@DBNAME VARCHAR(100), +@FILENAME VARCHAR(1000) +AS +BEGIN + SET NOCOUNT ON + DECLARE @SQL VARCHAR(8000) = ' + BACKUP '+CASE WHEN @TYPE = 2 THEN 'LOG' ELSE 'DATABASE' END+' ['+@DBNAME+'] + TO DISK = '''+@FILENAME+''' + WITH INIT,STATS = 10 '+CASE WHEN @TYPE = 3 THEN ',DIFFERENTIAL' ELSE '' END+' + ' + --PRINT(@SQL) + EXEC(@SQL) + IF @@ERROR <> 0 + RETURN 0 + ELSE RETURN 1 +END +GO + +CREATE PROCEDURE DBO.TOOL_CHECK_DISK_FREE_SIZE +@BACKUP_PATH VARCHAR(1000), +@FREE_SIZE_MB INT +AS +BEGIN + SET NOCOUNT ON + DECLARE @DISKCUR INT = 0 + IF OBJECT_ID('TEMPDB.DBO.#DISKFREE','U') IS NOT NULL + DROP TABLE #DISKFREE + CREATE TABLE #DISKFREE(LABEL VARCHAR(100) NOT NULL,FREEMB INT NOT NULL) + INSERT INTO #DISKFREE EXEC MASTER.DBO.XP_FIXEDDRIVES + SELECT @DISKCUR = ISNULL(FREEMB,0) FROM #DISKFREE WHERE LABEL = LEFT(@BACKUP_PATH,1) + IF @DISKCUR < @FREE_SIZE_MB + RETURN 0 + RETURN 1 +END +GO + + +CREATE PROCEDURE DBO.TOOL_BACKUP_DATABASE +@TYPE INT = 1 +AS +BEGIN + SET NOCOUNT ON; + DECLARE @DISK_MIN_SIZE_MB INT = 10240 + DECLARE @BACKUP_PATH VARCHAR(100) = 'D:\' + DECLARE @KEEP_BACKUP_DAYS INT + DECLARE @CHECKER INT = 0 + DECLARE @SUCCESS INT = 0 + DECLARE @CMD VARCHAR(8000) + DECLARE @SUFFIX VARCHAR(10) = '.bak' + + DECLARE @IP VARCHAR(100),@PORT VARCHAR(100) + DECLARE @SQL NVARCHAR(MAX),@FETCH_STATUS INT + + SET @SQL = NULL + SELECT @SQL = ISNULL(@SQL+'','')+'EXEC MSDB.DBO.SP_UPDATE_JOB @JOB_NAME= N'''+A.NAME+''',@ENABLED = 0;' + FROM MSDB.DBO.SYSJOBS A + WHERE A.NAME IN('TC_BACKUP_LOG') + --PRINT(@SQL) + EXEC(@SQL) + + --如果有当前实例有其他备份进程,则等待3分钟 + WHILE EXISTS(SELECT 1 FROM SYS.DM_EXEC_REQUESTS WHERE COMMAND LIKE 'BACKUP%') + BEGIN + RAISERROR ('another backup process is running.wait 3 minute continue', 1,1) + WAITFOR DELAY '00:03:00' + END + + DECLARE @APP VARCHAR(100), + @FULL_BACKUP_PATH VARCHAR(100), + @LOG_BACKUP_PATH VARCHAR(100), + @KEEP_FULL_BACKUP_DAYS INT, + @KEEP_LOG_BACKUP_DAYS INT, + @FULL_BACKUP_MIN_SIZE_MB INT, + @LOG_BACKUP_MIN_SIZE_MB INT, + @ERROR_MESSAGE VARCHAR(4000) + + --获取备份配置数据 + SELECT @APP = APP, + @FULL_BACKUP_PATH = FULL_BACKUP_PATH, + @LOG_BACKUP_PATH = LOG_BACKUP_PATH, + @KEEP_FULL_BACKUP_DAYS = KEEP_FULL_BACKUP_DAYS, + @KEEP_LOG_BACKUP_DAYS = KEEP_LOG_BACKUP_DAYS, + @FULL_BACKUP_MIN_SIZE_MB = FULL_BACKUP_MIN_SIZE_MB, + @LOG_BACKUP_MIN_SIZE_MB = LOG_BACKUP_MIN_SIZE_MB + FROM DBO.BACKUP_SETTING + --获取IP,PORT + EXEC DBO.TOOL_GET_IPPORT @IP OUTPUT,@PORT OUTPUT + + --定义变量 + DECLARE @CURRENT_TIME VARCHAR(20) + DECLARE @START_TIME VARCHAR(25) = CONVERT(CHAR(19),GETDATE(),120) + + IF @TYPE = 1 + SELECT @BACKUP_PATH = @FULL_BACKUP_PATH,@KEEP_BACKUP_DAYS = @KEEP_FULL_BACKUP_DAYS,@DISK_MIN_SIZE_MB = @FULL_BACKUP_MIN_SIZE_MB,@SUFFIX = '.bak' + ELSE + SELECT @BACKUP_PATH = @LOG_BACKUP_PATH,@KEEP_BACKUP_DAYS = @KEEP_LOG_BACKUP_DAYS,@DISK_MIN_SIZE_MB = @LOG_BACKUP_MIN_SIZE_MB,@SUFFIX = '.trn' + IF @TYPE = 3 + SELECT @SUFFIX = '.diff' + + --删除旧文件 + SET @CMD ='FORFILES /P '+@BACKUP_PATH+' /M *'+@SUFFIX+' /S /D '+LTRIM(-1*@KEEP_BACKUP_DAYS)+' /C "CMD /C DEL @file"' + EXEC XP_CMDSHELL @CMD + + EXEC @CHECKER = DBO.TOOL_CHECK_DISK_FREE_SIZE @BACKUP_PATH,@DISK_MIN_SIZE_MB + IF @CHECKER = 0 + BEGIN + --删除1天前的文件 + SET @CMD ='FORFILES /P '+@BACKUP_PATH+' /M *'+@SUFFIX+' /S /D -1 /C "CMD /C DEL @file"' + EXEC XP_CMDSHELL @CMD + + EXEC @CHECKER = DBO.TOOL_CHECK_DISK_FREE_SIZE @BACKUP_PATH,@DISK_MIN_SIZE_MB + IF @CHECKER = 0 + BEGIN + SET @SQL = NULL + SELECT @SQL = ISNULL(@SQL+'','')+'EXEC MSDB.DBO.SP_UPDATE_JOB @JOB_NAME= N'''+A.NAME+''',@ENABLED = 1;' + FROM MSDB.DBO.SYSJOBS A + WHERE A.NAME IN('TC_BACKUP_LOG') + --PRINT(@SQL) + EXEC(@SQL) + + SET @ERROR_MESSAGE = 'DISK_FREE_SIZE_MB LESS THAN '+LTRIM(@DISK_MIN_SIZE_MB)+' MB,BACKUP FAIL.' + RAISERROR(@ERROR_MESSAGE,11,1); + END + END + + BEGIN TRY + --开始备份 + SET @SQL = NULL + SELECT @SQL = ISNULL(@SQL+CHAR(13),'')+' + DECLARE @SUCCESS_'+NAME+' INT = 0,@CHECKER_'+NAME+' INT = 0 + DECLARE @STARTTIME_'+NAME+' VARCHAR(25) = CONVERT(CHAR(19),GETDATE(),120), + @STARTTIME_SHORT_'+NAME+' VARCHAR(25) =REPLACE(REPLACE(REPLACE(CONVERT(CHAR(19),GETDATE(),120),'':'',''''),''-'',''''),'' '','''') + DECLARE @FILENAME_'+NAME+' VARCHAR(4000) = '''+@APP+'_'+@IP+'_'+LTRIM(@PORT)+'_'+NAME+'_''+@STARTTIME_SHORT_'+NAME+'+'''+@SUFFIX+''' + DECLARE @FULLFILENAME_'+NAME+' VARCHAR(4000) = '''+@BACKUP_PATH+'''+@FILENAME_'+NAME+' + EXEC @CHECKER_'+NAME+' = DBO.TOOL_CHECK_DISK_FREE_SIZE '''+@BACKUP_PATH+''','+LTRIM(@DISK_MIN_SIZE_MB)+' + IF @CHECKER_'+NAME+' = 1 + BEGIN + IF '+LTRIM(@TYPE)+' <> 1 AND EXISTS(SELECT 1 FROM SYS.MASTER_FILES A,Monitor.DBO.BACKUP_DBLIST B WHERE A.DATABASE_ID = B.DATABASE_ID AND B.NAME = '''+NAME+''' AND A.TYPE = 0 AND A.DIFFERENTIAL_BASE_LSN IS NULL) + BEGIN + DECLARE @NEWFULLFILENAME_'+NAME+' VARCHAR(4000) = REPLACE(REPLACE(@FULLFILENAME_'+NAME+','''+@SUFFIX+''',''.bak''),'''+@BACKUP_PATH+''','''+@FULL_BACKUP_PATH+''') + EXEC @SUCCESS_'+NAME+' = DBO.TOOL_BACKUP_DATABASE_OPERATOR 1,'''+NAME+''',@NEWFULLFILENAME_'+NAME+' + END + EXEC @SUCCESS_'+NAME+' = DBO.TOOL_BACKUP_DATABASE_OPERATOR '+LTRIM(@TYPE)+','''+NAME+''',@FULLFILENAME_'+NAME+' + END + DECLARE @ENDTIME_'+NAME+' VARCHAR(25) = CONVERT(CHAR(19),GETDATE(),120) + INSERT INTO DBO.BACKUP_TRACE(DBNAME,[PATH],FILENAME,TYPE,STARTTIME,ENDTIME,FILESIZE,MD5CODE,SUCCESS,UPLOADED,WRITETIME) + VALUES('''+NAME+''','''+@BACKUP_PATH+''',@FILENAME_'+NAME+','+LTRIM(@TYPE)+',@STARTTIME_'+NAME+',@ENDTIME_'+NAME+',0,0,@SUCCESS_'+NAME+',0,GETDATE())' + FROM DBO.BACKUP_DBLIST + --PRINT(@SQL) + EXEC (@SQL) + END TRY + BEGIN CATCH + PRINT '~~ error in backup database ~~' + END CATCH + + BEGIN TRY + --开始生成文件大小和MD5码,以及上报XML + SET @SQL = NULL + SELECT @SQL = ISNULL(@SQL+CHAR(13),'')+' + EXEC DBO.TOOL_BACKUP_XML '''+FILENAME+''','''+@IP+''','''+@PORT+'''' + FROM MONITOR.DBO.BACKUP_TRACE + WHERE SUCCESS = 1 AND UPLOADED = 0 AND TYPE = @TYPE AND STARTTIME >= @START_TIME + --PRINT(@SQL) + EXEC (@SQL) + + --生成每天的日志备份上报数据 + IF (@TYPE > 1 AND DATEPART(HOUR,GETDATE()) = 23 AND DATEPART(MI,GETDATE()) >= 30 AND DATEPART(MI,GETDATE()) < 59) + BEGIN + EXEC MONITOR.DBO.TOOL_BACKUP_XML_LOG_DAILY @IP,@PORT + END + + END TRY + BEGIN CATCH + PRINT '~~ error in build xml ~~' + END CATCH + + SET @SQL = NULL + SELECT @SQL = ISNULL(@SQL+'','')+'EXEC MSDB.DBO.SP_UPDATE_JOB @JOB_NAME= N'''+A.NAME+''',@ENABLED = 1;' + FROM MSDB.DBO.SYSJOBS A + WHERE A.NAME IN('TC_BACKUP_LOG') + --PRINT(@SQL) + EXEC(@SQL) + + --add shrink log step + DECLARE @shrink_size bigint + SET @shrink_size=1024 + IF EXISTS(SELECT 1 FROM [Monitor].[dbo].[BACKUP_SETTING] where APP in(SELECT APP FROM MONITOR.DBO.APP_SETTING)) + SET @shrink_size=20480 + + SET @SQL = NULL + SELECT @SQL = ISNULL(@SQL+';'+CHAR(13),'')+'USE ['+A.NAME+'] DBCC SHRINKFILE ('''+B.NAME+''','+convert(varchar,@shrink_size)+')' + FROM SYS.DATABASES A,SYS.MASTER_FILES B + WHERE A.DATABASE_ID > 4 + AND A.NAME <> 'MONITOR' + AND A.STATE = 0 + AND A.IS_READ_ONLY = 0 + AND A.DATABASE_ID = B.DATABASE_ID + AND B.TYPE = 1 + AND B.SIZE*8/1024/1024 >= 15 + --PRINT(@SQL) + EXEC(@SQL) +END +GO + +CREATE PROCEDURE [dbo].[sp_dbo_do_log_backup] +AS +BEGIN + EXEC DBO.TOOL_BACKUP_DATABASE 2 +END +GO +CREATE PROCEDURE [dbo].[sp_dbo_do_diff_backup] +AS +BEGIN + EXEC DBO.TOOL_BACKUP_DATABASE 3 +END +GO + +CREATE PROCEDURE [dbo].[sp_dbo_dbbackup] +AS +BEGIN + EXEC DBO.TOOL_BACKUP_DATABASE 1 +END +GO diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/03_auto_switch.sql b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/03_auto_switch.sql new file mode 100644 index 0000000000..333c00aa15 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/03_auto_switch.sql @@ -0,0 +1,824 @@ +USE Monitor +SET QUOTED_IDENTIFIER ON +SET NOCOUNT ON +GO +IF OBJECT_ID('DBO.[Sys_AutoSwitch]','P') IS NOT NULL +DROP PROC DBO.[Sys_AutoSwitch] +GO +IF OBJECT_ID('DBO.[Sys_AutoSwitch_Suspend]','P') IS NOT NULL +DROP PROC DBO.[Sys_AutoSwitch_Suspend] +GO +IF OBJECT_ID('DBO.[Sys_AutoSwitch_SafetyOff]','P') IS NOT NULL +DROP PROC DBO.[Sys_AutoSwitch_SafetyOff] +GO +IF OBJECT_ID('DBO.[Sys_AutoSwitch_Resume]','P') IS NOT NULL +DROP PROC DBO.[Sys_AutoSwitch_Resume] +GO +IF OBJECT_ID('DBO.[Sys_AutoSwitch_Remove]','P') IS NOT NULL +DROP PROC DBO.[Sys_AutoSwitch_Remove] +GO +IF OBJECT_ID('DBO.[Sys_AutoSwitch_LossOver]','P') IS NOT NULL +DROP PROC DBO.[Sys_AutoSwitch_LossOver] +GO +IF OBJECT_ID('DBO.[Sys_AutoSwitch_FailOver]','P') IS NOT NULL +DROP PROC DBO.[Sys_AutoSwitch_FailOver] +GO +IF OBJECT_ID('DBO.[Sys_AutoSwitch_DrToDb]','P') IS NOT NULL +DROP PROC DBO.[Sys_AutoSwitch_DrToDb] +GO + + +/****** Object: StoredProcedure [dbo].[Sys_AutoSwitch_Suspend] Script Date: 02/28/2015 20:29:52 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE Proc [dbo].[Sys_AutoSwitch_Suspend] +(@msg varchar(1000) output) +AS + +declare @strsql varchar(max) ,@dbname varchar(100) +set @dbname='' + +BEGIN TRY + + --判断DB镜像状态,状态为Suspended可进行Suspend + if not exists(select 1 from master.sys.database_mirroring + where mirroring_role=1 and mirroring_state=4) + begin + set @msg='GameDB Is not Synchronized' + return -1 + end + + --获取待Resume镜像DB列表 + DECLARE dblist_cur cursor static forward_only Read_only for + select name from master.sys.sysdatabases a left join master.sys.database_mirroring b + on a.dbid=b.database_id + where dbid>4 and name not in('monitor') and b.mirroring_guid is not null and b.mirroring_role=1 + OPEN dblist_cur; + + FETCH NEXT FROM dblist_cur INTO @dbname + WHILE @@FETCH_STATUS = 0 + BEGIN + --resume + set @strsql='Use master alter database '+@dbname+' set partner Suspend;' + exec(@strsql) + if @@error>0 + begin + set @msg='GameDb Suspend abnormal failure' + return -1 + end + + FETCH NEXT FROM dblist_cur INTO @dbname; + END + CLOSE dblist_cur; + DEALLOCATE dblist_cur; + + --检测镜像是否Resume + if exists(select 1 from master.sys.database_mirroring + where mirroring_role=1 and mirroring_state=4) + begin + set @msg='GameDb has no Suspend' + return -1 + end + + set @msg='GameDb Suspend Success' + + RETURN 1 + +END TRY +BEGIN CATCH + --扑捉异常错误 + --set @msg='GameDb execution exception' + set @msg=ERROR_MESSAGE() + RETURN -1 + +END CATCH +GO +/****** Object: StoredProcedure [dbo].[Sys_AutoSwitch_SafetyOff] Script Date: 02/28/2015 20:29:52 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE Proc [dbo].[Sys_AutoSwitch_SafetyOff] +(@msg varchar(1000) output) +AS + +declare @strsql varchar(max) ,@dbname varchar(100) +set @dbname='' + +BEGIN TRY + + --判断DB镜像状态,状态为Principal可进行SafetyOff + if not exists(select 1 from master.sys.database_mirroring + where mirroring_role=1) + begin + set @msg='GameDB Is not Principal' + return -1 + end + + --获取待Resume镜像DB列表 + DECLARE dblist_cur cursor static forward_only Read_only for + select name from master.sys.sysdatabases a left join master.sys.database_mirroring b + on a.dbid=b.database_id + where dbid>4 and name not in('monitor') and b.mirroring_guid is not null and b.mirroring_role=1 + OPEN dblist_cur; + + FETCH NEXT FROM dblist_cur INTO @dbname + WHILE @@FETCH_STATUS = 0 + BEGIN + --resume + set @strsql='Use master alter database '+@dbname+' set partner safety off;' + exec(@strsql) + if @@error>0 + begin + set @msg='GameDb SafetyOff abnormal failure' + return -1 + end + + FETCH NEXT FROM dblist_cur INTO @dbname; + END + CLOSE dblist_cur; + DEALLOCATE dblist_cur; + + --检测镜像是否Resume + if exists(select 1 from master.sys.database_mirroring + where mirroring_role=1 and mirroring_safety_level=2) + begin + set @msg='GameDb has no SafetyOff' + return -1 + end + + set @msg='GameDb SafetyOff Success' + + RETURN 1 + +END TRY +BEGIN CATCH + --扑捉异常错误 + set @msg='GameDb execution exception' + + RETURN -1 + +END CATCH +GO +/****** Object: StoredProcedure [dbo].[Sys_AutoSwitch_Resume] Script Date: 02/28/2015 20:29:52 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE Proc [dbo].[Sys_AutoSwitch_Resume] +(@msg varchar(1000) output) +AS + +declare @strsql varchar(max) ,@dbname varchar(100) +set @dbname='' + +BEGIN TRY + + --判断DB镜像状态,状态为Suspended可进行Resume + if not exists(select 1 from master.sys.database_mirroring + where mirroring_role=1 and mirroring_state=0) + begin + set @msg='GameDB state has been Suspended' + return -1 + end + + --获取待Resume镜像DB列表 + DECLARE dblist_cur cursor static forward_only Read_only for + select name from master.sys.sysdatabases a left join master.sys.database_mirroring b + on a.dbid=b.database_id + where dbid>4 and name not in('monitor') and b.mirroring_guid is not null and b.mirroring_role=1 and b.mirroring_state=0 + OPEN dblist_cur; + + FETCH NEXT FROM dblist_cur INTO @dbname + WHILE @@FETCH_STATUS = 0 + BEGIN + --resume + set @strsql='Use master alter database '+@dbname+' set partner resume;' + exec(@strsql) + if @@error>0 + begin + set @msg='GameDb Resume abnormal failure' + return -1 + end + + FETCH NEXT FROM dblist_cur INTO @dbname; + END + CLOSE dblist_cur; + DEALLOCATE dblist_cur; + + --检测镜像是否Resume + if exists(select 1 from master.sys.database_mirroring + where mirroring_state=0) + begin + set @msg='GameDb has no Synchronized' + return -1 + end + + set @msg='GameDb Resume Success' + + RETURN 1 + +END TRY +BEGIN CATCH + --扑捉异常错误 + set @msg='GameDb execution exception' + + RETURN -1 + +END CATCH +GO +/****** Object: StoredProcedure [dbo].[Sys_AutoSwitch_Remove] Script Date: 02/28/2015 20:29:52 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE Proc [dbo].[Sys_AutoSwitch_Remove] +(@msg varchar(1000) output) +AS + +declare @strsql varchar(max) ,@dbname varchar(100) +set @dbname='' + +BEGIN TRY + + --判断DB镜像状态,状态为Suspended可进行Resume + if not exists(select 1 from master.sys.database_mirroring + where mirroring_role=1) + begin + set @msg='GameDB Is Not Principal' + return -1 + end + + --获取待Resume镜像DB列表 + DECLARE dblist_cur cursor static forward_only Read_only for + select name from master.sys.sysdatabases a left join master.sys.database_mirroring b + on a.dbid=b.database_id + where dbid>4 and name not in('monitor') and b.mirroring_guid is not null and b.mirroring_role=1 + OPEN dblist_cur; + + FETCH NEXT FROM dblist_cur INTO @dbname + WHILE @@FETCH_STATUS = 0 + BEGIN + --resume + set @strsql='Use master alter database '+@dbname+' set partner off;' + exec(@strsql) + if @@error>0 + begin + set @msg='GameDb Remove abnormal failure' + return -1 + end + + FETCH NEXT FROM dblist_cur INTO @dbname; + END + CLOSE dblist_cur; + DEALLOCATE dblist_cur; + + --检测镜像是否Resume + if exists(select 1 from master.sys.database_mirroring + where mirroring_role=1) + begin + set @msg='GameDb has no Remove' + return -1 + end + + set @msg='GameDb Remove Success' + + RETURN 1 + +END TRY +BEGIN CATCH + --扑捉异常错误 + set @msg='GameDb execution exception' + + RETURN -1 + +END CATCH +GO +/****** Object: StoredProcedure [dbo].[Sys_AutoSwitch_LossOver] Script Date: 02/28/2015 20:29:52 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE Proc [dbo].[Sys_AutoSwitch_LossOver] +(@msg varchar(1000) output) +AS + +declare @strsql varchar(max) ,@dbname varchar(100) +set @dbname='' + +BEGIN TRY + + --判断DR镜像状态,状态为断开可进行切换 + if not exists(select 1 from master.sys.database_mirroring + where mirroring_role=2 and mirroring_state=1) + begin + set @msg='GameDB state has been Suspended' + return -1 + end + + --判断DR落后DB时间,[待发送日志]小于10秒(10M)为可进行切换 + IF exists(SELECT 1 FROM master.sys.dm_os_performance_counters + WHERE object_name LIKE '%Database Mirroring%' + AND counter_name='Log Send Queue KB' and cntr_value>10240) --10M + begin + set @msg='GameDB to send log exceeds 10M' + return -1 + end + + --判断DR跟进DB情况,[待重做日志]小于1M为可进行切换 + IF exists(SELECT 1 FROM master.sys.dm_os_performance_counters + WHERE object_name LIKE '%Database Mirroring%' + AND counter_name='Redo Queue KB' and cntr_value>1024) --1M + begin + set @msg='GameDB to redo log exceeds 1M' + return -1 + end + + --获取待切换镜像DB列表 + DECLARE dblist_cur cursor static forward_only Read_only for + select name from master.sys.sysdatabases a left join master.sys.database_mirroring b + on a.dbid=b.database_id + where dbid>4 and name not in('monitor') and b.mirroring_guid is not null and b.mirroring_role=2 and b.mirroring_state=1 + OPEN dblist_cur; + + FETCH NEXT FROM dblist_cur INTO @dbname + WHILE @@FETCH_STATUS = 0 + BEGIN + --强制故障切换 + set @strsql='Use master alter database '+@dbname+' set partner FORCE_SERVICE_ALLOW_DATA_LOSS;' + + exec(@strsql) + if @@error>0 + begin + set @msg='GameDR switch abnormal failure' + return -1 + end + + FETCH NEXT FROM dblist_cur INTO @dbname; + END + CLOSE dblist_cur; + DEALLOCATE dblist_cur; + + --检测镜像是否都切换为主 + if exists(select 1 from master.sys.database_mirroring + where mirroring_role=1) + begin + set @msg='GameDr has no DB switching' + return -1 + end + + set @msg='GameDR switch Success' + + RETURN 1 + +END TRY +BEGIN CATCH + --扑捉异常错误 + set @msg='GameDr execution exception' + + RETURN -1 + +END CATCH +GO +/****** Object: StoredProcedure [dbo].[Sys_AutoSwitch_FailOver] Script Date: 02/28/2015 20:29:52 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE Proc [dbo].[Sys_AutoSwitch_FailOver] +(@msg varchar(1000) output) +AS + + +declare @strsql varchar(max) ,@dbname varchar(100) +set @dbname='' + +BEGIN TRY + + --判断DR镜像状态,状态为断开可进行切换 + if not exists(select 1 from master.sys.database_mirroring + where mirroring_role=1 and mirroring_state=4) + begin + set @msg='GameDB state has been Synchronized' + return -1 + end + + --获取待切换镜像DB列表 + DECLARE dblist_cur cursor static forward_only Read_only for + select name from master.sys.sysdatabases a left join master.sys.database_mirroring b + on a.dbid=b.database_id + where dbid>4 and name not in('monitor') and b.mirroring_guid is not null and b.mirroring_role=1 and b.mirroring_state=4 + OPEN dblist_cur; + + FETCH NEXT FROM dblist_cur INTO @dbname + WHILE @@FETCH_STATUS = 0 + BEGIN + --强制故障切换 + set @strsql='Use master alter database '+@dbname+' set partner safety full;' + set @strsql=@strsql+'alter database '+@dbname+' set partner failover;' + + exec(@strsql) + if @@error>0 + begin + set @msg='GameDR switch abnormal failure' + return -1 + end + + FETCH NEXT FROM dblist_cur INTO @dbname; + END + CLOSE dblist_cur; + DEALLOCATE dblist_cur; + + --检测镜像是否都切换为主 + if exists(select 1 from master.sys.database_mirroring + where mirroring_role=1) + begin + set @msg='GameDr has no DB switching' + return -1 + end + + set @msg='GameDR switch Success' + + RETURN 1 + +END TRY +BEGIN CATCH + --扑捉异常错误 + --set @msg='GameDb execution exception' + set @msg=ERROR_MESSAGE() + RETURN -1 + +END CATCH +GO +/****** Object: StoredProcedure [dbo].[Sys_AutoSwitch_DrToDb] Script Date: 02/28/2015 20:29:52 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE Proc [dbo].[Sys_AutoSwitch_DrToDb] +AS + +/** +功能:DB故障进行验证和切换到DR +验证方式: +1.判断DR镜像状态,状态为断开可进行切换 +2.判断GameDB故障时间,小于10分钟可进行切换 +3.判断DR落后DB时间,[待发送日志]小于10秒(10M)为可进行切换 +4.判断DR跟进DB情况,[待重做日志]小于1M为可进行切换 +切换方式: +Use master alter database test set partner FORCE_SERVICE_ALLOW_DATA_LOSS; +检测镜像是否都切换为主 + +exec monitor.dbo.Sys_AutoSwitch_DrToDb + +**/ + +declare @msg varchar(1000) + +declare @r int,@strsql varchar(max) ,@dbname varchar(100) +DECLARE @ERR_FAILURE INT = 1 +set @dbname='' + +BEGIN TRY + declare @version bigint,@is_alwayson_flag tinyint + set @version=convert(bigint,DATABASEPROPERTYEX('master','version')) + set @is_alwayson_flag=0 + + IF OBJECT_ID('TEMPDB.DBO.#tmp_dblist','U') IS NOT NULL + DROP TABLE #tmp_dblist + create table #tmp_dblist(name varchar(200)) + + IF @version>=869 + exec('insert into #tmp_dblist select name from sys.availability_groups') + + IF exists(select 1 from #tmp_dblist) + set @is_alwayson_flag=1 + + IF not exists(select database_id from master.sys.database_mirroring where mirroring_guid is not null) and not exists(select 1 from #tmp_dblist) + BEGIN + set @msg='alwayson/mirroring is not exists' + select -1 as status,@msg as msg + return -1 + END + + DECLARE @SQL VARCHAR(MAX) + DECLARE @i INT + IF @is_alwayson_flag=1 + BEGIN + IF OBJECT_ID('TEMPDB.DBO.#repl_state','U') IS NOT NULL + DROP TABLE #repl_state + CREATE TABLE #repl_state(is_local bit,role tinyint,connected_state tinyint,synchronization_health tinyint,operational_state tinyint,recovery_health tinyint,last_connect_error_number int,last_connect_error_timestamp datetime) + + SET @i=1 + WHILE @i<=60 + BEGIN + if @i<>1 + waitfor delay '00:00:01' + + SET @SQL='delete from #repl_state;insert into #repl_state select is_local,role,connected_state,synchronization_health,operational_state,recovery_health,last_connect_error_number,last_connect_error_timestamp from master.sys.dm_hadr_availability_replica_states where is_local=1 and role=2' + EXEC(@SQL) + + IF EXISTS(SELECT 1 FROM #repl_state WHERE connected_state=0) + SET @i=60 + + SET @i=@i+1 + END + + IF NOT EXISTS(SELECT 1 FROM #repl_state WHERE connected_state=0) + BEGIN + set @msg='GameDB state has been disconnected' + select -1 as status,@msg as msg + return -1 + END + ELSE + BEGIN + SET @SQL=' + DECLARE @SQL varchar(max),@group_name varchar(1000),@msg VARCHAR(100) + IF EXISTS(SELECT 1 FROM sys.availability_groups) + BEGIN + BEGIN TRY + select @group_name=name from sys.availability_groups + SET @SQL=''USE MASTER ALTER AVAILABILITY GROUP [''+@group_name+''] FORCE_FAILOVER_ALLOW_DATA_LOSS'' + EXEC(@SQL) + END TRY + BEGIN CATCH + SET @msg=''GameDr switch err'' + END CATCH + END + ' + --PRINT(@SQL) + BEGIN TRY + EXEC(@SQL) + END TRY + BEGIN CATCH + SET @msg='GameDr switch failed' + END CATCH + + SET @i=1 + WHILE @i<=60 + BEGIN + if @i<>1 + waitfor delay '00:00:01' + + SET @SQL='delete from #repl_state;insert into #repl_state select is_local,role,connected_state,synchronization_health,operational_state,recovery_health,last_connect_error_number,last_connect_error_timestamp from master.sys.dm_hadr_availability_replica_states where is_local=1 and role=1' + EXEC(@SQL) + + IF EXISTS(SELECT 1 FROM #repl_state) + SET @i=60 + + SET @i=@i+1 + END + + IF exists(select 1 from #repl_state where is_local=1 and role=1) + BEGIN + set @msg='GameDR switch Success' + select 1 as status,@msg as msg + return 1 + END + ELSE + BEGIN + set @msg='GameDr switch Failed' + select -1 as status,@msg as msg + return -1 + END + END + END + ELSE + BEGIN + --判断DR镜像状态,状态为断开可进行切换 + if not exists(select 1 from master.sys.database_mirroring + where mirroring_state=1) + begin + set @msg='GameDB state has been disconnected' + select -1 as status,@msg as msg + return -1 + end + + --判断DB待未发送日志量大于10M,不允许切换 + IF exists(SELECT 1 FROM master.sys.dm_os_performance_counters + WHERE object_name LIKE '%Database Mirroring%' + AND counter_name='Log Send Queue KB' and cntr_value>102400) --100M + begin + set @msg='GameDB to send log exceeds 100M' + select -1 as status,@msg as msg + return -1 + end + + --判断DR待还原日志量大于100M,不允许切换 + IF exists(SELECT 1 FROM master.sys.dm_os_performance_counters + WHERE object_name LIKE '%Database Mirroring%' + AND counter_name='Redo Queue KB' and cntr_value>102400) --100M + begin + set @msg='GameDB to redo log exceeds 1M' + select -1 as status,@msg as msg + return -1 + end + + --获取待切换镜像DB列表 + DECLARE dblist_cur cursor static forward_only Read_only for + select name from master.sys.sysdatabases a left join master.sys.database_mirroring b + on a.dbid=b.database_id + where dbid>4 and name not in('monitor') and b.mirroring_guid is not null and b.mirroring_role=2 and b.mirroring_state=1 + OPEN dblist_cur; + + FETCH NEXT FROM dblist_cur INTO @dbname + WHILE @@FETCH_STATUS = 0 + BEGIN + --强制故障切换 + set @strsql='Use master alter database '+@dbname+' set partner FORCE_SERVICE_ALLOW_DATA_LOSS;' + exec(@strsql) + if @@error>0 + begin + set @msg='GameDR switch abnormal failure' + select -1 as status,@msg as msg + return -1 + end + + FETCH NEXT FROM dblist_cur INTO @dbname; + END + CLOSE dblist_cur; + DEALLOCATE dblist_cur; + + --检测镜像是否都切换为主 + if exists(select 1 from master.sys.database_mirroring + where mirroring_role=2) + begin + set @msg='GameDr has no DB switching' + select -1 as status,@msg as msg + return -1 + end + + set @msg='GameDR switch Success' + select 1 as status,@msg as msg + + RETURN 1 + END + +END TRY +BEGIN CATCH + --扑捉异常错误 + set @msg='GameDr execution exception' + select -1 as status,@msg as msg + + RETURN -1 + +END CATCH +GO + +/****** Object: StoredProcedure [dbo].[Sys_AutoSwitch] Script Date: 02/28/2015 20:29:52 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE proc [dbo].[Sys_AutoSwitch] +(@Flag tinyint) +AS + +declare @r int=0; +declare @i int=1; +declare @DBname varchar(100) +declare @ERR_FAILURE INT = 1; +declare @msg varchar(1000) + +BEGIN TRY + SET @DBname='test' + + --检查2分钟 + while @i<=120 + begin + --校验数据是否同步 + Exec @r=dbo.A @DBname + if @r=1 + break + + waitfor time '00:00:01' + set @i=@i+1 + end + + if @r<>1 + begin + print 'err' + return -1 + end + + --自动切换+断开镜像 + if @Flag=1 + begin + --切换镜像角色 + Exec @r=Link_DB.monitor.dbo.Sys_AutoSwitch_FailOver @msg output + if @r<>1 + begin + print 'err2' + return -1 + end + + -- + waitfor time '00:00:01' + + --断开镜像关系 + Exec @r=monitor.dbo.Sys_AutoSwitch_Remove @msg output + if @r<>1 + begin + print 'err3' + return -1 + end + + end + --自动切换 + else if @Flag=2 + begin + --切换镜像角色 + Exec @r=Link_DB.monitor.dbo.Sys_AutoSwitch_FailOver @msg output + if @r<>1 + begin + print 'err2' + return -1 + end + + Exec @r=monitor.dbo.Sys_AutoSwitch_SafetyOff @msg output + if @r<>1 + begin + print 'err3' + return -1 + end + + end + --强制切换 + else if @Flag=3 + begin + --切换镜像角色 + Exec @r=monitor.dbo.Sys_AutoSwitch_LossOver @msg output + if @r<>1 + begin + print 'err3' + return -1 + end + end + --强制切换 + else if @Flag=4 + begin + --切换镜像角色 + Exec @r=monitor.dbo.Sys_AutoSwitch_Resume @msg output + if @r<>1 + begin + print 'err3' + return -1 + end + end + --强制切换 + else if @Flag=5 + begin + --切换镜像角色 + Exec @r=monitor.dbo.Sys_AutoSwitch_Remove @msg output + if @r<>1 + begin + print 'err3' + return -1 + end + end + --强制切换 + else if @Flag=6 + begin + --切换镜像角色 + Exec @r=monitor.dbo.Sys_AutoSwitch_SafetyOff @msg output + if @r<>1 + begin + print 'err3' + return -1 + end + end + + if @Flag<>0 + begin + --检查新DB状态 + SELECT mirroring_state, mirroring_state_desc, mirroring_failover_lsn + FROM sys.database_mirroring + WHERE database_id=db_id(@DBname); + end + + RETURN 1 + +END TRY +BEGIN CATCH +DECLARE @ERR_NUMBER INT = ERROR_NUMBER(), + @ERR_SEVERITY INT = ERROR_SEVERITY(), + @ERR_STATE INT = ERROR_STATE(), + @ERR_PROCEDURE NVARCHAR(126) = ERROR_PROCEDURE(), + @ERR_MESSAGE NVARCHAR(2048) = ERROR_MESSAGE(), + @ERR_CODE INT = @ERR_FAILURE; + + IF (@ERR_NUMBER >= 50000) BEGIN + IF (@ERR_PROCEDURE = OBJECT_NAME(@@PROCID)) + SET @ERR_CODE = @ERR_STATE; + END + + IF (@@NESTLEVEL = 1) + RAISERROR(N'[%s], %s', @ERR_SEVERITY, @ERR_CODE, @ERR_PROCEDURE, @ERR_MESSAGE); + ELSE + RAISERROR(@ERR_MESSAGE, @ERR_SEVERITY, @ERR_CODE); + + RETURN @ERR_CODE; +END CATCH +GO diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/04_sqlsetting.sql b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/04_sqlsetting.sql new file mode 100644 index 0000000000..03596b1e4c --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/04_sqlsetting.sql @@ -0,0 +1,32 @@ +USE MASTER +SET QUOTED_IDENTIFIER ON +SET NOCOUNT ON +GO + + +EXEC SP_CONFIGURE 'SHOW ADVANCED OPTIONS',1 +GO +RECONFIGURE; +GO + +EXEC SP_CONFIGURE 'CROSS DB OWNERSHIP CHAINING',1 +EXEC SP_CONFIGURE 'AGENT XPS',1 +exec SP_CONFIGURE 'remote access',1 +EXEC SP_CONFIGURE 'REMOTE ADMIN CONNECTIONS',0 +EXEC SP_CONFIGURE 'XP_CMDSHELL',1 +EXEC SP_CONFIGURE 'C2 AUDIT MODE',0 +EXEC SP_CONFIGURE 'RECOVERY INTERVAL',0 +EXEC SP_CONFIGURE 'FILL FACTOR (%)',80 +EXEC SP_CONFIGURE 'ALLOW UPDATES',0 +EXEC SP_CONFIGURE 'BACKUP COMPRESSION DEFAULT',1 +EXEC SP_CONFIGURE 'AD HOC DISTRIBUTED QUERIES',1 +EXEC SP_CONFIGURE 'SMO and DMO XPs',1 + +GO +RECONFIGURE +GO + +EXEC SP_CONFIGURE 'SHOW ADVANCED OPTIONS',0 +GO +RECONFIGURE; +GO \ No newline at end of file diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/init_sqlserver.ps1 b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/init_sqlserver.ps1 new file mode 100644 index 0000000000..fe395a1329 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/init_sqlserver.ps1 @@ -0,0 +1,187 @@ +# TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. +# Copyright (C) 2017-2023 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 https://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. + + +#POWERSHELL D:\sql_install\dba_tools\install\common.ps1 0.0.0.0 SQL2008x64_SorceMedia S48322,S48332 0 0 >D:\sql_install\dba_tools\install\install.log 2>&1 +#POWERSHELL D:\sql_install\dba_tools\install\common.ps1 0.0.0.0 SQL2019x64_SorceMedia S48322,S48332 1 1 >D:\sql_install\dba_tools\install\install.log 2>&1 +#"C:\Program Files\7-Zip\7z" x -oD: D:\SQL2008R2x64_SorceMedia.tar +PARAM +( +[STRING]$LOCAL_IP = $(THROW "Parameter LOCAL_IP missing."), +[STRING]$MEDIA_PATH_VERSION = $(THROW "Parameter sqlserver version missing.such as SQL2008R2x64,SQL2012x64,SQL2014x64,SQL2016x64,SQL2017x64,SQL2019x64,SQL2022x64 etc."), +[STRING]$INSNAME_LIST = $(THROW "Parameter INSNAME_LIST list missing."), +[STRING]$HADR_Enabled = $(THROW "Parameter HADR_Enabled missing."), +[STRING]$SSMS_Enabled = $(THROW "Parameter SSMS_Enabled missing.") +) + +#----------------------------------- version controler ----------------------- +$TARGET_INSTANCES = $INSNAME_LIST.TOUPPER().SPLIT(" ") +$MANAGER_PATH = "D:\" +$MEDIA_PATH = "D:\"+$MEDIA_PATH_VERSION+"\" + +# $CONFIGURATION_FILE_HEAD_VERSION = "[OPTIONS]" +# IF ($MEDIA_PATH_VERSION -like "*2008*") +# { +# $CONFIGURATION_FILE_HEAD_VERSION = "[SQLSERVER2008]" +# } + +#--------------------------------------- mkdir path ----------------------------------- +# $DISKLIST = GET-WMIOBJECT -CLASS WIN32_LOGICALDISK |WHERE-OBJECT {$_.DRIVETYPE -EQ 3}|SELECT-OBJECT -PROPERTY DEVICEID + +# FOREACH($T IN $TARGET_INSTANCES) +# { +# $PORT = $T.REPLACE("S","") +# FOREACH($DISK IN $DISKLIST) +# { +# IF($DISK.DEVICEID -NE "C:") +# { +# $CMD = "IF NOT EXIST "+$DISK.DEVICEID+"\gamedb\"+$PORT+" md "+$DISK.DEVICEID+"\gamedb\"+$PORT+"" +# CMD /C $CMD +# } +# } +# } + +#--------------------------------------- special work ----------------------------------- +# #configuration windows service +# SET-SERVICE AppMgmt -STARTUPTYPE DISABLED +# SET-SERVICE Spooler -STARTUPTYPE DISABLED +# SET-SERVICE RasMan -STARTUPTYPE DISABLED +# SET-SERVICE RpcLocator -STARTUPTYPE DISABLED +# SET-SERVICE RemoteAccess -STARTUPTYPE DISABLED +# SET-SERVICE SCardSvr -STARTUPTYPE DISABLED +# SET-SERVICE AudioSrv -STARTUPTYPE DISABLED +# SET-SERVICE SharedAccess -STARTUPTYPE DISABLED +# SET-SERVICE WinRM -STARTUPTYPE DISABLED + +# #Ignore restart +# $CMD = "reg delete ""HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired"" /f" +# CMD /C $CMD +# $CMD = "reg delete ""HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager"" /v PendingFileRenameOperations /f" +# CMD /C $CMD + + +#--------------------------------------- install action ------------------------------------------- +# IMPORT-MODULE SERVERMANAGER #GET-WINDOWSFEATURE +# ADD-WINDOWSFEATURE TELNET-CLIENT + +# SET-LOCATION "C:\Windows\Temp" + +# key of configuration file +# FOREACH($T IN $TARGET_INSTANCES) +# { +# $PORT = $T.REPLACE("S","") +# $TARGET_CONFIGURATION_FILE = $MANAGER_PATH+$MODULE_CONFIGURATION_FILE+"_"+$T +# IF(TEST-PATH $TARGET_CONFIGURATION_FILE){REMOVE-ITEM $TARGET_CONFIGURATION_FILE} +# $CONTENT = GET-CONTENT $SOURCE_CONFIGURATION_FILE +# $CONTENT = $CONTENT.REPLACE('{data_dir_port}',$PORT) +# "$CONFIGURATION_FILE_HEAD_VERSION" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $TARGET_CONFIGURATION_FILE +# $CONTENT | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $TARGET_CONFIGURATION_FILE +# "INSTANCEID=""$T""" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $TARGET_CONFIGURATION_FILE +# "INSTANCENAME=""$T""" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $TARGET_CONFIGURATION_FILE +# #install aciton +# $CMD = $MEDIA_PATH+"setup.exe /ConfigurationFile=$TARGET_CONFIGURATION_FILE" +# CMD /C $CMD +# REMOVE-ITEM $TARGET_CONFIGURATION_FILE +# } + +# REMOVE-ITEM $SOURCE_CONFIGURATION_FILE + +#--------------------------------------- bind port ----------------------------------- +#define sever instance array +$LOCAL_INSTANCES = @() +$MASTER_KEY_SHORT = "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\" +$MASTER_KEY = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\" +$DETAIL_KEY = "\MSSQLServer\SuperSocketNetLib\Tcp" +$DETAIL_HADR_KEY = "\MSSQLServer" + +#get all instance name,version,ipnum on server +FOREACH($KEY IN GET-CHILDITEM $MASTER_KEY_SHORT | WHERE-OBJECT {$_.NAME -LIKE "*MSSQL*"} | WHERE-OBJECT {$_.NAME -NOTLIKE "*Microsoft SQL Server\MSSQLSERVER"}) +{ + $STR = $KEY.NAME.REPLACE($MASTER_KEY,"") + IF($STR.LENGTH -GT 0) + { + FOREACH($T IN $TARGET_INSTANCES) + { + IF ($STR -like "*."+$T) + { + $PORT = $T.REPLACE("S","") + $KEY_COUNT = (GET-CHILDITEM ($KEY.NAME+$DETAIL_KEY).REPLACE("HKEY_LOCAL_MACHINE","HKLM:")).LENGTH - 1 + $LOCAL_INSTANCES += ,($KEY.NAME,$T,$KEY_COUNT,$PORT) + } + } + } +} + +$BIND_PORT_FILE = $MANAGER_PATH+"bind_port.bat" +IF(TEST-PATH $BIND_PORT_FILE) +{ + REMOVE-ITEM $BIND_PORT_FILE +} +"@ECHO OFF" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + +FOR($I = 0;$I -LT $LOCAL_INSTANCES.LENGTH;$I ++) +{ + $KEY_HADR = $LOCAL_INSTANCES[$I][0] + $DETAIL_HADR_KEY + $KEY_PART = $LOCAL_INSTANCES[$I][0] + $DETAIL_KEY + $SQLSVC_NAME = "MSSQL$"+$LOCAL_INSTANCES[$I][1] + $AGTSVC_NAME = "SQLAGENT$"+$LOCAL_INSTANCES[$I][1] + $IPKEY_CNT = $LOCAL_INSTANCES[$I][2] + $PORT = $LOCAL_INSTANCES[$I][3] + + "REG ADD """+$KEY_PART+"\IP1"" /v Active /t REG_DWORD /d 1 /f" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + "REG ADD """+$KEY_PART+"\IP1"" /v Enabled /t REG_DWORD /d 1 /f" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + "REG ADD """+$KEY_PART+"\IP1"" /v IpAddress /t REG_SZ /d "+$LOCAL_IP+" /f" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + "REG ADD """+$KEY_PART+"\IP1"" /v TcpDynamicPorts /t REG_SZ /d """" /f" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + "REG ADD """+$KEY_PART+"\IP1"" /v TcpPort /t REG_SZ /d "+$PORT+" /f" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + + "REG ADD """+$KEY_PART+"\IP2"" /v Active /t REG_DWORD /d 1 /f" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + "REG ADD """+$KEY_PART+"\IP2"" /v Enabled /t REG_DWORD /d 1 /f" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + "REG ADD """+$KEY_PART+"\IP2"" /v IpAddress /t REG_SZ /d 127.0.0.1 /f" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + "REG ADD """+$KEY_PART+"\IP2"" /v TcpDynamicPorts /t REG_SZ /d """" /f" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + "REG ADD """+$KEY_PART+"\IP2"" /v TcpPort /t REG_SZ /d "+$PORT+" /f" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + + FOR($K = 3;$K -LE $IPKEY_CNT;$K ++) + { + "REG ADD """+$KEY_PART+"\IP"+$K+""" /v Active /t REG_DWORD /d 0 /f" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + "REG ADD """+$KEY_PART+"\IP"+$K+""" /v Enabled /t REG_DWORD /d 0 /f" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + "REG ADD """+$KEY_PART+"\IP"+$K+""" /v IpAddress /t REG_SZ /d ::"+$K+" /f" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + "REG ADD """+$KEY_PART+"\IP"+$K+""" /v TcpDynamicPorts /t REG_SZ /d """" /f" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + "REG ADD """+$KEY_PART+"\IP"+$K+""" /v TcpPort /t REG_SZ /d """" /f" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + } + "REG ADD """+$KEY_PART+""" /v AuditLevel /t REG_DWORD /d 2 /f" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + "REG ADD """+$KEY_PART+""" /v ListenOnAllIPs /t REG_DWORD /d 0 /f" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + "REG ADD """+$KEY_PART+"\IPALL"" /v TcpPort /t REG_SZ /d """" /f" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + "REG ADD """+$KEY_PART+"\IPALL"" /v TcpDynamicPorts /t REG_SZ /d """" /f" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + + #SQL2017+ + IF($HADR_Enabled -EQ "1"){ + "REG ADD """+$KEY_HADR+"\HADR"" /v HADR_Enabled /t REG_DWORD /d 1 /f" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + } + + #"NET STOP "+$AGTSVC_NAME | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + "NET STOP "+$SQLSVC_NAME+" /Y" | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + "NET START "+$SQLSVC_NAME | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE + "NET START "+$AGTSVC_NAME | OUT-FILE -ENCODING "Default" -APPEND -FILEPATH $BIND_PORT_FILE +} +#run security file +CMD /C $BIND_PORT_FILE + +REMOVE-ITEM $BIND_PORT_FILE + +#SQL2016+ +IF($SSMS_Enabled -EQ "1") +{ + $CMD = $MEDIA_PATH+"SSMS-Setup-ENU.exe /install /passive /norestart" + CMD /C $CMD +} + +#SQL2019 +IF ($MEDIA_PATH_VERSION -like "*2019*") +{ + Copy-Item -Path 'C:\Program Files (x86)\Microsoft SQL Server Management Studio 18\Common7\IDE\PrivateAssemblies\Interop\Microsoft.VisualStudio.Shell.Interop.8.0.dll' -Destination 'C:\Program Files (x86)\Microsoft SQL Server Management Studio 18\Common7\IDE\PublicAssemblies\' -Force +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/staticembed.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/staticembed.go new file mode 100644 index 0000000000..65b976dee0 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/staticembed.go @@ -0,0 +1,41 @@ +// Package staticembed TODO +package staticembed + +import "embed" + +const ( + // SysInitScriptFileName TODO + SysInitScriptFileName = "sysinit.ps1" + // InitSqlServerFileName TODO + InitSqlServerFileName = "init_sqlserver.ps1" + // MonitorFileName TODO + MonitorFileName = "01_monitor.sql" + // BackupFileName TODO + BackupFileName = "02_backup.sql" + // AutoSwitchFileName TODO + AutoSwitchFileName = "03_auto_switch.sql" + // SqlSettingFileName TODO + SqlSettingFileName = "04_sqlsetting.sql" + // TestFileName TODO + TestFileName = "test.sql" +) + +// SysInitScript TODO +// +//go:embed sysinit.ps1 +var SysInitScript embed.FS + +// InitSqlServer TODO +// +//go:embed init_sqlserver.ps1 +var InitSqlServer embed.FS + +// Test TODO +// +//go:embed *.sql +var Test embed.FS + +// SQLScript TODO +// +//go:embed *.sql +var SQLScript embed.FS diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/sysinit.ps1 b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/sysinit.ps1 new file mode 100644 index 0000000000..dbb6a01230 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/sysinit.ps1 @@ -0,0 +1,37 @@ +#-------------------------------------- special work ----------------------------------- +#configuration windows service +SET-SERVICE AppMgmt -STARTUPTYPE DISABLED +SET-SERVICE Spooler -STARTUPTYPE DISABLED +SET-SERVICE RasMan -STARTUPTYPE DISABLED +SET-SERVICE RpcLocator -STARTUPTYPE DISABLED +SET-SERVICE RemoteAccess -STARTUPTYPE DISABLED +SET-SERVICE SCardSvr -STARTUPTYPE DISABLED +SET-SERVICE AudioSrv -STARTUPTYPE DISABLED +SET-SERVICE SharedAccess -STARTUPTYPE DISABLED +SET-SERVICE WinRM -STARTUPTYPE DISABLED + + +# if there are some previous operations make OS require a restart, turn it off +Remove-Item -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager" -Name "PendingFileRenameOperations" -Force +Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired" -Force + +# wait 3s +Start-Sleep -Seconds 3 + + +# 代码的作用是为除了系统盘(C:)以外的所有逻辑磁盘添加权限,以便 SQL Server 和 MSSQL 账号可以访问这些磁盘 +$DISKLIST = GET-WMIOBJECT -CLASS WIN32_LOGICALDISK |WHERE-OBJECT {$_.DRIVETYPE -EQ 3}|SELECT-OBJECT -PROPERTY DEVICEID +FOREACH($DISK IN $DISKLIST) +{ + #add privileges + IF($DISK.DEVICEID -NE "C:") + { + $CMD = "ICACLS "+$DISK.DEVICEID+"\ /T /C /Q /GRANT mssql:(OI)(CI)F & ICACLS "+$DISK.DEVICEID+"\ /T /C /Q /GRANT sqlserver:(OI)(CI)F" + CMD /C $CMD + } +} + +#--------------------------------------- install action ------------------------------------------- +# 导入 ServerManager 模块 +IMPORT-MODULE SERVERMANAGER + diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/test.sql b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/test.sql new file mode 100644 index 0000000000..a388582180 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/core/staticembed/test.sql @@ -0,0 +1,13 @@ +USE MASTER +SET QUOTED_IDENTIFIER ON +SET NOCOUNT ON +GO + +DECLARE @SQL VARCHAR(8000) +SELECT @SQL = ISNULL(@SQL+' +','')+'EXEC SP_TRACE_SETSTATUS '+LTRIM(ID)+',0;EXEC SP_TRACE_SETSTATUS '+LTRIM(ID)+',2;' +FROM SYS.TRACES A +-- WHERE A.IS_DEFAULT = 0 +select @SQL +--EXEC(@SQL) +--GO diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/tools/tools.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/tools/tools.go new file mode 100644 index 0000000000..390699ba0d --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/tools/tools.go @@ -0,0 +1,12 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +// Package tools 外部工具 +package tools diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/auth/auth.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/auth/auth.go new file mode 100644 index 0000000000..ca85333e53 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/auth/auth.go @@ -0,0 +1,12 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +// Package auth 认证 +package auth diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/auth/jwt_token.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/auth/jwt_token.go new file mode 100644 index 0000000000..d92a771f77 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/auth/jwt_token.go @@ -0,0 +1,30 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package auth + +import ( + "time" + + "github.com/golang-jwt/jwt/v4" +) + +// Sign 签名加密 +func Sign(username string, secretId, secretKey string) (tokenString string, err error) { + // The token content. + token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ + "sub": secretId, + "user": username, + "iat": time.Now().Add(-1 * time.Minute).Unix(), + }) + // Sign the token with the specified secret. + tokenString, err = token.SignedString([]byte(secretKey)) + return +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/bkrepo/bkrepo.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/bkrepo/bkrepo.go new file mode 100644 index 0000000000..d5690b9845 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/bkrepo/bkrepo.go @@ -0,0 +1,301 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +// Package bkrepo TODO +package bkrepo + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "log" + "mime/multipart" + "net/http" + "net/url" + "os" + "path" + "path/filepath" + "strconv" + "strings" + + "dbm-services/common/go-pubpkg/logger" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/util" +) + +/* + API: GET /generic/{project}/{repo}/{path}?download=true + API 名称: download + 功能说明: + + 中文:下载通用制品文件 + English:download generic file + 请求体 此接口请求体为空 +*/ + +// BkRepoClient TODO +type BkRepoClient struct { + Client *http.Client + BkRepoProject string + BkRepoPubBucket string + BkRepoEndpoint string + BkRepoUser string + BkRepoPwd string +} + +// BkRepoRespone TODO +type BkRepoRespone struct { + Code int `json:"code"` + Message string `json:"message"` + Data json.RawMessage `json:"data"` + RequestId string `json:"request_id"` +} + +// getBaseUrl TODO +// +// @receiver b +func (b *BkRepoClient) getBaseUrl() string { + u, err := url.Parse(b.BkRepoEndpoint) + if err != nil { + log.Fatal(err) + } + u.Path = path.Join(u.Path, "generic", b.BkRepoProject, b.BkRepoPubBucket) + return u.String() +} + +// Download 从制品库下载文件 +// +// @receiver b +func (b *BkRepoClient) Download(sqlpath, filename, downloaddir string) (err error) { + uri := b.getBaseUrl() + path.Join("/", sqlpath, filename) + "?download=true" + logger.Info("The download uri %s", uri) + req, err := http.NewRequest(http.MethodGet, uri, nil) + if err != nil { + return err + } + if strings.Contains(filename, "..") { + return fmt.Errorf("%s 存在路径穿越风险", filename) + } + fileAbPath, err := filepath.Abs(path.Join(downloaddir, filename)) + if err != nil { + return err + } + f, err := os.Create(fileAbPath) + if err != nil { + return err + } + req.SetBasicAuth(b.BkRepoUser, b.BkRepoPwd) + resp, err := b.Client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + size, err := io.Copy(f, resp.Body) + if err != nil { + return err + } + logger.GetLogger().Info(fmt.Sprintf("Downloaded a file %s with size %d", filename, size)) + fileNodeInfo, err := b.QueryFileNodeInfo(sqlpath, filename) + if err != nil { + return err + } + + if size != int64(fileNodeInfo.Size) { + return fmt.Errorf("当前文件&源文件大小不一致,当前文件是:%d,制品库文件是:%d", size, fileNodeInfo.Size) + } + + currentFileMd5, err := util.GetFileMd5(fileAbPath) + if err != nil { + return err + } + if currentFileMd5 != fileNodeInfo.Md5 { + return fmt.Errorf("当前文件&源文件md5b不一致,当前文件是:%s,制品库文件是:%s", currentFileMd5, fileNodeInfo.Md5) + } + return nil +} + +// FileNodeInfo TODO +type FileNodeInfo struct { + Name string `json:"name"` + Sha256 string `json:"sha256"` + Md5 string `json:"md5"` + Size int `json:"size"` + Metadata map[string]string `json:"metadata"` +} + +// QueryFileNodeInfo TODO +// QueryMetaData 查询文件元数据信息 +// +// @receiver b +func (b *BkRepoClient) QueryFileNodeInfo(filepath, filename string) (realData FileNodeInfo, err error) { + var baseResp BkRepoRespone + uri := b.BkRepoEndpoint + path.Join("repository/api/node/detail/", b.BkRepoProject, b.BkRepoPubBucket, filepath, + filename) + req, err := http.NewRequest(http.MethodGet, uri, nil) + if err != nil { + return FileNodeInfo{}, err + } + resp, err := b.Client.Do(req) + if err != nil { + return FileNodeInfo{}, err + } + defer resp.Body.Close() + if err = json.NewDecoder(resp.Body).Decode(&baseResp); err != nil { + return FileNodeInfo{}, err + } + if baseResp.Code != 0 { + return FileNodeInfo{}, fmt.Errorf("bkrepo Return Code: %d,Messgae:%s", baseResp.Code, baseResp.Message) + } + if err = json.Unmarshal([]byte(baseResp.Data), &realData); err != nil { + return FileNodeInfo{}, err + } + return +} + +// UploadRespData TODO +type UploadRespData struct { + Sha256 string `json:"sha256"` + Md5 string `json:"md5"` + Size int64 `json:"size"` + FullPath string `json:"fullPath"` + CreateBy string `json:"createBy"` + CreateDate string `json:"createdDate"` + LastModifiedBy string `json:"lastModifiedBy"` + LastModifiedDate string `json:"lastModifiedDate"` + Folder bool `json:"folder"` // 是否为文件夹 + Path string `json:"path"` + Name string `json:"name"` + ProjectId string `json:"projectId"` + RepoName string `json:"repoName"` +} + +// FileServerInfo 文件服务器 +type FileServerInfo struct { + URL string `json:"url"` // 制品库地址 + Bucket string `json:"bucket"` // 目标bucket + Password string `json:"password"` // 制品库 password + Username string `json:"username"` // 制品库 username + Project string `json:"project"` // 制品库 project +} + +func newfileUploadRequest(uri string, params map[string]string, paramName, path string) (*http.Request, error) { + file, err := os.Open(path) + if err != nil { + return nil, err + } + defer file.Close() + + body := &bytes.Buffer{} + writer := multipart.NewWriter(body) + part, err := writer.CreateFormFile(paramName, filepath.Base(path)) + if err != nil { + return nil, err + } + _, err = io.Copy(part, file) + if err != nil { + return nil, err + } + for key, val := range params { + _ = writer.WriteField(key, val) + } + err = writer.Close() + if err != nil { + return nil, err + } + + req, err := http.NewRequest(http.MethodPut, uri, body) + req.Header.Set("Content-Type", writer.FormDataContentType()) + return req, err +} + +// UploadDirectToBkRepo TODO +func UploadDirectToBkRepo(filepath string, targetURL string, username string, password string) (*BkRepoRespone, error) { + logger.Info("start upload files from %s to %s", filepath, targetURL) + bodyBuf := bytes.NewBufferString("") + bodyWriter := multipart.NewWriter(bodyBuf) + fh, err := os.Open(filepath) + if err != nil { + logger.Info("error opening file") + return nil, err + } + boundary := bodyWriter.Boundary() + closeBuf := bytes.NewBufferString("") + + requestReader := io.MultiReader(bodyBuf, fh, closeBuf) + fi, err := fh.Stat() + if err != nil { + fmt.Printf("Error Stating file: %s", filepath) + return nil, err + } + req, err := http.NewRequest("PUT", targetURL, requestReader) + if err != nil { + return nil, err + } + req.SetBasicAuth(username, password) + // Set headers for multipart, and Content Length + req.Header.Set("Content-Type", "multipart/form-data; boundary="+boundary) + // 文件是否可以被覆盖,默认false + req.Header.Set("X-BKREPO-OVERWRITE", "True") + // 文件默认保留半年 + req.Header.Set("X-BKREPO-EXPIRES", "183") + req.ContentLength = fi.Size() + int64(bodyBuf.Len()) + int64(closeBuf.Len()) + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("返回码非200 %d", resp.StatusCode) + } + var baseResp BkRepoRespone + if err = json.NewDecoder(resp.Body).Decode(&baseResp); err != nil { + return nil, err + } + return &baseResp, err +} + +// UploadFile 上传文件到蓝盾制品库 +// filepath: 本地需要上传文件的路径 +// targetURL: 仓库文件完整路径 +func UploadFile(filepath string, targetURL string, username string, password string, BkCloudId int, + DBCloudToken string) (*BkRepoRespone, error) { + logger.Info("start upload files from %s to %s", filepath, targetURL) + if BkCloudId == 0 { + return UploadDirectToBkRepo(filepath, targetURL, username, password) + } + req, err := newfileUploadRequest(targetURL, map[string]string{ + "bk_cloud_id": strconv.Itoa(BkCloudId), + "db_cloud_token": DBCloudToken, + }, "file", filepath) + if err != nil { + logger.Error("new request failed %s", err.Error()) + return nil, err + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body := &bytes.Buffer{} + _, err = body.ReadFrom(resp.Body) + if err != nil { + logger.Error("read from body failed %s", err.Error()) + return nil, err + } + logger.Info("respone body:%s", body.String()) + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("返回码非200 %d,Message:%s", resp.StatusCode, body.String()) + } + var baseResp BkRepoRespone + if err = json.NewDecoder(body).Decode(&baseResp); err != nil { + return nil, err + } + return &baseResp, err +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/bkrepo/bkrepo_test.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/bkrepo/bkrepo_test.go new file mode 100644 index 0000000000..8275e6a3f8 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/bkrepo/bkrepo_test.go @@ -0,0 +1,21 @@ +package bkrepo_test + +import ( + "net/url" + "path" + "testing" + + "dbm-services/sqlserver/db-tools/dbactuator/pkg/util/bkrepo" +) + +func TestUploadFile(t *testing.T) { + t.Log("start...") + r, err := url.Parse(path.Join("/generic", "/")) + t.Log(r.String()) + resp, err := bkrepo.UploadFile("/tmp/1.sql", "", "", "", 0, "") + if err != nil { + t.Log(err.Error()) + return + } + t.Log(resp) +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/filelock.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/filelock.go new file mode 100644 index 0000000000..fb70cbbd22 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/filelock.go @@ -0,0 +1,209 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package util + +import ( + "fmt" + "io/ioutil" + "os" + "strconv" + "strings" + "sync" + "time" + + "github.com/gofrs/flock" + "github.com/pkg/errors" +) + +// FLock TODO +type FLock struct { + fileName string + file *os.File + filedataName string + filedata *os.File + filedataMax int +} + +// NewFlock TODO +func NewFlock(filename string, maxConn int) (*FLock, error) { + // maxConn cannot be 0 + + // check filedataName lastModifyTime + // 如果 filedataName 文件最后修改时间在 1h 以前,删掉这个文件 + + if strings.ContainsAny(filename, " ;'\"") { + // 非法文件名 + return nil, fmt.Errorf("illegal filename:%s", filename) + } else if maxConn == 0 { + return nil, fmt.Errorf("illegal maxConn:%d", maxConn) + } + + filedataName := filename + ".data" + if ok, mtimeInt := GetFileModifyTime(filedataName); ok { + curTime := time.Now() + mtime := time.Unix(mtimeInt, 0) + timeDiff := curTime.Sub(mtime) + if timeDiff.Minutes() > 60 { + os.Remove(filedataName) + } + } + + fl := &FLock{ + fileName: filename, + filedataName: filedataName, + filedataMax: maxConn, + } + + return fl, nil +} + +// FileFlock TODO +func (fl *FLock) FileFlock() (locked bool, err error) { + if fl.fileName == "" { + return false, errors.New("fileLock filename canot be empty") + } + fileLock := flock.New(fl.fileName) + return fileLock.TryLock() +} + +// FileUnlock TODO +func (fl *FLock) FileUnlock() error { + fileLock := flock.New(fl.fileName) + return fileLock.Unlock() +} + +// SetFileLockIncr TODO +func (fl *FLock) SetFileLockIncr(incr int) (succ int, err error) { + f, err := os.OpenFile(fl.filedataName, os.O_CREATE|os.O_RDWR, 0644) + if err == nil { + defer f.Close() + } + content, err := ioutil.ReadAll(f) + contentStr := strings.Trim(strings.ReplaceAll(string(content), " ", ""), "\n") + if err != nil { + return -1, fmt.Errorf(`io error:%v`, err.Error()) + } else if contentStr == "" { + contentStr = fmt.Sprintf(`%d:0`, fl.filedataMax) + } + concurrent := strings.Split(contentStr, ":") + if len(concurrent) != 2 { + return -1, fmt.Errorf(`error:contentStr=%s`, contentStr) + } + maxNum, err1 := strconv.Atoi(concurrent[0]) + CurNum, err2 := strconv.Atoi(concurrent[1]) + if err1 == nil && err2 == nil { + CurNum += incr + if CurNum > maxNum && incr > 0 { + // lock fail + return 0, nil + } + if CurNum < 0 { + CurNum = 0 + } + contentStr = fmt.Sprintf(`%d:%d`, maxNum, CurNum) + f.Seek(0, 0) + f.Truncate(0) + f.WriteString(contentStr) + return 1, nil + } else { + return -1, fmt.Errorf(`error:contentStr=%s`, contentStr) + } +} + +// FileIncrSafe TODO +// retryInterval: 如果获取锁失败,下次重试间隔(秒)。为 0 时表示不重试,麻烦返回获取锁失败 +// retcode: +// 1: success incr +// 0: full +// -1: operation failed +func (fl *FLock) FileIncrSafe(incr int, retryInterval int) (succ int, err error) { + intvl := time.Duration(retryInterval) + + fileLock := flock.New(fl.fileName) + locked, err := fileLock.TryLock() + + if err != nil { + // handle locking error + return -1, errors.New(fmt.Sprintf("failed to get lock: %s", err.Error())) + } + if locked { + // open and incr 1 and close + succ, err2 := fl.SetFileLockIncr(incr) + fileLock.Unlock() + if succ == 1 { + /* + if err = fileLock.Unlock(); err != nil { + // handle unlock error + return false, errors.New(fmt.Sprintf(`failed to unlock: %s`, err.Error())) + } + */ + return 1, nil + } else if succ == 0 { + if retryInterval == 0 { + return 0, nil + } else { + time.Sleep(intvl * time.Second) + return fl.FileIncrSafe(incr, retryInterval) + } + } else { + return -1, errors.New(fmt.Sprintf("failed to incr: %s", err2.Error())) + } + + } else { + // wait and retry + if retryInterval == 0 { + return 0, nil + } else { + // lockWaitMs := IntnRange(500, 3000) + // time.Sleep(time.Duration(lockWaitMs) * time.Millisecond) + time.Sleep(time.Duration(IntnRange(500, 3000)) * time.Millisecond) + return fl.FileIncrSafe(incr, retryInterval) + } + } + return 1, nil +} + +// FileUnlockIncr TODO +func (fl *FLock) FileUnlockIncr(filename string) error { + fileLock := flock.New(filename) + return fileLock.Unlock() +} + +// Test TODO +func Test() { + filename := "flashback.lock" + maxConn := 4 + fl, err := NewFlock(filename, maxConn) + if err != nil { + fmt.Println(err) + return + } + + wg := &sync.WaitGroup{} + for i := 0; i <= 8; i++ { + fmt.Println(i) + wg.Add(1) + go func(i int) { + time.Sleep(time.Duration(IntnRange(100, 2000)) * time.Millisecond) + defer wg.Done() + // 这个 retryInterval 尽量跟单个任务处理时间接近 + if succ, err := fl.FileIncrSafe(1, 20); succ == 1 { + // do + fmt.Printf("id=%d\n", i) + time.Sleep(20 * time.Second) + fl.FileIncrSafe(-1, 1) + } else if err != nil { + fmt.Printf("id=%d err=%v\n", i, err.Error()) + } + }(i) + } + wg.Wait() +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/helpers.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/helpers.go new file mode 100644 index 0000000000..e5adfbf4c5 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/helpers.go @@ -0,0 +1,63 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package util + +import ( + "fmt" + "os" + "strings" + + "dbm-services/common/go-pubpkg/logger" +) + +const ( + // DefaultErrorExitCode TODO + DefaultErrorExitCode = 1 +) + +// CheckErr TODO +func CheckErr(err error) { + if err == nil { + return + } + msg, ok := StandardErrorMessage(err) + if !ok { + msg = err.Error() + if !strings.HasPrefix(msg, "error: ") { + msg = fmt.Sprintf("error: %s", msg) + } + } + LoggerErrorStack(logger.Error, err) + fatal(msg, DefaultErrorExitCode) +} + +func fatal(msg string, code int) { + if len(msg) > 0 { + // add newline if needed + if !strings.HasSuffix(msg, "\n") { + msg += "\n" + } + fmt.Fprint(os.Stderr, msg) + } + os.Exit(code) +} + +type debugError interface { + DebugError() (msg string, args []interface{}) +} + +// StandardErrorMessage TODO +func StandardErrorMessage(err error) (string, bool) { + if debugErr, ok := err.(debugError); ok { + logger.Info(debugErr.DebugError()) + } + return "", false +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/logger.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/logger.go new file mode 100644 index 0000000000..59cf9dcac2 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/logger.go @@ -0,0 +1,20 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package util + +// LoggerErrorStack 在最外层遇到 error 时打印 stack 信息到日志 +// err == nil 时不打印 +// output 是个 logger,避免在 util 里引入 logger导致循环 import +func LoggerErrorStack(output func(format string, args ...interface{}), err error) { + if err != nil { + output("%+v", err) + } +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil/cmdexec.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil/cmdexec.go new file mode 100644 index 0000000000..97c5bd99db --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil/cmdexec.go @@ -0,0 +1,148 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package osutil + +import ( + "bytes" + "os" + "os/exec" + "strings" + + "dbm-services/common/go-pubpkg/logger" + + "github.com/pkg/errors" +) + +// FileOutputCmd 封装exec.Command,用于执行命令并输出到文件的场景,支持自动将输出文件上传到文件服务器(尽可能上传,如果上传失败则返回原文件) +type FileOutputCmd struct { + exec.Cmd + StdOutFile string + StdErrFile string + + stdOutFile *os.File + stdErrFile *os.File + stdOutDownloadLink string + stdErrDownloadLink string +} + +// GetStdOutDownloadLink TODO +func (c *FileOutputCmd) GetStdOutDownloadLink() string { + return c.stdOutDownloadLink +} + +// GetStdErrDownloadLink TODO +func (c *FileOutputCmd) GetStdErrDownloadLink() string { + return c.stdErrDownloadLink +} + +func (c *FileOutputCmd) initOutputFile() error { + if c.StdErrFile == "" { + c.StdErrFile = c.StdOutFile + } + if c.StdOutFile != "" { + stdOutFile, err := os.OpenFile(c.StdOutFile, os.O_CREATE|os.O_WRONLY, os.ModePerm) + if err != nil { + return errors.Wrapf(err, "open std out log file %s failed", c.StdOutFile) + } + c.stdOutFile = stdOutFile + c.Cmd.Stdout = stdOutFile + } + + if c.StdOutFile == c.StdErrFile { + c.stdErrFile = nil + c.Cmd.Stderr = c.stdOutFile + return nil + } + + if c.StdErrFile != "" { + stdErrFile, err := os.OpenFile(c.StdErrFile, os.O_CREATE|os.O_WRONLY, os.ModePerm) + if err != nil { + return errors.Wrapf(err, "open std err log file %s failed", c.StdErrFile) + } + c.stdErrFile = stdErrFile + c.Cmd.Stderr = stdErrFile + } + return nil +} + +func (c *FileOutputCmd) closeOutputFile() { + if c.stdOutFile != nil { + if err := c.stdOutFile.Close(); err != nil { + logger.Warn("close %s failed, err:%s", c.StdOutFile, err.Error()) + } + } + if c.stdErrFile != nil { + if err := c.stdErrFile.Close(); err != nil { + logger.Warn("close %s failed, err:%s", c.StdErrFile, err.Error()) + } + } + // UploadPath? +} + +// Run TODO +func (c *FileOutputCmd) Run() error { + if err := c.initOutputFile(); err != nil { + return err + } + + defer func() { + c.closeOutputFile() + }() + + return c.Cmd.Run() +} + +// Start TODO +func (c *FileOutputCmd) Start() error { + if err := c.initOutputFile(); err != nil { + return err + } + + return c.Cmd.Start() +} + +// Wait TODO +func (c *FileOutputCmd) Wait() error { + defer func() { + c.closeOutputFile() + }() + + return c.Cmd.Wait() +} + +// CleanExecOutput TODO +func CleanExecOutput(s string) string { + return strings.ReplaceAll(strings.TrimSpace(s), "\n", "") +} + +// StandardPowerShellCommand TODO +func StandardPowerShellCommand(param string) (stdoutStr string, err error) { + var stdout, stderr bytes.Buffer + cmd := exec.Command("powershell", "-Command", param) + cmd.Stdout = &stdout + cmd.Stderr = &stderr + err = cmd.Run() + if err != nil { + return stderr.String(), errors.WithMessage(err, stderr.String()) + } + return stdout.String(), nil +} + +// StandardPowerShellCommands TODO +func StandardPowerShellCommands(params []string) (stdoutStr string, err error) { + for _, param := range params { + ret, err := StandardPowerShellCommand(param) + if err != nil { + return ret, err + } + } + return "", nil +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil/create_cnf.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil/create_cnf.go new file mode 100644 index 0000000000..fa94bc0974 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil/create_cnf.go @@ -0,0 +1,49 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package osutil + +import ( + "encoding/json" + "fmt" + "os" + "strings" +) + +// CreateInstallConf 根据传入的配置json,以及配置文件位置,本地生成配置文件 +func CreateInstallConf(conf []byte, confFile string, version string) error { + var m map[string]interface{} + err := json.Unmarshal(conf, &m) + if err != nil { + return err + } + + file, err := os.Create(confFile) + if err != nil { + return err + } + defer file.Close() + + // 这里写入配置文件的类别,不同版本类别名称都不一样 + title := "[OPTIONS]" + if strings.Contains(version, "2008") { + title = "[SQLSERVER2008]" + } + file.WriteString(title) + + for key, value := range m { + line := fmt.Sprintf("%s=\"%v\"\n", key, value) + _, err = file.WriteString(line) + if err != nil { + return err + } + } + return nil +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil/osutil.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil/osutil.go new file mode 100644 index 0000000000..205247d086 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil/osutil.go @@ -0,0 +1,147 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +// Package osutil TODO +package osutil + +import ( + "bytes" + "fmt" + "io" + "os" + "path/filepath" + "regexp" + "strconv" + "strings" +) + +// StringToMap 字符串 TO map +// 如db1,,db2,db3,db2 ,等去重并转换成db1,db2,db3 +func StringToMap(srcStr string, seq string) map[string]struct{} { + splitReg := regexp.MustCompile(seq) + strList := splitReg.Split(srcStr, -1) + strMap := make(map[string]struct{}) + for _, str := range strList { + if len(strings.TrimSpace(str)) == 0 { + continue + } + strMap[strings.TrimSpace(str)] = struct{}{} + } + return strMap +} + +// FileExist TODO +func FileExist(fileName string) bool { + _, err := os.Stat(fileName) + if err != nil { + return os.IsExist(err) + } + return true +} + +// SplitName 切分用户传过来的IP字符串列表等 +// 切分规则: +// 把\r+|\s+|;+|\n+|,+这些分隔符,转成字符串数组 +// 返回字符串数组 +func SplitName(input string) ([]string, error) { + if reg, err := regexp.Compile(`\r+|\s+|;+|\n+`); err != nil { + return nil, err + } else { + input = reg.ReplaceAllString(input, ",") + } + if reg, err := regexp.Compile(`^,+|,+$`); err != nil { + return nil, err + } else { + input = reg.ReplaceAllString(input, "") + } + if reg, err := regexp.Compile(`,+`); err != nil { + return nil, err + } else { + input = reg.ReplaceAllString(input, ",") + } + result := strings.Split(input, ",") + return result, nil +} + +// Uniq 对字符串数组进行去重 +func Uniq(input []string) []string { + var newData []string + if len(input) > 0 { + temp := map[string]bool{} + for _, value := range input { + temp[value] = true + } + for k := range temp { + newData = append(newData, k) + } + } + return newData +} + +// WrapFileLink TODO +func WrapFileLink(link string) string { + name := filepath.Base(link) + return fmt.Sprintf(`%s`, link, name) +} + +// CapturingPassThroughWriter is a writer that remembers +// data written to it and passes it to w +type CapturingPassThroughWriter struct { + buf bytes.Buffer + w io.Writer +} + +// NewCapturingPassThroughWriter creates new CapturingPassThroughWriter +func NewCapturingPassThroughWriter(w io.Writer) *CapturingPassThroughWriter { + return &CapturingPassThroughWriter{ + w: w, + } +} + +// Write 用于常见IO +func (w *CapturingPassThroughWriter) Write(d []byte) (int, error) { + w.buf.Write(d) + return w.w.Write(d) +} + +// Bytes returns bytes written to the writer +func (w *CapturingPassThroughWriter) Bytes() []byte { + return w.buf.Bytes() +} + +// ReadFileString TODO +func ReadFileString(filename string) (string, error) { + if body, err := os.ReadFile(filename); err != nil { + return "", err + } else { + return string(body), nil + } +} + +// GetInstallName 根据端口号拼接sqlserver的实例名称,比如48322,那么端口号是S48322 +func GetInstallName(port int) string { + return fmt.Sprintf("S%d", port) +} + +// GetVersionYears 根据版本号信息提取版本年份 +func GetVersionYears(SQlServerVersion string) (int, error) { + re := regexp.MustCompile(`\d+`) + match := re.FindString(SQlServerVersion) + num, err := strconv.Atoi(match) + if err != nil { + return 0, fmt.Errorf("Error converting string to int:", err) + } + return num, nil +} + +// GetInstallPackageName 根据端口号拼接sqlserver的实例名称,比如48322,那么端口号是S48322 +func GetInstallPackageName(version string) string { + return fmt.Sprintf("%s_SorceMedia", version) +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil/osutil_test.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil/osutil_test.go new file mode 100644 index 0000000000..6691898ce3 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil/osutil_test.go @@ -0,0 +1,56 @@ +package osutil_test + +import ( + "bytes" + "encoding/json" + "html/template" + "testing" + + "dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil" +) + +func TestIsFileExist(t *testing.T) { + f := "/tmp/1.txt" + d := "/tmp/asdad/" + exist_f := osutil.FileExist(f) + exist_d := osutil.FileExist(d) + t.Log("f exist", exist_f) + t.Log("d exist", exist_d) +} + +func Test(t *testing.T) { + type Person struct { + Name string `json:"name"` + Age int `json:"age"` + } + + jsonData := `{"name": "John", "age": 30}` + + var p Person + err := json.Unmarshal([]byte(jsonData), &p) + if err != nil { + panic(err) + } + + t.Log(p.Name) + t.Log(p.Age) + + conf := []byte(`{"name": "{{.Name}}", "age": {{.Age}}, "a":1}`) + t.Log(string(conf)) + tmpl := template.Must(template.New("mytemplate").Parse(string(conf))) + + var rendered bytes.Buffer + err = tmpl.Execute(&rendered, p) + if err != nil { + t.Log(err) + } + t.Log(rendered.String()) + var m map[string]interface{} + _ = json.Unmarshal([]byte(rendered.String()), &m) + t.Log(m) + for key, value := range m { + t.Log(key) + t.Log(value) + } + +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil/wins_file.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil/wins_file.go new file mode 100644 index 0000000000..6a4fcddd2e --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil/wins_file.go @@ -0,0 +1,71 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package osutil + +import ( + "fmt" + "os" + "os/exec" + + "dbm-services/common/go-pubpkg/logger" +) + +// WINSFile 定义window文件/目录的结构体 +type WINSFile struct { + FileName string +} + +// FileExists 判断文件是否存在 +func (f *WINSFile) FileExists() (error, bool) { + _, err := os.Stat(f.FileName) + if os.IsNotExist(err) { + return nil, false + } else if err != nil { + return err, false + } + return nil, true +} + +// Create 文件/目录创建 +func (f *WINSFile) Create(mode os.FileMode) bool { + err := os.MkdirAll(f.FileName, mode) + if err != nil { + logger.Error(err.Error()) + return false + } + return true +} + +// SetChmod 设置目录/文件权限 +func (f *WINSFile) SetChmod(mode os.FileMode) bool { + err := os.Chmod(f.FileName, mode) + if err != nil { + logger.Error(err.Error()) + return false + } + return true +} + +// SetChown 设置目录/文件的所属者 +func (f *WINSFile) SetChown(user string) bool { + cmd := exec.Command( + "powershell", + "-Command", + fmt.Sprintf("icacls %s /setowner %s /T /C", f.FileName, user), + ) + err := cmd.Run() + if err != nil { + logger.Error(err.Error()) + return false + } + logger.Info(fmt.Sprintf("icacls %s /setowner %s /T /C successfully", f.FileName, user)) + return true +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil/wins_os_user.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil/wins_os_user.go new file mode 100644 index 0000000000..4e233641c5 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil/wins_os_user.go @@ -0,0 +1,155 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package osutil + +import ( + "fmt" + "strings" + + "dbm-services/common/go-pubpkg/logger" +) + +// WINSOSUser 定义windows用户的结构体 +type WINSOSUser struct { + User string + Pass string + Comment string +} + +// UserExists 定义判断windows系统用户是否存在的方法 +func (w *WINSOSUser) UserExists() bool { + + output, err := StandardPowerShellCommand( + fmt.Sprintf("(Get-WmiObject -Class Win32_UserAccount -Filter \"Name='%s'\").Name", w.User), + ) + if err != nil { + logger.Error(err.Error()) + return false + } + if strings.TrimSpace(string(output)) == w.User { + return true + } else { + return false + } +} + +// AddGroupMember TODO +// AddGroups 定义用户添加某个用户组 +func (w *WINSOSUser) AddGroupMember(groupName string) error { + + // 判断用户是否在该组 + if w.IsExistInGroup(groupName) { + logger.Info("The user [%s] in this group [%s], skip", w.User, groupName) + return nil + } + _, err := StandardPowerShellCommand( + fmt.Sprintf("Add-LocalGroupMember -Group '%s' -Member '%s'", groupName, w.User), + ) + if err != nil { + return err + } + logger.Info(fmt.Sprintf("Add system user [%s] in group [%s] successfully", w.User, groupName)) + return nil +} + +// RemoveGroupMember 定义用户移除出某个用户组 +func (w *WINSOSUser) RemoveGroupMember(groupName string) error { + + // 判断用户是否在该组 + if !w.IsExistInGroup(groupName) { + logger.Info("The user [%s] not in this group [%s], skip", w.User, groupName) + return nil + } + _, err := StandardPowerShellCommand( + fmt.Sprintf("Remove-LocalGroupMember -Group '%s' -Member '%s'", groupName, w.User), + ) + if err != nil { + return err + } + logger.Info(fmt.Sprintf("Add system user [%s] has successfully removed the group [%s]", w.User, groupName)) + return nil +} + +// CreateUser 定义创建系统用户的方法 +func (w *WINSOSUser) CreateUser(isTranAdmin bool) error { + // 创建账号,账号默认在内置的Users组 + + _, err := StandardPowerShellCommand( + fmt.Sprintf( + "New-LocalUser -Name '%s' -Password (ConvertTo-SecureString '%s' -AsPlainText -Force) -Description '%s'", + w.User, w.Pass, w.Comment), + ) + if err != nil { + return err + } + logger.Info(fmt.Sprintf("Create system user [%s] successfully", w.User)) + if isTranAdmin { + // 判断加入系统内置管理组 + err := w.AddGroupMember("Administrators") + if err != nil { + return err + } + } + return nil +} + +// DropUser 定义删除系统用户的方法 +func (w *WINSOSUser) DropUser() error { + // 创建账号,账号不存在默认不报错 + + _, err := StandardPowerShellCommand( + fmt.Sprintf("Remove-LocalUser -Name '%s' -ErrorAction SilentlyContinue", w.User), + ) + if err != nil { + return err + } + + logger.Info(fmt.Sprintf("drop system user [%s] successfully", w.User)) + + return nil +} + +// SetUerPass 定义设置系统用户的密码的方法 +func (w *WINSOSUser) SetUerPass() error { + // 创建账号,账号不存在默认不报错 + + _, err := StandardPowerShellCommand( + fmt.Sprintf( + "Set-LocalUser -Name '%s' -Password (ConvertTo-SecureString '%s' -AsPlainText -Force) ", + w.User, + w.Pass, + ), + ) + if err != nil { + return err + } + + logger.Info(fmt.Sprintf("System user [%s]set password successfully ", w.User)) + return nil +} + +// IsExistInGroup 判断用户是否在某个用户组的方法 +func (w *WINSOSUser) IsExistInGroup(groupName string) bool { + output, err := StandardPowerShellCommand( + fmt.Sprintf( + "(Get-LocalGroupMember -group %s | Where-Object { $_.Name -like '*\\%s' -and $_.ObjectClass -eq 'User'}).Name", + groupName, w.User), + ) + if err != nil { + logger.Error(err.Error()) + return false + } + if string(output) != "" { + return true + } else { + return false + } +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil/wins_regedit.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil/wins_regedit.go new file mode 100644 index 0000000000..b3c2bf7e1b --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil/wins_regedit.go @@ -0,0 +1,70 @@ +//go:build windows +// +build windows + +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package osutil + +import ( + "dbm-services/common/go-pubpkg/logger" + "fmt" + + "golang.org/x/sys/windows/registry" +) + +// WINSRegItem 定义window注册表的结构体 +type WINSRegItem struct { + ItemRootKey registry.Key +} + +// ReadIiem 读取注册表项是否存在某个key +func (i *WINSRegItem) ReadIiem(ItemKeyPath string, ItemName string) (error, string) { + // 读取注册表项,能读取成功则证明存在 + key, err := registry.OpenKey(i.ItemRootKey, ItemKeyPath, registry.READ) + if err != nil { + return err, "" + } + defer key.Close() + value, _, err := key.GetStringValue(ItemName) + if err != nil { + return err, "" + } + + return nil, value +} + +// SetItem 注册表项下某个key的value +func (i *WINSRegItem) SetItem(ItemKeyPath string, ItemName string, SetVaule string) error { + // 读取注册表项 + key, err := registry.OpenKey(i.ItemRootKey, ItemKeyPath, registry.SET_VALUE) + if err != nil { + return err + } + defer key.Close() + err = key.SetStringValue(ItemName, SetVaule) + if err != nil { + return err + } + logger.Info(fmt.Sprintf("the reg key [%s\\%s\\%s] Set: [%s] successfully", i.ItemRootKey, ItemKeyPath, ItemName, + SetVaule)) + return nil +} + +// RemoveItem 删除注册表项 +func (i *WINSRegItem) RemoveItem(ItemKeyPath string) error { + // 读取注册表项 + err := registry.DeleteKey(i.ItemRootKey, ItemKeyPath) + if err != nil { + return err + } + logger.Info(fmt.Sprintf("the reg key [%s\\%s] delete successfully", i.ItemRootKey, ItemKeyPath)) + return nil +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/random/random.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/random/random.go new file mode 100644 index 0000000000..a3b8c55c3c --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/random/random.go @@ -0,0 +1,12 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +// Package random TODO +package random diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/random/randstring.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/random/randstring.go new file mode 100644 index 0000000000..ad59a41f6b --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/random/randstring.go @@ -0,0 +1,37 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package random + +import ( + "math/rand" + "time" +) + +var defaultLetters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") + +// RandomString returns a random string with a fixed length +func RandomString(n int, allowedChars ...[]rune) string { + var letters []rune + rand.Seed(time.Now().UnixNano()) + + if len(allowedChars) == 0 { + letters = defaultLetters + } else { + letters = allowedChars[0] + } + + b := make([]rune, n) + for i := range b { + b[i] = letters[rand.Intn(len(letters))] + } + + return string(b) +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/sizebytes.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/sizebytes.go new file mode 100644 index 0000000000..997ef5e192 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/sizebytes.go @@ -0,0 +1,91 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package util + +import ( + "strings" + "unicode" + + "github.com/pkg/errors" + "github.com/spf13/cast" + "github.com/spf13/viper" +) + +// ViperGetSizeInBytes TODO +func ViperGetSizeInBytes(key string) int64 { + return ParseSizeInBytes(viper.GetString(key)) +} + +// ViperGetSizeInBytesE TODO +func ViperGetSizeInBytesE(key string) (int64, error) { + return ParseSizeInBytesE(viper.GetString(key)) +} + +// ParseSizeInBytesE converts strings like 1GB or 12 mb into an unsigned integer number of bytes +// withB indicate where sizeStr has suffix b/B +func ParseSizeInBytesE(sizeStr string) (int64, error) { + sizeStr = strings.TrimSpace(sizeStr) + if unicode.ToLower(rune(sizeStr[len(sizeStr)-1])) != 'b' { + sizeStr += "b" + } + lastChar := len(sizeStr) - 1 + multiplier := uint(1) + if lastChar > 0 { + if sizeStr[lastChar] == 'b' || sizeStr[lastChar] == 'B' { + if lastChar > 1 { + switch unicode.ToLower(rune(sizeStr[lastChar-1])) { + case 'k': + multiplier = 1 << 10 + sizeStr = strings.TrimSpace(sizeStr[:lastChar-1]) + case 'm': + multiplier = 1 << 20 + sizeStr = strings.TrimSpace(sizeStr[:lastChar-1]) + case 'g': + multiplier = 1 << 30 + sizeStr = strings.TrimSpace(sizeStr[:lastChar-1]) + default: + multiplier = 1 + sizeStr = strings.TrimSpace(strings.TrimSuffix(sizeStr, "b")) + } + } else if lastChar == 1 { + multiplier = 1 + sizeStr = strings.TrimSpace(strings.TrimSuffix(sizeStr, "b")) + } + } + } + size, err := cast.ToInt64E(sizeStr) + if err != nil { + return -1, errors.Errorf("parse failed to bytes: %s", sizeStr) + } else if size < 0 { + return -2, errors.Errorf("bytes canot be negative: %s", sizeStr) + } + return safeMul(size, int64(multiplier)), nil +} + +func safeMul(a, b int64) int64 { + c := a * b + if a > 1 && b > 1 && c/b != a { + return 0 + } + return c +} + +// ParseSizeInBytes 将 gb, MB 转换成 bytes 数字. b 不区分大小写,代表 1字节 +// ignore error +func ParseSizeInBytes(sizeStr string) int64 { + sizeBytes, err := ParseSizeInBytesE(sizeStr) + if err != nil { + sizeBytes = 0 + } else if sizeBytes < 0 { + sizeBytes = 0 + } + return sizeBytes +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/slice.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/slice.go new file mode 100644 index 0000000000..e4891c8f10 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/slice.go @@ -0,0 +1,282 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package util + +import ( + "fmt" + "reflect" + "sort" + "strconv" + "strings" + + "github.com/pkg/errors" +) + +// IntsHas check the []int contains the given value +func IntsHas(ints []int, val int) bool { + for _, ele := range ints { + if ele == val { + return true + } + } + return false +} + +// Int64sHas check the []int64 contains the given value +func Int64sHas(ints []int64, val int64) bool { + for _, ele := range ints { + if ele == val { + return true + } + } + return false +} + +// StringsHas check the []string contains the given element +func StringsHas(ss []string, val string) bool { + for _, ele := range ss { + if ele == val { + return true + } + } + return false +} + +// StringsHasICase check the []string contains the given element. insensitive case +func StringsHasICase(ss []string, val string) bool { + val = strings.ToLower(val) + for _, ele := range ss { + if strings.ToLower(ele) == val { + return true + } + } + return false +} + +// UniqueStrings Returns unique items in a slice +func UniqueStrings(slice []string) []string { + // create a map with all the values as key + uniqMap := make(map[string]struct{}) + for _, v := range slice { + uniqMap[v] = struct{}{} + } + + // turn the map keys into a slice + uniqSlice := make([]string, 0, len(uniqMap)) + for v := range uniqMap { + uniqSlice = append(uniqSlice, v) + } + return uniqSlice +} + +// UniqueInts Returns unique items in a slice +func UniqueInts(slice []int) []int { + // create a map with all the values as key + uniqMap := make(map[int]struct{}) + for _, v := range slice { + uniqMap[v] = struct{}{} + } + + // turn the map keys into a slice + uniqSlice := make([]int, 0, len(uniqMap)) + for v := range uniqMap { + uniqSlice = append(uniqSlice, v) + } + return uniqSlice +} + +// IsConsecutiveStrings 是否是连续数字 +// 如果存在 空元素 则报错 +func IsConsecutiveStrings(strList []string, isNumber bool) error { + err := errors.New("not consecutive numbers") + intList := make([]int, len(strList)) + if !isNumber { + // string to ascii + // .aa .ab .ac => 469797 469798 469799 + for i, s := range strList { + ss := "" + for _, si := range []rune(s) { + ss += strconv.FormatInt(int64(si), 10) + } + // todo ss 不能超过20位 + strList[i] = ss + } + } + for i, s := range strList { + if d, e := strconv.Atoi(s); e != nil { + return errors.Errorf("illegal number %s", s) + } else { + intList[i] = d + } + } + intList = UniqueInts(intList) + sort.Ints(intList) + count := len(intList) + if (intList[count-1] - intList[0] + 1) != count { + return err + } + return nil +} + +// RemoveEmpty 过滤掉空字符串 +func RemoveEmpty(input []string) []string { + var result []string + for _, item := range input { + if strings.TrimSpace(item) != "" { + result = append(result, item) + } + } + return result +} + +// StringSliceToInterfaceSlice 把字符串数组转换为interface{}数组 +func StringSliceToInterfaceSlice(ids []string) []interface{} { + var result []interface{} + if len(ids) == 1 { + result = append(result, ids[0]) + } else { + for i := 0; i < len(ids); i++ { + result = append(result, ids[i]) + } + } + return result +} + +// StringsRemove an value form an string slice +func StringsRemove(ss []string, s string) []string { + var ns []string + for _, v := range ss { + if v != s { + ns = append(ns, v) + } + } + + return ns +} + +// StringsInsertAfter 在 slice 里插入某个元素之后,仅匹配一次 +// 如果没有找到元素,忽略 +func StringsInsertAfter(ss []string, old string, new string) []string { + var ssNew = make([]string, len(ss)+1) + var found bool + for i, v := range ss { + if found { + ssNew[i+1] = v + } else if v == old { + ssNew[i] = v + ssNew[i+1] = new + found = true + } else { + ssNew[i] = v + } + } + if !found { + return ssNew[:len(ss)] + } + return ssNew +} + +// StringsInsertIndex 在 slice index 当前位置,插入一个元素 +// 如果 index 非法,则忽略 +func StringsInsertIndex(ss []string, index int, new string) []string { + if index < 0 || index > len(ss)-1 { + return ss + } + var ssNew = make([]string, len(ss)+1) + for i, v := range ss { + if i > index { + ssNew[i+1] = v + } else if i < index { + ssNew[i] = v + } else { + ssNew[i] = new + ssNew[i+1] = v + } + } + return ssNew +} + +// FilterOutStringSlice 滤除scr中含有filters 里面元素的数组 +// +// @receiver src +// @receiver filters +// @return dst +func FilterOutStringSlice(src []string, filters []string) (dst []string) { + for _, v := range src { + if !StringsHas(filters, v) { + dst = append(dst, v) + } + } + return +} + +// RemoveNilElements TODO +func RemoveNilElements(v []interface{}) []interface{} { + newSlice := make([]interface{}, 0, len(v)) + for _, i := range v { + if i != nil { + newSlice = append(newSlice, i) + } + } + return newSlice +} + +// StrVal TODO +func StrVal(v interface{}) string { + switch v := v.(type) { + case string: + return v + case []byte: + return string(v) + case error: + return v.Error() + case fmt.Stringer: + return v.String() + default: + return fmt.Sprintf("%v", v) + } +} + +// StrSlice TODO +func StrSlice(v interface{}) []string { + switch v := v.(type) { + case []string: + return v + case []interface{}: + b := make([]string, 0, len(v)) + for _, s := range v { + if s != nil { + b = append(b, StrVal(s)) + } + } + return b + default: + val := reflect.ValueOf(v) + switch val.Kind() { + case reflect.Array, reflect.Slice: + l := val.Len() + b := make([]string, 0, l) + for i := 0; i < l; i++ { + value := val.Index(i).Interface() + if value != nil { + b = append(b, StrVal(value)) + } + } + return b + default: + if v == nil { + return []string{} + } + + return []string{StrVal(v)} + } + } +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/sqlserver/sqlserver.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/sqlserver/sqlserver.go new file mode 100644 index 0000000000..576204304a --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/sqlserver/sqlserver.go @@ -0,0 +1,153 @@ +// Package sqlserver TODO +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ +package sqlserver + +import ( + "context" + "database/sql" + "fmt" + "strings" + "time" + + "dbm-services/common/go-pubpkg/logger" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/core/cst" + "dbm-services/sqlserver/db-tools/dbactuator/pkg/util/osutil" + + _ "github.com/denisenkom/go-mssqldb" // go-mssqldb TODO + "github.com/jmoiron/sqlx" +) + +// DbWorker TODO +type DbWorker struct { + Dsn string + Db *sql.DB +} + +// NewDbWorker 初始化SQLserver实例对象 +func NewDbWorker(user string, pass string, server string, port int) (dbw *DbWorker, err error) { + dsn := fmt.Sprintf( + "server=%s;port=%d;user id=%s;password=%s;database=master;encrypt=disable", + server, port, user, pass, + ) + dbw = &DbWorker{ + Dsn: dsn, + } + dbw.Db, err = sql.Open("sqlserver", dbw.Dsn) + if err != nil { + return nil, err + } + // check connect with timeout + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + if err := dbw.Db.PingContext(ctx); err != nil { + return nil, fmt.Errorf("ping context failed, err:%w", err) + } + return dbw, nil +} + +// Stop close connection +func (h *DbWorker) Stop() { + if h.Db != nil { + if err := h.Db.Close(); err != nil { + logger.Warn("close db handler failed, err:%s", err.Error()) + } + } +} + +// Exec 执行任意sql,返回影响行数 +func (h *DbWorker) Exec(query string, args ...interface{}) (int64, error) { + ret, err := h.Db.Exec(query, args...) + if err != nil { + return 0, err + } + return ret.RowsAffected() +} + +// ExecMore 执行一堆sql +// 会在同一个连接里执行 +// 空元素会跳过 +func (h *DbWorker) ExecMore(sqls []string) (rowsAffectedCount int64, err error) { + var c int64 + db, err := h.Db.Conn(context.Background()) + if err != nil { + return 0, err + } + defer db.Close() + for _, sqlStr := range sqls { + if strings.TrimSpace(sqlStr) == "" { + continue + } + ret, err := db.ExecContext(context.Background(), sqlStr) + if err != nil { + return rowsAffectedCount, fmt.Errorf("exec %s failed,err:%w", sqlStr, err) + } + if c, err = ret.RowsAffected(); err != nil { + return rowsAffectedCount, fmt.Errorf("exec %s failed,err:%w", sqlStr, err) + } + rowsAffectedCount += c + } + return +} + +// Queryx execute query use sqlx +func (h *DbWorker) Queryx(data interface{}, query string, args ...interface{}) error { + logger.Info("Queryx:%s, args:%v", query, args) + db := sqlx.NewDb(h.Db, "mssql") + udb := db.Unsafe() + if err := udb.Select(data, query, args...); err != nil { + return fmt.Errorf("sqlx select failed, err:%w", err) + } + return nil +} + +// Queryxs execute query use sqlx return Single column +func (h *DbWorker) Queryxs(data interface{}, query string) error { + logger.Info("Queryxs:%s", query) + db := sqlx.NewDb(h.Db, "mssql") + udb := db.Unsafe() + if err := udb.Get(data, query); err != nil { + return err + } + return nil +} + +// ExecLocalSQLFile TODO +// 调用本地的sqlcmd执行本地sql脚本,识别smss的语法(主要是go语法) +// 适配sql脚本执行、初始化等相关大脚本操作 +func ExecLocalSQLFile(sqlVeriosn string, filenames []string, port int) error { + var cmdSql string + switch { + case strings.Contains(sqlVeriosn, "2008"): + cmdSql = cst.SQLCMD_2008 + case strings.Contains(sqlVeriosn, "2012"): + cmdSql = cst.SQLCMD_2012 + case strings.Contains(sqlVeriosn, "2014"): + cmdSql = cst.SQLCMD_2014 + case strings.Contains(sqlVeriosn, "2016"): + cmdSql = cst.SQLCMD_2016 + case strings.Contains(sqlVeriosn, "2017"): + cmdSql = cst.SQLCMD_2017 + case strings.Contains(sqlVeriosn, "2019"): + cmdSql = cst.SQLCMD_2019 + default: + return fmt.Errorf("This version [%s] is not supported", sqlVeriosn) + } + for _, filename := range filenames { + cmd := fmt.Sprintf("& '%s' -S \"127.0.0.1,%d\" -C -i %s", cmdSql, port, filename) + if _, err := osutil.StandardPowerShellCommand(cmd); err != nil { + logger.Error("exec init script failed %s", err.Error()) + return err + } + logger.Info("exec init script success [%d:%s]", port, filename) + } + + return nil +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/sqlserver/sqlserver_test.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/sqlserver/sqlserver_test.go new file mode 100644 index 0000000000..2c10750526 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/sqlserver/sqlserver_test.go @@ -0,0 +1,44 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package sqlserver_test + +import ( + "testing" + + "dbm-services/sqlserver/db-tools/dbactuator/pkg/util/sqlserver" + + _ "github.com/denisenkom/go-mssqldb" +) + +func Test(t *testing.T) { + checkCmd := "SELECT count(0) FROM SYS.SYSPROCESSES WHERE 1!=1" + + var dbWork *sqlserver.DbWorker + var err error + var cnt int + if dbWork, err = sqlserver.NewDbWorker( + "xxx", + "xxx", + "xxx", + 1433, + ); err != nil { + t.Log(err) + return + } + // 到最后回收db连接 + defer dbWork.Stop() + + if err := dbWork.Queryxs(&cnt, checkCmd); err != nil { + t.Log(err) + } + t.Log(cnt) + +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/templates/cmd_groups.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/templates/cmd_groups.go new file mode 100644 index 0000000000..827e6185f2 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/templates/cmd_groups.go @@ -0,0 +1,31 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package templates + +import ( + "github.com/spf13/cobra" +) + +// CommandGroup TODO +type CommandGroup struct { + Message string + Commands []*cobra.Command +} + +// CommandGroups TODO +type CommandGroups []CommandGroup + +// Add TODO +func (g CommandGroups) Add(c *cobra.Command) { + for _, group := range g { + c.AddCommand(group.Commands...) + } +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/templates/normallizers.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/templates/normallizers.go new file mode 100644 index 0000000000..f95983111a --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/templates/normallizers.go @@ -0,0 +1,42 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package templates + +import ( + "strings" + + "github.com/MakeNowJust/heredoc" +) + +// Indentation TODO +const Indentation = ` ` + +// LongDesc TODO +func LongDesc(s string) string { + if len(s) == 0 { + return s + } + return normalizer{s}.heredoc().trim().string +} + +type normalizer struct { + string +} + +func (s normalizer) heredoc() normalizer { + s.string = heredoc.Doc(s.string) + return s +} + +func (s normalizer) trim() normalizer { + s.string = strings.TrimSpace(s.string) + return s +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/templates/templates.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/templates/templates.go new file mode 100644 index 0000000000..415b837e06 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/templates/templates.go @@ -0,0 +1,12 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +// Package templates TODO +package templates diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/timeutil/duration.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/timeutil/duration.go new file mode 100644 index 0000000000..9472d34a92 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/timeutil/duration.go @@ -0,0 +1,77 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package timeutil + +import ( + "encoding/json" + "fmt" + "time" +) + +// Duration TODO +type Duration struct { + time.Duration +} + +// UnmarshalJSON TODO +func (d *Duration) UnmarshalJSON(b []byte) error { + var unmarshalledJson interface{} + + err := json.Unmarshal(b, &unmarshalledJson) + if err != nil { + return err + } + + switch value := unmarshalledJson.(type) { + case float64: + d.Duration = time.Duration(value) + case string: + d.Duration, err = time.ParseDuration(value) + if err != nil { + return err + } + default: + return fmt.Errorf("invalid duration: %#v", unmarshalledJson) + } + + return nil +} + +// String 用于打印 +func (d *Duration) String() string { + return fmt.Sprintf("%s", d.Duration) +} + +// IsZeroDuration TODO +func (d *Duration) IsZeroDuration() bool { + return d.Duration == 0 +} + +// Return TODO +func (d *Duration) Return() time.Duration { + return d.Duration +} + +// NewDuration TODO +func NewDuration(t time.Duration) Duration { + return Duration{t} +} + +// CompareDuration 1: t1>t2, -1: t1 t2.Duration { + return 1 + } else if t1.Duration < t2.Duration { + return -1 + } else { + return 0 + } +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/timeutil/duration_ext.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/timeutil/duration_ext.go new file mode 100644 index 0000000000..858c453f10 --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/timeutil/duration_ext.go @@ -0,0 +1,226 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +package timeutil + +import ( + "errors" + "time" + + "github.com/spf13/cast" + "github.com/spf13/viper" +) + +// modify from: https://gist.github.com/xhit/79c9e137e1cfe332076cdda9f5e24699 + +// ViperGetDuration TODO +func ViperGetDuration(s string) time.Duration { + return ToDurationExt(viper.GetString(s)) +} + +// ViperGetDurationE TODO +func ViperGetDurationE(s string) (time.Duration, error) { + return ToDurationExtE(viper.GetString(s)) +} + +// ToDurationExt 使用扩展的 duration, 支持 1d 1w 格式 +func ToDurationExt(s string) time.Duration { + d, _ := parseDuration(s) + return d +} + +// ToDurationExtE 使用扩展的 duration, 支持 1d 1w 格式 +func ToDurationExtE(s string) (time.Duration, error) { + return parseDuration(s) +} + +// ToDuration 使用内置的 duration, 不支持 1d 格式 +func ToDuration(s string) time.Duration { + return cast.ToDuration(s) +} + +// ToDurationE 使用内置的 duration, 不支持 1d 格式 +func ToDurationE(s string) (time.Duration, error) { + return cast.ToDurationE(s) +} + +var unitMap = map[string]int64{ + "ns": int64(time.Nanosecond), + "us": int64(time.Microsecond), + "µs": int64(time.Microsecond), // U+00B5 = micro symbol + "μs": int64(time.Microsecond), // U+03BC = Greek letter mu + "ms": int64(time.Millisecond), + "s": int64(time.Second), + "m": int64(time.Minute), + "h": int64(time.Hour), + "d": int64(time.Hour) * 24, + "w": int64(time.Hour) * 168, +} + +// parseDuration parses a duration string. +// A duration string is a possibly signed sequence of +// decimal numbers, each with optional fraction and a unit suffix, +// such as "300ms", "-1.5h" or "2h45m". +// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h", "d", "w". +func parseDuration(s string) (time.Duration, error) { + // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+ + orig := s + var d int64 + neg := false + + // Consume [-+]? + if s != "" { + c := s[0] + if c == '-' || c == '+' { + neg = c == '-' + s = s[1:] + } + } + // Special case: if all that is left is "0", this is zero. + if s == "0" { + return 0, nil + } + if s == "" { + return 0, errors.New("time: invalid duration " + quote(orig)) + } + for s != "" { + var ( + v, f int64 // integers before, after decimal point + scale float64 = 1 // value = v + f/scale + ) + + var err error + + // The next character must be [0-9.] + if !(s[0] == '.' || '0' <= s[0] && s[0] <= '9') { + return 0, errors.New("time: invalid duration " + quote(orig)) + } + // Consume [0-9]* + pl := len(s) + v, s, err = leadingInt(s) + if err != nil { + return 0, errors.New("time: invalid duration " + quote(orig)) + } + pre := pl != len(s) // whether we consumed anything before a period + + // Consume (\.[0-9]*)? + post := false + if s != "" && s[0] == '.' { + s = s[1:] + pl := len(s) + f, scale, s = leadingFraction(s) + post = pl != len(s) + } + if !pre && !post { + // no digits (e.g. ".s" or "-.s") + return 0, errors.New("time: invalid duration " + quote(orig)) + } + + // Consume unit. + i := 0 + for ; i < len(s); i++ { + c := s[i] + if c == '.' || '0' <= c && c <= '9' { + break + } + } + if i == 0 { + return 0, errors.New("time: missing unit in duration " + quote(orig)) + } + u := s[:i] + s = s[i:] + unit, ok := unitMap[u] + if !ok { + return 0, errors.New("time: unknown unit " + quote(u) + " in duration " + quote(orig)) + } + if v > (1<<63-1)/unit { + // overflow + return 0, errors.New("time: invalid duration " + quote(orig)) + } + v *= unit + if f > 0 { + // float64 is needed to be nanosecond accurate for fractions of hours. + // v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit) + v += int64(float64(f) * (float64(unit) / scale)) + if v < 0 { + // overflow + return 0, errors.New("time: invalid duration " + quote(orig)) + } + } + d += v + if d < 0 { + // overflow + return 0, errors.New("time: invalid duration " + quote(orig)) + } + } + + if neg { + d = -d + } + return time.Duration(d), nil +} + +func quote(s string) string { + return "\"" + s + "\"" +} + +var errLeadingInt = errors.New("time: bad [0-9]*") // never printed + +// leadingInt consumes the leading [0-9]* from s. +func leadingInt(s string) (x int64, rem string, err error) { + i := 0 + for ; i < len(s); i++ { + c := s[i] + if c < '0' || c > '9' { + break + } + if x > (1<<63-1)/10 { + // overflow + return 0, "", errLeadingInt + } + x = x*10 + int64(c) - '0' + if x < 0 { + // overflow + return 0, "", errLeadingInt + } + } + return x, s[i:], nil +} + +// leadingFraction consumes the leading [0-9]* from s. +// It is used only for fractions, so does not return an error on overflow, +// it just stops accumulating precision. +func leadingFraction(s string) (x int64, scale float64, rem string) { + i := 0 + scale = 1 + overflow := false + for ; i < len(s); i++ { + c := s[i] + if c < '0' || c > '9' { + break + } + if overflow { + continue + } + if x > (1<<63-1)/10 { + // It's possible for overflow to give a positive number, so take care. + overflow = true + continue + } + y := x*10 + int64(c) - '0' + if y < 0 { + overflow = true + continue + } + x = y + scale *= 10 + } + return x, scale, s[i:] +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/timeutil/timeutil.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/timeutil/timeutil.go new file mode 100644 index 0000000000..37d93b81ec --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/timeutil/timeutil.go @@ -0,0 +1,12 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +// Package timeutil TODO +package timeutil diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/util.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/util.go new file mode 100644 index 0000000000..e47dc7249e --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/util.go @@ -0,0 +1,418 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +// Package util TODO +package util + +import ( + "crypto/md5" + "encoding/json" + "fmt" + "io" + "math/rand" + "net" + "net/url" + "os" + "path" + "reflect" + "regexp" + "runtime" + "strings" + "time" + + "dbm-services/common/go-pubpkg/logger" + + "github.com/TylerBrock/colorjson" + "github.com/juju/ratelimit" + "github.com/pkg/errors" +) + +// RetryConfig TODO +type RetryConfig struct { + Times int // 重试次数 + DelayTime time.Duration // 每次重试间隔 +} + +// Retry 重试 +// 第 0 次也需要 delay 再运行 +func Retry(r RetryConfig, f func() error) (err error) { + for i := 0; i < r.Times; i++ { + time.Sleep(r.DelayTime) + if err = f(); err == nil { + return nil + } + logger.Warn("第%d次重试,函数错误:%s", i, err.Error(), err.Error()) + } + return +} + +// AtWhere TODO +func AtWhere() string { + pc, _, _, ok := runtime.Caller(1) + if ok { + fileName, line := runtime.FuncForPC(pc).FileLine(pc) + result := strings.Index(fileName, "/bk-dbactuator/") + if result > 1 { + preStr := fileName[0:result] + fileName = strings.Replace(fileName, preStr, "", 1) + } + return fmt.Sprintf("%s:%d", fileName, line) + } else { + return "Method not Found!" + } +} + +// HasElem TODO +func HasElem(elem interface{}, slice interface{}) bool { + defer func() { + if err := recover(); err != nil { + logger.Error("HasElem error %s ", err) + } + }() + arrV := reflect.ValueOf(slice) + if arrV.Kind() == reflect.Slice || arrV.Kind() == reflect.Array { + for i := 0; i < arrV.Len(); i++ { + // XXX - panics if slice element points to an unexported struct field + // see https://golang.org/pkg/reflect/#Value.Interface + if reflect.DeepEqual(arrV.Index(i).Interface(), elem) { + return true + } + } + } + return false +} + +const ( + tcpDialTimeout = 3 * time.Second +) + +// HostCheck TODO +func HostCheck(host string) bool { + _, err := net.DialTimeout("tcp", host, time.Duration(tcpDialTimeout)) + if err != nil { + logger.Info(err.Error()) + return false + } + return true +} + +// GetFileMd5 TODO +func GetFileMd5(fileAbPath string) (md5sum string, err error) { + rFile, err := os.Open(fileAbPath) + if err != nil { + return "", err + } + defer rFile.Close() + h := md5.New() + if _, err := io.Copy(h, rFile); err != nil { + return "", err + } + return fmt.Sprintf("%x", h.Sum(nil)), nil +} + +// Struct2Map TODO +func Struct2Map(s interface{}, tag string) (map[string]interface{}, error) { + out := make(map[string]interface{}) + v := reflect.ValueOf(s) + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + if v.Kind() != reflect.Struct { + return nil, fmt.Errorf("only accept struct or pointer, got %T", v) + } + t := v.Type() + for i := 0; i < v.NumField(); i++ { + f := t.Field(i) + if tagValue := f.Tag.Get(tag); tagValue != "" { + out[tagValue] = v.Field(i).Interface() + } + } + return out, nil +} + +// SetField TODO +func SetField(obj interface{}, name string, value interface{}) error { + structValue := reflect.ValueOf(obj).Elem() + structFieldValue := structValue.FieldByName(name) + + if !structFieldValue.IsValid() { + return fmt.Errorf("no such field: %s in obj", name) + } + + if !structFieldValue.CanSet() { + return fmt.Errorf("cannot set %s field value", name) + } + + structFieldType := structFieldValue.Type() + val := reflect.ValueOf(value) + if structFieldType != val.Type() { + return errors.New("provided value type didn't match obj field type") + } + + structFieldValue.Set(val) + return nil +} + +// Convert2Map TODO +func Convert2Map(m interface{}) map[string]string { + ret := make(map[string]string) + v := reflect.ValueOf(m) + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + var fd string + for i := 0; i < v.NumField(); i++ { + f := v.Field(i) + switch f.Kind() { + case reflect.Struct: + fallthrough + case reflect.Ptr: + Convert2Map(f.Interface()) + default: + fd = f.String() + } + ret[v.Type().Field(i).Tag.Get("json")] = fd + } + return ret +} + +// StrIsEmpty TODO +func StrIsEmpty(str string) bool { + return strings.TrimSpace(str) == "" +} + +// FileExists 检查目录是否已经存在 +func FileExists(path string) bool { + _, err := os.Stat(path) + if err != nil { + return os.IsExist(err) + } + return true +} + +// IsDirectory 检查本机路径是否是目录 +func IsDirectory(path string) bool { + fileInfo, err := os.Stat(path) + if err != nil { + return false + } + return fileInfo.IsDir() +} + +// FileExistsErr 如果文件不存在则抛出 error +func FileExistsErr(path string) error { + _, err := os.Stat(path) + if err != nil { + return errors.WithStack(err) + } + return nil +} + +// GetFileSize TODO +func GetFileSize(path string) int64 { + f, err := os.Stat(path) + if err != nil { + // 有可能没权限,有可能不存在 + if os.IsNotExist(err) { + return -1 + } else if os.IsPermission(err) { + return -2 + } else { + return -3 + } + } + return f.Size() +} + +// OutputPrettyJson 直接传一个空结构体过来 +func OutputPrettyJson(p interface{}) { + var inInterface map[string]interface{} + inrec, _ := json.Marshal(p) + json.Unmarshal(inrec, &inInterface) + // Make a custom formatter with indent set + f := colorjson.NewFormatter() + f.Indent = 4 + pp, err := f.Marshal(inInterface) + if err != nil { + fmt.Println(err) + return + } + fmt.Println("Payload Example: ") + fmt.Println("") + fmt.Println(string(pp)) + fmt.Println("") +} + +// IntSlice2String 效果:[]int{1,2,3,4} -> "1,2,3,4" +func IntSlice2String(elements []int, sep string) string { + elemStr := "" + if len(elements) > 0 { + for i, elem := range elements { + if i == (len(elements) - 1) { + elemStr += fmt.Sprintf("%d", elem) + break + } + elemStr += fmt.Sprintf("%d%s", elem, sep) + } + } + return elemStr +} + +// ConverMapInterface2MapString TODO +func ConverMapInterface2MapString(mi map[string]interface{}) (ms map[string]string, err error) { + ms = make(map[string]string) + for key, v := range mi { + dv, ok := v.(string) + if !ok { + return nil, fmt.Errorf("key:%s 断言string 失败", key) + } + ms[key] = dv + } + return +} + +// RegexReplaceSubString TODO +func RegexReplaceSubString(str, old, new string) string { + re := regexp.MustCompile(fmt.Sprintf(`(%s)`, old)) + return re.ReplaceAllString(str, new) +} + +// IOLimitRate TODO +// io.Copy 限速 +func IOLimitRate(dst io.Writer, src io.Reader, bwlimitMB int64) (written int64, err error) { + bwlimit := bwlimitMB * 1024 * 1024 + srcBucket := ratelimit.NewBucketWithRate(float64(bwlimit), bwlimit) + return io.Copy(dst, ratelimit.Reader(src, srcBucket)) +} + +// GetSuffixWithLenAndSep 获取后缀 +// 先截取后面 maxlen 长度字符串,再根据 separator 分隔取后缀 +func GetSuffixWithLenAndSep(strList []string, separator string, maxlen int) []string { + if maxlen > 0 { + for i, s := range strList { + l := len(s) + if l-maxlen > 0 { + strList[i] = s[l-maxlen:] + } + } + } + seqList := make([]string, len(strList)) + for i, s := range strList { + seqList[i] = LastElement(strings.Split(s, separator)) + } + return seqList +} + +// LastElement TODO +func LastElement(arr []string) string { + return arr[len(arr)-1] +} + +// ReverseRead · 逆序读取文件,类型tail -n 10 +// +// @receiver name +// @receiver lineNum 读取最后多少上内容 +// @return []string 返回逆序读取的文件内容 +// @return error +func ReverseRead(name string, lineNum uint) ([]string, error) { + // 打开文件 + file, err := os.Open(name) + if err != nil { + return nil, err + } + defer file.Close() + // 获取文件大小 + fs, err := file.Stat() + if err != nil { + return nil, err + } + fileSize := fs.Size() + + var offset int64 = -1 // 偏移量,初始化为-1,若为0则会读到EOF + char := make([]byte, 1) // 用于读取单个字节 + lineStr := "" // 存放一行的数据 + buff := make([]string, 0, 100) + for (-offset) <= fileSize { + // 通过Seek函数从末尾移动游标然后每次读取一个字节 + file.Seek(offset, io.SeekEnd) + _, err := file.Read(char) + if err != nil { + return buff, err + } + if char[0] == '\n' { + offset-- // windows跳过'\r' + lineNum-- // 到此读取完一行 + buff = append(buff, lineStr) + lineStr = "" + if lineNum == 0 { + return buff, nil + } + } else { + lineStr = string(char) + lineStr + } + offset-- + } + buff = append(buff, lineStr) + return buff, nil +} + +// SliceErrorsToError TODO +func SliceErrorsToError(errs []error) error { + var errStrs []string + for _, e := range errs { + errStrs = append(errStrs, e.Error()) + } + errString := strings.Join(errStrs, "\n") + return errors.New(errString) +} + +// IntnRange TODO +func IntnRange(min, max int) int { + rand.Seed(time.Now().Unix()) + return rand.Intn(max-min) + min +} + +// GetFileModifyTime TODO +func GetFileModifyTime(filename string) (bool, int64) { + if _, err := os.Stat(filename); !os.IsNotExist(err) { + f, err1 := os.Open(filename) + if err1 != nil { + return true, 0 + } + fi, err2 := f.Stat() + if err2 != nil { + return true, 0 + } + return true, fi.ModTime().Unix() + } + return false, 0 +} + +// UrlJoinPath utl.JoinPath go1.919 +func UrlJoinPath(p, subPath string) (string, error) { + u, err := url.Parse(p) + if err != nil { + return "", err + } + u.Path = path.Join(u.Path, subPath) + return u.String(), nil +} + +// FileIsEmpty TODO +func FileIsEmpty(path string) error { + fileInfo, err := os.Stat(path) + if err != nil { + return err + } + if fileInfo.Size() <= 0 { + return fmt.Errorf("文件为空") + } + return nil +} diff --git a/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/validate/validate.go b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/validate/validate.go new file mode 100644 index 0000000000..425cc379df --- /dev/null +++ b/dbm-services/sqlserver/db-tools/dbactuator/pkg/util/validate/validate.go @@ -0,0 +1,136 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * Copyright (C) 2017-2023 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 https://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. + */ + +// Package validate TODO +package validate + +import ( + "fmt" + "reflect" + "strings" + "time" + + "dbm-services/sqlserver/db-tools/dbactuator/pkg/util" + + "github.com/go-playground/locales/en" + ut "github.com/go-playground/universal-translator" + "github.com/go-playground/validator/v10" + en_translations "github.com/go-playground/validator/v10/translations/en" + "github.com/pkg/errors" +) + +// ValidateEnums TODO +// make validate tag work with enums tag +// 避免 validate oneof 和 swagger enums 写 2 份重复的校验和文档 +// example: Method string `validate:"required,enums" enums:"post,get" json:"method"` +func ValidateEnums(f validator.FieldLevel) bool { + fieldValue := f.Field().String() + fieldName := f.StructFieldName() + // get StructField + sf, _ := f.Parent().Type().FieldByName(fieldName) + // get tag value from tag_field enums + tagValue := sf.Tag.Get(TagEnum) + enumsValues := strings.Split(tagValue, ",") + if util.StringsHas(enumsValues, fieldValue) { + return true + } else { + return false + } +} + +// GoValidateStructSimple TODO +// 简单校验 struct,不涉及逻辑 +// 如果 struct 上有 tag validate:"enums",必须启用enum=true校验 +func GoValidateStructSimple(v interface{}, enum bool) error { + validate := validator.New() + if enum { + _ = validate.RegisterValidation("enums", ValidateEnums) + } + if err := validate.Struct(v); err != nil { + return err + } + return nil +} + +// TagEnum TODO +const TagEnum = "enums" + +// GoValidateStruct v 不能是Ptr +func GoValidateStruct(v interface{}, enum bool, charset bool) error { + validate := validator.New() + uni := ut.New(en.New()) + trans, _ := uni.GetTranslator("en") + // 提示时显示 json 字段的名字 + validate.RegisterTagNameFunc(func(fld reflect.StructField) string { + // name := fld.Tag.Get("json") + name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] + if name == "-" { + return "" + } + return name + }) + if err := en_translations.RegisterDefaultTranslations(validate, trans); err != nil { + return err + } + + if enum { + _ = validate.RegisterValidation(TagEnum, ValidateEnums) + } + if charset { + _ = validate.RegisterValidation("checkCharset", validCharSet) + } + _ = validate.RegisterValidation("time", validateTimeStr) + if err := validate.Struct(v); err != nil { + return translateErr2Msg(v, trans, err) + } + return nil +} + +// translateErr2Msg v 不能是Ptr +func translateErr2Msg(v interface{}, trans ut.Translator, err error) error { + var errStr []string + _, ok := err.(*validator.InvalidValidationError) + if ok { + return fmt.Errorf("param error:%s", err.Error()) + } + for _, vErr := range err.(validator.ValidationErrors) { + if vErr.Tag() == TagEnum { + errmsg := "" + // errmsg := customEnumTransFunc(vErr, v) + if vErr.Param() == "" { + sf, _ := reflect.TypeOf(v).FieldByName(vErr.StructField()) + tagValue := sf.Tag.Get(TagEnum) + errmsg = fmt.Sprintf("%s must be one of [%s]", vErr.Field(), tagValue) + } else { + errmsg = vErr.Param() + } + errStr = append(errStr, errmsg) + continue + } + errStr = append(errStr, vErr.Translate(trans)) + } + return errors.New(strings.Join(errStr, " || ")) +} + +func validCharSet(f validator.FieldLevel) bool { + v := f.Field().String() + return util.HasElem(v, []string{"default", "utf8mb4", "utf8", "latin1", "gb2312", "gbk", "binary", "gb18030"}) +} + +// validateTimeStr TODO +// 验证时间字符串 "09:00:00" 这种 +func validateTimeStr(f validator.FieldLevel) bool { + v := f.Field().String() + if strings.TrimSpace(v) == "" { + return true + } + _, err := time.Parse("15:04:05", v) + return err == nil +}