add server
Change-Id: I0760f17f6a01c0121b59fcbfafc666032dbc30af
This commit is contained in:
parent
3f5f28d785
commit
e94826ce29
@ -20,31 +20,14 @@ schedule:
|
||||
postgres:
|
||||
data:
|
||||
enable: ${POSTGRES_DATA_ENABLE||false}
|
||||
host: ${POSTGRES_DATA_HOST||10.110.63.138}
|
||||
port: ${POSTGRES_DATA_PORT||5432}
|
||||
database: ${POSTGRES_DATA_DATABASE||postgres}
|
||||
username: ${POSTGRES_DATA_USERNAME||postgres}
|
||||
password: ${POSTGRES_DATA_PASSWORD||Mypostgres!23}
|
||||
log_level: ${LOG_LEVEL||4}
|
||||
auth:
|
||||
enable: ${POSTGRES_AUTH_ENABLE||false}
|
||||
host: ${POSTGRES_AUTH_HOST||10.110.63.138}
|
||||
port: ${POSTGRES_AUTH_PORT||5432}
|
||||
database: ${POSTGRES_AUTH_DATABASE||auth}
|
||||
username: ${POSTGRES_AUTH_USERNAME||postgres}
|
||||
password: ${POSTGRES_AUTH_PASSWORD||Mypostgres!23}
|
||||
log_level: ${LOG_LEVEL||4}
|
||||
redis:
|
||||
enable: ${REDIS_ENABLE||false}
|
||||
host: ${REDIS_HOST||127.0.0.1}
|
||||
port: ${REDIS_POST||6379}
|
||||
password: ${REDIS_PASSWORD||}
|
||||
database: ${REDIS_DATABASE||0}
|
||||
nats_config:
|
||||
# 10.110.63.81:30529 192.168.12.110
|
||||
url: ${NATS_URL||nats://10.110.63.81:30529}
|
||||
user: ${NATS_USER||admin}
|
||||
password: ${NATS_PASSWORD||T0pS3cr3tFGThjjds56}
|
||||
url: ${NATS_URL||}
|
||||
user: ${NATS_USER||}
|
||||
password: ${NATS_PASSWORD||}
|
||||
|
||||
|
||||
logger:
|
||||
|
119
server/README.md
Normal file
119
server/README.md
Normal file
@ -0,0 +1,119 @@
|
||||
# go project种子项目
|
||||
本项目基于 gin 框架为核心的一个脚手架搭建而成,可以基于本项目快速完成业务开发,开箱📦 即用。
|
||||
|
||||
HTTP 运行
|
||||
拉取代码后在项目根目录执行如下命令:
|
||||
|
||||
# 本地有 go 环境,版本 >= 1.18.1
|
||||
# 建议开启GO111MODULE
|
||||
# go env -w GO111MODULE=on
|
||||
|
||||
# 配置Go Mod引用私有库
|
||||
go env -w GOPRIVATE=git.inspur.com
|
||||
go env -w GOINSECURE=git.inspur.com
|
||||
go env -w GOPROXY="http://nexus.inspur.local/repository/go-public/,direct"
|
||||
|
||||
# 依赖管理
|
||||
go mod tidy
|
||||
# 依赖库下载
|
||||
go mod vendor
|
||||
|
||||
# 首次运行会自动复制一份示例配置(config/config.example.yaml)文件到config目录(config/config.yaml)
|
||||
go run main.go
|
||||
|
||||
# 项目起来后执行下面命令访问示例路由
|
||||
curl "http://127.0.0.1:8899/api/v1/hello-world"
|
||||
# {"code":0,"message":"OK","data":{"result":"hello gin-layout"},"cost":"6.151µs"}
|
||||
curl "http://127.0.0.1:8899/api/v1/hello-world?name=world"
|
||||
# {"code":0,"message":"OK","data":{"result":"hello world"},"cost":"6.87µs"}
|
||||
部署
|
||||
# 打包项目(如何打包其他os平台的包自行 google)
|
||||
go build -o cmd/ main.go
|
||||
|
||||
# 运行时请配置指定config文件的位置,否则可能会出现找不到配置的情况,修改完配置请重启
|
||||
cmd/main.go -c="指定配置文件位置(/home/config.yaml)"
|
||||
|
||||
# nginx 反向代理配置示例
|
||||
server {
|
||||
listen 80;
|
||||
server_name api.xxx.com;
|
||||
location / {
|
||||
proxy_set_header Host $host;
|
||||
proxy_pass http://172.0.0.1:8899;
|
||||
}
|
||||
}
|
||||
目录结构
|
||||
.
|
||||
|——.gitignore
|
||||
|——go.mod
|
||||
|——go.sum
|
||||
|——main.go // 项目入口 main 包
|
||||
|——LICENSE
|
||||
|——README.md
|
||||
|——doc // 设计和用户文档
|
||||
|——db // 数据库脚本
|
||||
|——hack // 用于执行各种构建,安装,分析等操作的脚本。
|
||||
|——boot // 项目初始化目录
|
||||
| └──boot.go
|
||||
|——config // 这里通常维护一些本地调试用的样例配置文件
|
||||
| └──autoload // 配置文件的结构体定义包
|
||||
| └──app.go
|
||||
| └──logger.go
|
||||
| └──mysql.go
|
||||
| └──redis.go
|
||||
| └──server.go
|
||||
| └──config.example.ini // .ini 配置示例文件
|
||||
| └──config.example.yaml // .yaml 配置示例文件
|
||||
| └──config.go // 配置初始化文件
|
||||
|——data // 数据初始化目录
|
||||
| └──data.go
|
||||
| └──mysql.go
|
||||
| └──redis.go
|
||||
|——internal // 该服务所有不对外暴露的代码,通常的业务逻辑都在这下面,使用internal避免错误引用
|
||||
| └──controller // 控制器代码
|
||||
| └──v1
|
||||
| └──auth.go // 完整流程演示代码,包含数据库表的操作
|
||||
| └──helloword.go // 基础演示代码
|
||||
| └──base.go
|
||||
| └──middleware // 中间件目录
|
||||
| └──cors.go
|
||||
| └──logger.go
|
||||
| └──recovery.go
|
||||
| └──requestCost.go
|
||||
| └──model // 业务数据访问
|
||||
| └──admin_users.go
|
||||
| └──base.go
|
||||
| └──pkg // 内部使用包
|
||||
| └──errors // 错误定义
|
||||
| └──code.go
|
||||
| └──en-us.go
|
||||
| └──zh-cn.go
|
||||
| └──logger // 日志处理
|
||||
| └──logger.go
|
||||
| └──response // 统一响应输出
|
||||
| └──response.go
|
||||
| └──routers // 路由定义
|
||||
| └──apiRouter.go
|
||||
| └──router.go
|
||||
| └──service // 业务逻辑
|
||||
| └──auth.go
|
||||
| └──validator // 请求参数验证器
|
||||
| └──form // 表单参数定义
|
||||
| └──auth.go
|
||||
| └──validator.go
|
||||
|——pkg // 可以被外部使用的包
|
||||
| └──convert // 数据类型转换
|
||||
| └──convert.go
|
||||
| └──utils // 帮助函数
|
||||
| └──utils.go
|
||||
生产环境注意事项
|
||||
在构建生产环境时,请配置好 .yaml 文件中基础路径 base_path,所有的日志记录文件会保存在该目录下的 {base_path}/gin-layout/logs/ 里面,该基础路径默认为执行命令的目录
|
||||
|
||||
其他说明
|
||||
项目中使用到的包
|
||||
核心:gin
|
||||
配置:gopkg.in/yaml.v3、gopkg.in/ini.v1
|
||||
参数验证:github.com/go-playground/validator/v10
|
||||
日志:go.uber.org/zap、github.com/natefinch/lumberjack、github.com/lestrrat-go/file-rotatelogs
|
||||
数据库:gorm.io/gorm、go-redis/v8
|
||||
还有其他不一一列举,更多请查看go.mod文件
|
54
server/boot/boot.go
Normal file
54
server/boot/boot.go
Normal file
@ -0,0 +1,54 @@
|
||||
package boot
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/config"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/data"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/event_engine"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/validator"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/pkg/log"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
configPath string
|
||||
printVersion bool
|
||||
Run string
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&Run, "r", "http", "执行命令默认运行http服务")
|
||||
flag.StringVar(&configPath, "c", "", "请输入配置文件绝对路径")
|
||||
flag.BoolVar(&printVersion, "version", false, "查看版本")
|
||||
flag.Parse()
|
||||
|
||||
if printVersion {
|
||||
// 打印版本号
|
||||
println(version)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// 1、初始化配置
|
||||
// 从环境变量读取配置文件路径
|
||||
if envConfigPath := os.Getenv("CFN_SCHEDULE_CONFIG_PATH"); envConfigPath != "" {
|
||||
configPath = envConfigPath
|
||||
}
|
||||
config.InitConfig(configPath)
|
||||
|
||||
// 2、初始化zap日志
|
||||
log.InitLogger()
|
||||
|
||||
// 3、初始化数据库
|
||||
data.InitData()
|
||||
|
||||
// 4、初始化验证器
|
||||
validator.InitValidatorTrans("zh")
|
||||
|
||||
service.Start()
|
||||
|
||||
event_engine.Init()
|
||||
|
||||
app_manage.Init()
|
||||
}
|
4
server/boot/version.go
Normal file
4
server/boot/version.go
Normal file
@ -0,0 +1,4 @@
|
||||
package boot
|
||||
|
||||
// version is the current gin-layout version.
|
||||
const version = "0.2.3"
|
26
server/config/app.go
Normal file
26
server/config/app.go
Normal file
@ -0,0 +1,26 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/pkg/convert"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/pkg/utils"
|
||||
)
|
||||
|
||||
type AppConfig struct {
|
||||
AppEnv string `ini:"app_env" yaml:"app_env" mapstructure:"app_env"`
|
||||
Debug bool `ini:"debug" yaml:"debug" mapstructure:"debug"`
|
||||
Language string `ini:"language" yaml:"language" mapstructure:"language"`
|
||||
StaticBasePath string `ini:"base_path" yaml:"base_path" mapstructure:"base_path"`
|
||||
}
|
||||
|
||||
var App = AppConfig{
|
||||
AppEnv: "local",
|
||||
Debug: true,
|
||||
Language: "zh_CN",
|
||||
StaticBasePath: getDefaultPath(),
|
||||
}
|
||||
|
||||
func getDefaultPath() (path string) {
|
||||
path, _ = utils.GetDefaultPath()
|
||||
path = convert.GetString(utils.If(path != "", path, "/tmp"))
|
||||
return
|
||||
}
|
15
server/config/auth.go
Normal file
15
server/config/auth.go
Normal file
@ -0,0 +1,15 @@
|
||||
package config
|
||||
|
||||
type AuthConfig struct {
|
||||
Enable bool `ini:"enable" yaml:"enable" mapstructure:"enable"`
|
||||
Url string `ini:"url" yaml:"url" mapstructure:"url"`
|
||||
LoginInfo string `ini:"login_info" yaml:"login_info" mapstructure:"login_info"`
|
||||
LoginWithCode string `ini:"login_with_code" yaml:"login_with_code" mapstructure:"login_with_code"`
|
||||
}
|
||||
|
||||
var Auth = AuthConfig{
|
||||
Enable: true,
|
||||
Url: "",
|
||||
LoginInfo: "",
|
||||
LoginWithCode: "",
|
||||
}
|
22
server/config/certs/minio.public.crt
Normal file
22
server/config/certs/minio.public.crt
Normal file
@ -0,0 +1,22 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDozCCAougAwIBAgIUYr8WFHmf63SG6G2DjGBn4Nu0T1YwDQYJKoZIhvcNAQEL
|
||||
BQAwYDELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUNob25nUWluZzEOMAwGA1UEBwwF
|
||||
WXVCZWkxDzANBgNVBAoMBkluc3B1cjEOMAwGA1UECwwFcHRqc2IxDDAKBgNVBAMM
|
||||
A3ljYjAgFw0yMzExMTUwNzQ0NTFaGA8yMTIzMTAyMjA3NDQ1MVowYDELMAkGA1UE
|
||||
BhMCQ04xEjAQBgNVBAgMCUNob25nUWluZzEOMAwGA1UEBwwFWXVCZWkxDzANBgNV
|
||||
BAoMBkluc3B1cjEOMAwGA1UECwwFcHRqc2IxDDAKBgNVBAMMA3ljYjCCASIwDQYJ
|
||||
KoZIhvcNAQEBBQADggEPADCCAQoCggEBANjEiLH20u8zacfn++ytfsYi3p+ygtHN
|
||||
KvXBYEntxYmURngKndOYWwR0v1wy5RQkaCmOjn6lIIoUf7G9uNT/mrumLJRi98Sx
|
||||
AR7AGhgUjHo9cuF/NjtIHstc64F2gGdzJeEfg0IEk1T5SSOMOs0FH0jWC24iu8Xa
|
||||
Jz5kFGFJy0iwHdQWcasdx0Dg8TxbGJkBsn6P+Li5xDWCrYu9jEgmm5c4Yd+cN8uF
|
||||
eJGUWqjEDCG/DfSZNzgi5wQAGIU5Zc738SJVsnqJzuutrYXiuk+68EoHwQ2/nlI0
|
||||
fIl4hAT7MmxrlXJNT/kdCPaj1xMkCxMlxmdXVrtWJexZ7X/MkJLgVycCAwEAAaNT
|
||||
MFEwHQYDVR0OBBYEFKcn6Z9mtF2cvTNT0IY/xbtNhmM5MB8GA1UdIwQYMBaAFKcn
|
||||
6Z9mtF2cvTNT0IY/xbtNhmM5MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
|
||||
BQADggEBAC3GKL46KfY/5dCDpZK2Az70pQ+LUMAzteZn7wuTmhLghKUdGRgoVz4b
|
||||
j6IvV6gr5cR64Y8+55rP9TqbGZC8XF/dwxl9kn/hp2aPcrLroyCqqRWZ4TECRh9R
|
||||
/7IIMX9+vwt3FLM0bJaQchiOLMawwWXeizakB/+6LZHssK8L/Qiwx1uXUq24mJox
|
||||
hgfvxUtYoF3BLv3zqHojqN/zAqKZrsiYEQMv0HgCBCOuWRXRsWMiKY7US6UrhLY4
|
||||
kaooXtGN8e6wTGnB4LN2fhQ+oAvVOzJUEnCR+AUwWMjbzOk0JZBFFxe2zpANa4yX
|
||||
4iGDpSkm4XgtV0USyx+T+iiA5BEvqps=
|
||||
-----END CERTIFICATE-----
|
125
server/config/config.go
Normal file
125
server/config/config.go
Normal file
@ -0,0 +1,125 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/config/customized"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/pkg/utils"
|
||||
"github.com/spf13/viper"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// The valid auth strategies and values for cookie handling
|
||||
const (
|
||||
// These constants are used for external services auth (Prometheus ...) ;
|
||||
AuthTypeBasic = "basic"
|
||||
AuthTypeBearer = "bearer"
|
||||
AuthTypeNone = "none"
|
||||
)
|
||||
|
||||
// Conf 配置项主结构体
|
||||
// mapstructure(配置文件属性名称无法与类属性名称直接对应)
|
||||
type Conf struct {
|
||||
AppConfig `yaml:"app" mapstructure:"app"`
|
||||
Server ServerConfig `yaml:"server" mapstructure:"server"`
|
||||
WebEmbed bool `yaml:"web_embed" mapstructure:"web_embed"`
|
||||
DatabaseConfig DatabaseConfig `yaml:"database" mapstructure:"database"`
|
||||
Redis RedisConfig `yaml:"redis" mapstructure:"redis"`
|
||||
Logger LoggerConfig `yaml:"logger" mapstructure:"logger"`
|
||||
Minio MinioConfig `yaml:"minio" mapstructure:"minio"`
|
||||
Nats NatsConfig `yaml:"nats" mapstructure:"nats"`
|
||||
Prometheus PrometheusConfig `yaml:"prometheus" mapstructure:"prometheus"`
|
||||
XxlJob XxlJobConfig `yaml:"xxljob" mapstructure:"xxljob"`
|
||||
SchemeService SchemeServiceConfig `yaml:"scheme_service" mapstructure:"scheme_service"`
|
||||
Auth AuthConfig `yaml:"auth" mapstructure:"auth"`
|
||||
CfnConfig customized.CfnConfig `yaml:"cfn_config" mapstructure:"cfn_config"`
|
||||
}
|
||||
|
||||
var Config = &Conf{
|
||||
AppConfig: App,
|
||||
Server: Server,
|
||||
DatabaseConfig: Database,
|
||||
Redis: Redis,
|
||||
Logger: Logger,
|
||||
Minio: Minio,
|
||||
Nats: Nats,
|
||||
Prometheus: Prometheus,
|
||||
XxlJob: XxlJob,
|
||||
SchemeService: SchemeService,
|
||||
Auth: Auth,
|
||||
CfnConfig: customized.Cfn,
|
||||
}
|
||||
|
||||
var once sync.Once
|
||||
|
||||
func InitConfig(configPath string) {
|
||||
once.Do(func() {
|
||||
// 加载 .yaml 配置
|
||||
loadYaml(configPath)
|
||||
})
|
||||
}
|
||||
|
||||
// todo 环境变量注入配置 or 与nacos集成
|
||||
func loadYaml(configPath string) {
|
||||
var yamlConfig string
|
||||
if configPath == "" {
|
||||
yamlConfig = filepath.Join(utils.GetRunPath(), "config/config.yaml")
|
||||
} else {
|
||||
yamlConfig = filepath.Join(configPath)
|
||||
}
|
||||
|
||||
viper.SetConfigFile(yamlConfig)
|
||||
viper.SetConfigType("yaml")
|
||||
err := viper.ReadInConfig()
|
||||
if err != nil {
|
||||
panic("Failed to read configuration file:" + err.Error())
|
||||
}
|
||||
for _, key := range viper.AllKeys() {
|
||||
value := viper.GetString(key)
|
||||
realValue := expandValueEnv(value)
|
||||
if value != realValue {
|
||||
viper.Set(key, realValue)
|
||||
}
|
||||
}
|
||||
|
||||
err = viper.Unmarshal(Config)
|
||||
if err != nil {
|
||||
panic("Failed to load configuration:" + err.Error())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func expandValueEnv(value string) (realValue string) {
|
||||
realValue = value
|
||||
|
||||
vLen := len(value)
|
||||
// 3 = ${}
|
||||
if vLen < 3 {
|
||||
return
|
||||
}
|
||||
// Need start with "${" and end with "}", then return.
|
||||
if value[0] != '$' || value[1] != '{' || value[vLen-1] != '}' {
|
||||
return
|
||||
}
|
||||
|
||||
key := ""
|
||||
defaultV := ""
|
||||
// value start with "${"
|
||||
for i := 2; i < vLen; i++ {
|
||||
if value[i] == '|' && (i+1 < vLen && value[i+1] == '|') {
|
||||
key = value[2:i]
|
||||
defaultV = value[i+2 : vLen-1] // other string is default value.
|
||||
break
|
||||
} else if value[i] == '}' {
|
||||
key = value[2:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
realValue = os.Getenv(key)
|
||||
if realValue == "" {
|
||||
realValue = defaultV
|
||||
}
|
||||
|
||||
return
|
||||
}
|
13
server/config/customized/cfn_config.go
Normal file
13
server/config/customized/cfn_config.go
Normal file
@ -0,0 +1,13 @@
|
||||
package customized
|
||||
|
||||
type CfnConfig struct {
|
||||
Enable bool `ini:"enable" yaml:"enable" mapstructure:"enable"`
|
||||
CfnWorkSpaceId string `ini:"cfn_workspace_id" yaml:"cfn_workspace_id" mapstructure:"cfn_workspace_id"`
|
||||
AgnetSilentUpgrade bool `ini:"agent_silent_upgrade" yaml:"agent_silent_upgrade" mapstructure:"agent_silent_upgrade"`
|
||||
}
|
||||
|
||||
var Cfn = CfnConfig{
|
||||
Enable: false,
|
||||
CfnWorkSpaceId: "cfn_workspace_id_default",
|
||||
AgnetSilentUpgrade: false,
|
||||
}
|
13
server/config/database.go
Normal file
13
server/config/database.go
Normal file
@ -0,0 +1,13 @@
|
||||
package config
|
||||
|
||||
type DatabaseConfig struct {
|
||||
Type string `ini:"type" yaml:"type" mapstructure:"type"`
|
||||
SqliteConfig SqliteConfig `ini:"sqlite" yaml:"sqlite" mapstructure:"sqlite"`
|
||||
PostgreSqlConfig PostgreSqlConfigMap `ini:"postgres" yaml:"postgres" mapstructure:"postgres"`
|
||||
}
|
||||
|
||||
var Database = DatabaseConfig{
|
||||
Type: "sqlite",
|
||||
SqliteConfig: Sqlite,
|
||||
PostgreSqlConfig: PostgreSql,
|
||||
}
|
35
server/config/logger.go
Normal file
35
server/config/logger.go
Normal file
@ -0,0 +1,35 @@
|
||||
package config
|
||||
|
||||
type DivisionTime struct {
|
||||
MaxAge int `ini:"max_age" yaml:"max_age" mapstructure:"max_age"` // 保留旧文件的最大天数,单位天
|
||||
RotationTime int `ini:"rotation_time" yaml:"rotation_time" mapstructure:"rotation_time"` // 多长时间切割一次文件,单位小时
|
||||
}
|
||||
|
||||
type DivisionSize struct {
|
||||
MaxSize int `ini:"max_size" yaml:"max_size" mapstructure:"max_size"` // 在进行切割之前,日志文件的最大大小(以MB为单位)
|
||||
MaxBackups int `ini:"max_backups" yaml:"max_backups" mapstructure:"max_backups"` // 保留旧文件的最大个数
|
||||
MaxAge int `ini:"max_age" yaml:"max_age" mapstructure:"max_age"` // 保留旧文件的最大天数
|
||||
Compress bool `ini:"compress" yaml:"compress"` // 是否压缩/归档旧文件
|
||||
}
|
||||
|
||||
type LoggerConfig struct {
|
||||
DefaultDivision string `ini:"default_division" yaml:"default_division" mapstructure:"default_division"`
|
||||
Filename string `ini:"file_name" yaml:"file_name" mapstructure:"file_name"`
|
||||
DivisionTime DivisionTime `ini:"division_time" yaml:"division_time" mapstructure:"division_time"`
|
||||
DivisionSize DivisionSize `ini:"division_size" yaml:"division_size" mapstructure:"division_size"`
|
||||
}
|
||||
|
||||
var Logger = LoggerConfig{
|
||||
DefaultDivision: "time", // time 按时间切割,默认一天, size 按文件大小切割
|
||||
Filename: "sys.log",
|
||||
DivisionTime: DivisionTime{
|
||||
MaxAge: 15,
|
||||
RotationTime: 24,
|
||||
},
|
||||
DivisionSize: DivisionSize{
|
||||
MaxSize: 2,
|
||||
MaxBackups: 2,
|
||||
MaxAge: 15,
|
||||
Compress: false,
|
||||
},
|
||||
}
|
13
server/config/minio.go
Normal file
13
server/config/minio.go
Normal file
@ -0,0 +1,13 @@
|
||||
package config
|
||||
|
||||
type MinioConfig struct {
|
||||
Endpoint string `ini:"endpoint" yaml:"endpoint"`
|
||||
AccessKey string `ini:"access_key" yaml:"access_key" mapstructure:"access_key"`
|
||||
SecretAccessKey string `ini:"secret_access_key" yaml:"secret_access_key" mapstructure:"secret_access_key"`
|
||||
}
|
||||
|
||||
var Minio = MinioConfig{
|
||||
Endpoint: "192.168.12.78:208670",
|
||||
AccessKey: "xxxxxxxx",
|
||||
SecretAccessKey: "yyyyyyyy",
|
||||
}
|
13
server/config/nats.go
Normal file
13
server/config/nats.go
Normal file
@ -0,0 +1,13 @@
|
||||
package config
|
||||
|
||||
type NatsConfig struct {
|
||||
Url string `ini:"url" yaml:"url"`
|
||||
User string `ini:"user" yaml:"user"`
|
||||
Password string `ini:"password" yaml:"password"`
|
||||
}
|
||||
|
||||
var Nats = NatsConfig{
|
||||
Url: "nats://192.168.12.110:30529",
|
||||
User: "admin",
|
||||
Password: "T0pS3cr3tFGThjjds56",
|
||||
}
|
37
server/config/postgres.go
Normal file
37
server/config/postgres.go
Normal file
@ -0,0 +1,37 @@
|
||||
package config
|
||||
|
||||
type PostgreSqlConfig struct {
|
||||
Host string `ini:"host" yaml:"host"`
|
||||
Username string `ini:"username" yaml:"username"`
|
||||
Password string `ini:"password" yaml:"password"`
|
||||
Port uint16 `ini:"port" yaml:"port"`
|
||||
Database string `ini:"database" yaml:"database"`
|
||||
TablePrefix string `ini:"table_prefix" yaml:"table_prefix" mapstructure:"table_prefix"`
|
||||
LogLevel int `ini:"log_level" yaml:"log_level" mapstructure:"log_level"`
|
||||
PrintSql bool `ini:"print_sql" yaml:"print_sql" mapstructure:"print_sql"`
|
||||
}
|
||||
|
||||
type PostgreSqlConfigMap map[string]PostgreSqlConfig
|
||||
|
||||
var PostgreSql = PostgreSqlConfigMap{
|
||||
"data": {
|
||||
Host: "127.0.0.1",
|
||||
Username: "root",
|
||||
Password: "root1234",
|
||||
Port: 3306,
|
||||
Database: "test",
|
||||
TablePrefix: "",
|
||||
LogLevel: 4,
|
||||
PrintSql: false,
|
||||
},
|
||||
"auth": {
|
||||
Host: "127.0.0.1",
|
||||
Username: "root",
|
||||
Password: "root1234",
|
||||
Port: 3306,
|
||||
Database: "test",
|
||||
TablePrefix: "",
|
||||
LogLevel: 4,
|
||||
PrintSql: false,
|
||||
},
|
||||
}
|
15
server/config/prometheus.go
Normal file
15
server/config/prometheus.go
Normal file
@ -0,0 +1,15 @@
|
||||
package config
|
||||
|
||||
type PrometheusConfig struct {
|
||||
Url string `ini:"url" yaml:"url" mapstructure:"url"`
|
||||
AuthEnable bool `ini:"auth_enable" yaml:"auth_enable" mapstructure:"auth_enable"`
|
||||
User string `ini:"user" yaml:"user" mapstructure:"user"`
|
||||
Password string `ini:"password" yaml:"password" mapstructure:"password"`
|
||||
}
|
||||
|
||||
var Prometheus = PrometheusConfig{
|
||||
Url: "http://127.0.0.1:9090",
|
||||
AuthEnable: false,
|
||||
User: "admin",
|
||||
Password: "admin",
|
||||
}
|
17
server/config/redis.go
Normal file
17
server/config/redis.go
Normal file
@ -0,0 +1,17 @@
|
||||
package config
|
||||
|
||||
type RedisConfig struct {
|
||||
Enable bool `ini:"enable" yaml:"enable"`
|
||||
Host string `ini:"host" yaml:"host"`
|
||||
Port string `ini:"port" yaml:"port"`
|
||||
Password string `ini:"password" yaml:"password"`
|
||||
Database int `ini:"database" yaml:"database"`
|
||||
}
|
||||
|
||||
var Redis = RedisConfig{
|
||||
Enable: false,
|
||||
Host: "127.0.0.1",
|
||||
Password: "root1234",
|
||||
Port: "6379",
|
||||
Database: 0,
|
||||
}
|
12
server/config/scheme_service.go
Normal file
12
server/config/scheme_service.go
Normal file
@ -0,0 +1,12 @@
|
||||
package config
|
||||
|
||||
// ServerConfig 定义项目配置
|
||||
type SchemeServiceConfig struct {
|
||||
BaseUrl string `ini:"base_url" yaml:"base_url" mapstructure:"base_url"`
|
||||
Token string `ini:"token" yaml:"token" mapstructure:"token"`
|
||||
}
|
||||
|
||||
var SchemeService = SchemeServiceConfig{
|
||||
BaseUrl: "127.0.0.1:9999",
|
||||
Token: "mock dkf98123",
|
||||
}
|
12
server/config/server.go
Normal file
12
server/config/server.go
Normal file
@ -0,0 +1,12 @@
|
||||
package config
|
||||
|
||||
// ServerConfig 定义项目配置
|
||||
type ServerConfig struct {
|
||||
Host string `ini:"host" yaml:"host" mapstructure:"host"`
|
||||
Port uint64 `ini:"port" yaml:"port" mapstructure:"port"`
|
||||
}
|
||||
|
||||
var Server = ServerConfig{
|
||||
Host: "127.0.0.1",
|
||||
Port: 9999,
|
||||
}
|
9
server/config/sqlite.go
Normal file
9
server/config/sqlite.go
Normal file
@ -0,0 +1,9 @@
|
||||
package config
|
||||
|
||||
type SqliteConfig struct {
|
||||
Data string `ini:"data" yaml:"data" mapstructure:"data"`
|
||||
}
|
||||
|
||||
var Sqlite = SqliteConfig{
|
||||
Data: "data/sqlite.db",
|
||||
}
|
11
server/config/xxljob.go
Normal file
11
server/config/xxljob.go
Normal file
@ -0,0 +1,11 @@
|
||||
package config
|
||||
|
||||
type XxlJobConfig struct {
|
||||
Url string `ini:"url" yaml:"url"`
|
||||
Token string `ini:"token" yaml:"token"`
|
||||
}
|
||||
|
||||
var XxlJob = XxlJobConfig{
|
||||
Url: "http://127.0.0.1/xxl-job-admin",
|
||||
Token: "xxx",
|
||||
}
|
26
server/data/data.go
Normal file
26
server/data/data.go
Normal file
@ -0,0 +1,26 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
c "git.inspur.com/sbg-jszt/cfn/cfn-schedule/config"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var once sync.Once
|
||||
|
||||
func InitData() {
|
||||
once.Do(func() {
|
||||
if c.Config.DatabaseConfig.Type == "sqlite" {
|
||||
initSqlite()
|
||||
} else {
|
||||
initPostgres()
|
||||
}
|
||||
|
||||
initNats()
|
||||
initPrometheus()
|
||||
initXxlJob()
|
||||
if c.Config.Redis.Enable {
|
||||
// 初始化 redis
|
||||
initRedis()
|
||||
}
|
||||
})
|
||||
}
|
43
server/data/nats.go
Normal file
43
server/data/nats.go
Normal file
@ -0,0 +1,43 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
c "git.inspur.com/sbg-jszt/cfn/cfn-schedule/config"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/pkg/log"
|
||||
"github.com/nats-io/nats.go"
|
||||
"time"
|
||||
)
|
||||
|
||||
var Nc *nats.Conn
|
||||
|
||||
func initNats() {
|
||||
var err error
|
||||
// 此种链接方式在Ubuntu桌面版上报错:dial tcp: missing address
|
||||
//url := fmt.Sprintf("nats://%s:%s@%s", c.Config.Nats.User, c.Config.Nats.Password, c.Config.Nats.Url)
|
||||
//Nc, err = nats.Connect(url)
|
||||
|
||||
opts := []nats.Option{nats.Name("NATS Sample Publisher")}
|
||||
opts = append(opts, nats.UserInfo(c.Config.Nats.User, c.Config.Nats.Password))
|
||||
|
||||
log.Infof("Nats connect url: %s", "nats://"+c.Config.Nats.Url)
|
||||
log.Infof("Nats connect options: %v", opts)
|
||||
Nc, err = nats.Connect("nats://"+c.Config.Nats.Url, opts...)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("连接nats失败:%s, %s, %s", c.Config.Nats.Url, c.Config.Nats.User, c.Config.Nats.Password)
|
||||
panic("Nats connection failed:" + err.Error())
|
||||
}
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Errorf("recover check nats connection: %v", r)
|
||||
}
|
||||
}()
|
||||
const interval = time.Minute * 2
|
||||
ticker := time.NewTicker(interval)
|
||||
for _ = range ticker.C {
|
||||
if !Nc.IsConnected() {
|
||||
Nc, _ = nats.Connect("nats://"+c.Config.Nats.Url, opts...)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
70
server/data/postgres.go
Normal file
70
server/data/postgres.go
Normal file
@ -0,0 +1,70 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
c "git.inspur.com/sbg-jszt/cfn/cfn-schedule/config"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/pkg/log"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
"gorm.io/gorm/schema"
|
||||
)
|
||||
|
||||
var PostgreSqlDB = make(map[string]*gorm.DB)
|
||||
|
||||
type Writer interface {
|
||||
Printf(string, ...interface{})
|
||||
}
|
||||
|
||||
type WriterLog struct {
|
||||
}
|
||||
|
||||
func (w WriterLog) Printf(format string, args ...interface{}) {
|
||||
log.Logger.Sugar().Infof(format, args...)
|
||||
}
|
||||
|
||||
func initPostgres() {
|
||||
var err error
|
||||
postgreSqlConfigMap := c.Config.DatabaseConfig.PostgreSqlConfig
|
||||
if c.Config.DatabaseConfig.PostgreSqlConfig != nil && len(postgreSqlConfigMap) > 0 {
|
||||
for name, postgreSqlConfig := range postgreSqlConfigMap {
|
||||
var writerLog WriterLog
|
||||
if postgreSqlConfig.PrintSql {
|
||||
writerLog = WriterLog{}
|
||||
}
|
||||
logConfig := logger.New(
|
||||
writerLog,
|
||||
logger.Config{
|
||||
SlowThreshold: 0, // 慢 SQL 阈值
|
||||
LogLevel: logger.LogLevel(postgreSqlConfig.LogLevel), // 日志级别
|
||||
IgnoreRecordNotFoundError: false, // 忽略ErrRecordNotFound(记录未找到)错误
|
||||
Colorful: false, // 是否启用彩色打印
|
||||
},
|
||||
)
|
||||
|
||||
configs := &gorm.Config{
|
||||
NamingStrategy: schema.NamingStrategy{
|
||||
TablePrefix: postgreSqlConfig.TablePrefix, // 表名前缀
|
||||
// SingularTable: true, // 使用单数表名
|
||||
},
|
||||
Logger: logConfig,
|
||||
}
|
||||
|
||||
dsn := fmt.Sprintf("host=%s port=%d user=%s dbname=%s password=%s timezone='Asia/Shanghai'",
|
||||
postgreSqlConfig.Host,
|
||||
postgreSqlConfig.Port,
|
||||
postgreSqlConfig.Username,
|
||||
postgreSqlConfig.Database,
|
||||
postgreSqlConfig.Password,
|
||||
)
|
||||
|
||||
log.Infof("postgres客户端初始化, 配置: %s", dsn)
|
||||
PostgreSqlDB[name], err = gorm.Open(postgres.Open(dsn), configs)
|
||||
|
||||
if err != nil {
|
||||
panic("postgres connection failed:" + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
61
server/data/prometheus.go
Normal file
61
server/data/prometheus.go
Normal file
@ -0,0 +1,61 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/config"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/pkg/log"
|
||||
"github.com/prometheus/client_golang/api"
|
||||
v1 "github.com/prometheus/client_golang/api/prometheus/v1"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
var V1api v1.API
|
||||
|
||||
type authRoundTripper struct {
|
||||
auth string
|
||||
originalRT http.RoundTripper
|
||||
}
|
||||
|
||||
func (rt *authRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
req.Header.Set("Authorization", rt.auth)
|
||||
return rt.originalRT.RoundTrip(req)
|
||||
}
|
||||
|
||||
func newAuthRoundTripper(auth *config.PrometheusConfig, rt http.RoundTripper) http.RoundTripper {
|
||||
encoded := base64.StdEncoding.EncodeToString([]byte(auth.User + ":" + auth.Password))
|
||||
return &authRoundTripper{auth: "Basic " + encoded, originalRT: rt}
|
||||
}
|
||||
|
||||
func initPrometheus() {
|
||||
if !config.Config.CfnConfig.Enable {
|
||||
return
|
||||
}
|
||||
|
||||
apiConfig := api.Config{
|
||||
Address: config.Config.Prometheus.Url,
|
||||
}
|
||||
|
||||
if config.Config.Prometheus.AuthEnable {
|
||||
roundTripper := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).DialContext,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
apiConfig.RoundTripper = newAuthRoundTripper(&config.Config.Prometheus, roundTripper)
|
||||
}
|
||||
|
||||
log.Infof("Prometheus客户端初始化, 配置: %s", apiConfig.Address)
|
||||
client, err := api.NewClient(apiConfig)
|
||||
|
||||
if err != nil {
|
||||
log.Info("Error creating prometheus client: ", err.Error())
|
||||
}
|
||||
|
||||
V1api = v1.NewAPI(client)
|
||||
}
|
23
server/data/redis.go
Normal file
23
server/data/redis.go
Normal file
@ -0,0 +1,23 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"context"
|
||||
c "git.inspur.com/sbg-jszt/cfn/cfn-schedule/config"
|
||||
"github.com/go-redis/redis/v8"
|
||||
)
|
||||
|
||||
var Rdb *redis.Client
|
||||
|
||||
func initRedis() {
|
||||
Rdb = redis.NewClient(&redis.Options{
|
||||
Addr: c.Config.Redis.Host + ":" + c.Config.Redis.Port,
|
||||
Password: c.Config.Redis.Password,
|
||||
DB: c.Config.Redis.Database,
|
||||
})
|
||||
var ctx = context.Background()
|
||||
_, err := Rdb.Ping(ctx).Result()
|
||||
|
||||
if err != nil {
|
||||
panic("Redis connection failed:" + err.Error())
|
||||
}
|
||||
}
|
22
server/data/sqlite.go
Normal file
22
server/data/sqlite.go
Normal file
@ -0,0 +1,22 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/config"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/pkg/log"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var SqliteDB *gorm.DB
|
||||
|
||||
func initSqlite() {
|
||||
var err error
|
||||
|
||||
sqliteConfig := config.Config.DatabaseConfig.SqliteConfig
|
||||
log.Infof("sqlite客户端初始化, 配置: %s", sqliteConfig.Data)
|
||||
|
||||
SqliteDB, err = gorm.Open(sqlite.Open(sqliteConfig.Data), &gorm.Config{})
|
||||
if err != nil {
|
||||
panic("sqlite connection failed:" + err.Error())
|
||||
}
|
||||
}
|
50
server/data/xxljob.go
Normal file
50
server/data/xxljob.go
Normal file
@ -0,0 +1,50 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
c "git.inspur.com/sbg-jszt/cfn/cfn-schedule/config"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/pkg/log"
|
||||
"github.com/xxl-job/xxl-job-executor-go"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var Xxljob xxl.Executor
|
||||
|
||||
func initXxlJob() {
|
||||
if !c.Config.CfnConfig.Enable {
|
||||
return
|
||||
}
|
||||
|
||||
//初始化执行器
|
||||
Xxljob = xxl.NewExecutor(
|
||||
xxl.ServerAddr(c.Config.XxlJob.Url),
|
||||
xxl.AccessToken(c.Config.XxlJob.Token),
|
||||
xxl.ExecutorPort(strconv.FormatUint(c.Config.Server.Port, 10)), //默认9999(此处要与gin服务启动port必需一至)
|
||||
xxl.RegistryKey("cfn-schedule"), //执行器名称
|
||||
xxl.SetLogger(&clogger{}), //自定义日志
|
||||
)
|
||||
Xxljob.Init()
|
||||
//设置日志查看handler
|
||||
Xxljob.LogHandler(customLogHandle)
|
||||
}
|
||||
|
||||
// 自定义日志处理器
|
||||
func customLogHandle(req *xxl.LogReq) *xxl.LogRes {
|
||||
return &xxl.LogRes{Code: xxl.SuccessCode, Msg: "", Content: xxl.LogResContent{
|
||||
FromLineNum: req.FromLineNum,
|
||||
ToLineNum: 2,
|
||||
LogContent: "这个是自定义日志handler",
|
||||
IsEnd: true,
|
||||
}}
|
||||
}
|
||||
|
||||
// xxl.Logger接口实现
|
||||
type clogger struct{}
|
||||
|
||||
func (l *clogger) Info(format string, a ...interface{}) {
|
||||
log.Info(fmt.Sprintf("xxl-job日志 - "+format, a...))
|
||||
}
|
||||
|
||||
func (l *clogger) Error(format string, a ...interface{}) {
|
||||
log.Error(fmt.Sprintf("xxl-job日志 - "+format, a...))
|
||||
}
|
112
server/go.mod
Normal file
112
server/go.mod
Normal file
@ -0,0 +1,112 @@
|
||||
module git.inspur.com/sbg-jszt/cfn/cfn-schedule
|
||||
|
||||
go 1.23
|
||||
|
||||
toolchain go1.23.0
|
||||
|
||||
require (
|
||||
github.com/araujo88/lambda-go v0.0.0-20240731183007-b33464d3e215
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/gin-contrib/cors v1.3.1
|
||||
github.com/gin-gonic/gin v1.8.1
|
||||
github.com/go-playground/locales v0.14.0
|
||||
github.com/go-playground/universal-translator v0.18.0
|
||||
github.com/go-playground/validator/v10 v10.11.1
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
github.com/go-resty/resty/v2 v2.10.0
|
||||
github.com/golang/glog v1.0.0
|
||||
github.com/google/uuid v1.4.0
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
|
||||
github.com/minio/minio-go v6.0.14+incompatible
|
||||
github.com/natefinch/lumberjack v2.0.0+incompatible
|
||||
github.com/nats-io/nats.go v1.31.0
|
||||
github.com/prometheus/client_golang v1.17.0
|
||||
github.com/prometheus/common v0.44.0
|
||||
github.com/renstrom/shortuuid v3.0.0+incompatible
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/segmentio/ksuid v1.0.4
|
||||
github.com/spf13/viper v1.17.0
|
||||
github.com/xuri/excelize/v2 v2.8.0
|
||||
github.com/xxl-job/xxl-job-executor-go v1.2.0
|
||||
github.com/zeromicro/go-zero v1.6.0
|
||||
go.uber.org/zap v1.24.0
|
||||
golang.org/x/crypto v0.21.0
|
||||
gorm.io/datatypes v1.2.0
|
||||
gorm.io/driver/postgres v1.5.2
|
||||
gorm.io/driver/sqlite v1.4.3
|
||||
gorm.io/gorm v1.25.0
|
||||
gorm.io/plugin/soft_delete v1.1.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/fatih/color v1.15.0 // indirect
|
||||
github.com/go-basic/ipv4 v1.0.0 // indirect
|
||||
github.com/go-ini/ini v1.67.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.7.1 // indirect
|
||||
github.com/klauspost/compress v1.17.4 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.15 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||
github.com/nats-io/nkeys v0.4.6 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/richardlehane/mscfb v1.0.4 // indirect
|
||||
github.com/richardlehane/msoleps v1.0.3 // indirect
|
||||
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca // indirect
|
||||
github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a // indirect
|
||||
go.opentelemetry.io/otel v1.19.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.19.0 // indirect
|
||||
go.uber.org/automaxprocs v1.5.3 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
gorm.io/driver/mysql v1.4.7 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.2.1 // indirect
|
||||
github.com/ahmetb/go-linq v3.0.0+incompatible
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/goccy/go-json v0.9.11
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||
github.com/jackc/pgx/v5 v5.4.3 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/lestrrat-go/strftime v1.0.6 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/onsi/gomega v1.20.1 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/sagikazarmark/locafero v0.3.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.10.0 // indirect
|
||||
github.com/spf13/cast v1.5.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/ugorji/go/codec v1.2.7 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect
|
||||
golang.org/x/net v0.23.0 // indirect
|
||||
golang.org/x/sys v0.24.0 // indirect
|
||||
golang.org/x/text v0.14.0
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
773
server/go.sum
Normal file
773
server/go.sum
Normal file
@ -0,0 +1,773 @@
|
||||
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/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
|
||||
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/ahmetb/go-linq v3.0.0+incompatible h1:qQkjjOXKrKOTy83X8OpRmnKflXKQIL/mC/gMVVDMhOA=
|
||||
github.com/ahmetb/go-linq v3.0.0+incompatible/go.mod h1:PFffvbdbtw+QTB0WKRP0cNht7vnCfnGlEpak/DVg5cY=
|
||||
github.com/araujo88/lambda-go v0.0.0-20240731183007-b33464d3e215 h1:cuA5Yg1IPMUxWXwuu4dW7tZhjgFI2Lkv1qIaMhHV/TM=
|
||||
github.com/araujo88/lambda-go v0.0.0-20240731183007-b33464d3e215/go.mod h1:aFEe3R1EyXWn1ikzW0zgjqWUvhHxwwfhLvhXMb/z354=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
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.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
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/gin-contrib/cors v1.3.1 h1:doAsuITavI4IOcd0Y19U4B+O0dNWihRyX//nn4sEmgA=
|
||||
github.com/gin-contrib/cors v1.3.1/go.mod h1:jjEJ4268OPZUcU7k9Pm653S7lXUGcqMADzFA61xsmDk=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
|
||||
github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8=
|
||||
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
|
||||
github.com/go-basic/ipv4 v1.0.0 h1:gjyFAa1USC1hhXTkPOwBWDPfMcUaIM+tvo1XzV9EZxs=
|
||||
github.com/go-basic/ipv4 v1.0.0/go.mod h1:etLBnaxbidQfuqE6wgZQfs38nEWNmzALkxDZe4xY8Dg=
|
||||
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-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
|
||||
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
|
||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
|
||||
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
|
||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||
github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
|
||||
github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
|
||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||
github.com/go-resty/resty/v2 v2.10.0 h1:Qla4W/+TMmv0fOeeRqzEpXPLfTUnR5HZ1+lGs+CkiCo=
|
||||
github.com/go-resty/resty/v2 v2.10.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A=
|
||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
|
||||
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
|
||||
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/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/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
|
||||
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
|
||||
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/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
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/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
||||
github.com/google/uuid v1.4.0/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/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
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/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/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY=
|
||||
github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
|
||||
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
||||
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
|
||||
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
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.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
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.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
|
||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8=
|
||||
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is=
|
||||
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4=
|
||||
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA=
|
||||
github.com/lestrrat-go/strftime v1.0.6 h1:CFGsDEt1pOpFNU+TJB0nhz9jl+K0hZSLE205AhTIGQQ=
|
||||
github.com/lestrrat-go/strftime v1.0.6/go.mod h1:f7jQKgV5nnJpYgdEasS+/y7EsTb8ykN2z68n3TtcTaw=
|
||||
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.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
|
||||
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
||||
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE=
|
||||
github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ=
|
||||
github.com/minio/minio-go v6.0.14+incompatible h1:fnV+GD28LeqdN6vT2XdGKW8Qe/IfjJDswNVuni6km9o=
|
||||
github.com/minio/minio-go v6.0.14+incompatible/go.mod h1:7guKYtitv8dktvNUGrhzmNlA5wrAABTQXCoesZdFQO8=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=
|
||||
github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=
|
||||
github.com/nats-io/nats.go v1.31.0 h1:/WFBHEc/dOKBF6qf1TZhrdEfTmOZ5JzdJ+Y3m6Y/p7E=
|
||||
github.com/nats-io/nats.go v1.31.0/go.mod h1:di3Bm5MLsoB4Bx61CBTsxuarI36WbhAwOm8QrW39+i8=
|
||||
github.com/nats-io/nkeys v0.4.6 h1:IzVe95ru2CT6ta874rt9saQRkWfe2nFj1NtvYSLqMzY=
|
||||
github.com/nats-io/nkeys v0.4.6/go.mod h1:4DxZNzenSVd1cYQoAa8948QY3QDjrHfcfVADymtkpts=
|
||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
|
||||
github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo=
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
|
||||
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
||||
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
||||
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
|
||||
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM=
|
||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
|
||||
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
|
||||
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
|
||||
github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
|
||||
github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
|
||||
github.com/renstrom/shortuuid v3.0.0+incompatible h1:F6T1U7bWlI3FTV+JE8HyeR7bkTeYZJntqQLA9ST4HOQ=
|
||||
github.com/renstrom/shortuuid v3.0.0+incompatible/go.mod h1:n18Ycpn8DijG+h/lLBQVnGKv1BCtTeXo8KKSbBOrQ8c=
|
||||
github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM=
|
||||
github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
|
||||
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
|
||||
github.com/richardlehane/msoleps v1.0.3 h1:aznSZzrwYRl3rLKRT3gUk9am7T/mLNSnJINvN0AQoVM=
|
||||
github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ=
|
||||
github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||
github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c=
|
||||
github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY=
|
||||
github.com/spf13/afero v1.10.0/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/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.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI=
|
||||
github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI=
|
||||
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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
|
||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||
github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca h1:uvPMDVyP7PXMMioYdyPH+0O+Ta/UO1WFfNYMO3Wz0eg=
|
||||
github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
|
||||
github.com/xuri/excelize/v2 v2.8.0 h1:Vd4Qy809fupgp1v7X+nCS/MioeQmYVVzi495UCTqB7U=
|
||||
github.com/xuri/excelize/v2 v2.8.0/go.mod h1:6iA2edBTKxKbZAa7X5bDhcCg51xdOn1Ar5sfoXRGrQg=
|
||||
github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a h1:Mw2VNrNNNjDtw68VsEj2+st+oCSn4Uz7vZw6TbhcV1o=
|
||||
github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
|
||||
github.com/xxl-job/xxl-job-executor-go v1.2.0 h1:MTl2DpwrK2+hNjRRks2k7vB3oy+3onqm9OaSarneeLQ=
|
||||
github.com/xxl-job/xxl-job-executor-go v1.2.0/go.mod h1:bUFhz/5Irp9zkdYk5MxhQcDDT6LlZrI8+rv5mHtQ1mo=
|
||||
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/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/zeromicro/go-zero v1.6.0 h1:UwSOR1lGZ2g7L0S07PM8RoneAcubtd5x//EfbuNucQ0=
|
||||
github.com/zeromicro/go-zero v1.6.0/go.mod h1:E9GCFPb0SwsTKFBcFr9UynGvXiDMmfc6fI5F15vqvAQ=
|
||||
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=
|
||||
go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs=
|
||||
go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY=
|
||||
go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE=
|
||||
go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8=
|
||||
go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o=
|
||||
go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A=
|
||||
go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg=
|
||||
go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo=
|
||||
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
|
||||
go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
|
||||
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
||||
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
|
||||
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
||||
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
||||
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||
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-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
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/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
|
||||
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/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo=
|
||||
golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
|
||||
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/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
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-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
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/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4=
|
||||
golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4=
|
||||
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/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/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-20190813064441-fde4db37ae7a/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-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-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
||||
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
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/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
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/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
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/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||
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=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||
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/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
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=
|
||||
gorm.io/datatypes v1.2.0 h1:5YT+eokWdIxhJgWHdrb2zYUimyk0+TaFth+7a0ybzco=
|
||||
gorm.io/datatypes v1.2.0/go.mod h1:o1dh0ZvjIjhH/bngTpypG6lVRJ5chTBxE09FH/71k04=
|
||||
gorm.io/driver/mysql v1.4.7 h1:rY46lkCspzGHn7+IYsNpSfEv9tA+SU4SkkB+GFX125Y=
|
||||
gorm.io/driver/mysql v1.4.7/go.mod h1:SxzItlnT1cb6e1e4ZRpgJN2VYtcqJgqnHxWr4wsP8oc=
|
||||
gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0=
|
||||
gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8=
|
||||
gorm.io/driver/sqlite v1.1.3/go.mod h1:AKDgRWk8lcSQSw+9kxCJnX/yySj8G3rdwYlU57cB45c=
|
||||
gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU=
|
||||
gorm.io/driver/sqlite v1.4.3/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI=
|
||||
gorm.io/driver/sqlserver v1.4.1 h1:t4r4r6Jam5E6ejqP7N82qAJIJAht27EGT41HyPfXRw0=
|
||||
gorm.io/driver/sqlserver v1.4.1/go.mod h1:DJ4P+MeZbc5rvY58PnmN1Lnyvb5gw5NPzGshHDnJLig=
|
||||
gorm.io/gorm v1.20.1/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
gorm.io/gorm v1.23.0/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
||||
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
||||
gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
|
||||
gorm.io/gorm v1.25.0 h1:+KtYtb2roDz14EQe4bla8CbQlmb9dN3VejSai3lprfU=
|
||||
gorm.io/gorm v1.25.0/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
||||
gorm.io/plugin/soft_delete v1.1.0 h1:LcE4L+GD29RkkMLxMYHpT4wQCJ/9945FsdU/mHGaDuE=
|
||||
gorm.io/plugin/soft_delete v1.1.0/go.mod h1:Zv7vQctOJTGOsJ/bWgrN1n3od0GBAZgnLjEx+cApLGk=
|
||||
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=
|
30
server/internal/command/command.go
Normal file
30
server/internal/command/command.go
Normal file
@ -0,0 +1,30 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/func_make"
|
||||
)
|
||||
|
||||
var (
|
||||
commandMap = map[string]interface{}{
|
||||
"demo": demo,
|
||||
}
|
||||
funcMake = func_make.New()
|
||||
)
|
||||
|
||||
func Register() {
|
||||
err := funcMake.Registers(commandMap)
|
||||
if err != nil {
|
||||
panic("failed to register console command: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func Run(funcName string) {
|
||||
Register()
|
||||
_, err := funcMake.Call(funcName)
|
||||
if err != nil {
|
||||
fmt.Printf("execution failed, error cause: %v \n", err.Error())
|
||||
return
|
||||
}
|
||||
fmt.Printf("complete! \n")
|
||||
}
|
7
server/internal/command/demo.go
Normal file
7
server/internal/command/demo.go
Normal file
@ -0,0 +1,7 @@
|
||||
package command
|
||||
|
||||
import "fmt"
|
||||
|
||||
func demo() {
|
||||
fmt.Println("hello console!")
|
||||
}
|
54
server/internal/controller/base.go
Normal file
54
server/internal/controller/base.go
Normal file
@ -0,0 +1,54 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
r "git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/response"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/pkg/log"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// Success 业务成功响应
|
||||
func Success(c *gin.Context, data ...any) {
|
||||
response := r.Resp()
|
||||
if data != nil {
|
||||
response.WithDataSuccess(c, data[0])
|
||||
return
|
||||
}
|
||||
response.Success(c)
|
||||
}
|
||||
|
||||
// FailCode 业务失败响应
|
||||
func FailCode(c *gin.Context, code int, err error, data ...any) {
|
||||
response := r.Resp()
|
||||
if err != nil {
|
||||
log.Errorf("异常: %v", err.Error())
|
||||
}
|
||||
if data != nil {
|
||||
response.WithData(data[0]).FailCode(c, code)
|
||||
return
|
||||
}
|
||||
response.FailCode(c, code)
|
||||
}
|
||||
|
||||
// Fail 业务失败响应
|
||||
func Fail(c *gin.Context, code int, message string, data ...any) {
|
||||
response := r.Resp()
|
||||
if data != nil {
|
||||
response.WithData(data[0]).FailCode(c, code, message)
|
||||
return
|
||||
}
|
||||
response.FailCode(c, code, message)
|
||||
}
|
||||
|
||||
// Err 判断错误类型是自定义类型则自动返回错误中携带的code和message,否则返回服务器错误
|
||||
func Err(c *gin.Context, e error) {
|
||||
businessError, err := errors.AsBusinessError(e)
|
||||
if err != nil {
|
||||
log.Logger.Warn("Unknown error:", zap.Any("Error reason:", err))
|
||||
FailCode(c, errors.ServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
Fail(c, businessError.GetCode(), businessError.GetMessage())
|
||||
}
|
137
server/internal/controller/v1/agentinfo.go
Normal file
137
server/internal/controller/v1/agentinfo.go
Normal file
@ -0,0 +1,137 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/agent"
|
||||
devc "git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/device"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/validator"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 获取最新版本列表
|
||||
func ListLastVersion(c *gin.Context) {
|
||||
aget := &agent.AgentInfo{}
|
||||
agents, err := aget.ListLastVersion()
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, agents)
|
||||
}
|
||||
|
||||
// 发布新版本
|
||||
func Release(c *gin.Context) {
|
||||
aget := &agent.AgentInfo{}
|
||||
err := validator.CheckPostParams(c, aget)
|
||||
if aget.BucketName == "" {
|
||||
aget.BucketName = "cpn"
|
||||
}
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
//转换版本号
|
||||
masterVersion := "10"
|
||||
secondVersion := "0"
|
||||
minVersion := "0"
|
||||
version := strings.Split(aget.Version, ".")
|
||||
if len(version[0]) < 2 {
|
||||
masterVersion = masterVersion + version[0]
|
||||
} else {
|
||||
masterVersion = "1" + version[0]
|
||||
}
|
||||
if len(version[1]) < 2 {
|
||||
secondVersion = secondVersion + version[1]
|
||||
} else {
|
||||
secondVersion = version[1]
|
||||
}
|
||||
if len(version[2]) < 2 {
|
||||
minVersion = minVersion + version[2]
|
||||
} else {
|
||||
minVersion = version[2]
|
||||
}
|
||||
versionNum, err := strconv.Atoi(masterVersion + secondVersion + minVersion)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
agents := make([]agent.AgentInfo, 0)
|
||||
agetJson, _ := json.Marshal(aget)
|
||||
for _, t := range strings.Split(aget.OsType, ",") {
|
||||
fields := map[string]interface{}{}
|
||||
fields["os_type"] = t
|
||||
fields["arch_type"] = aget.ArchType
|
||||
fields["version_num"] = versionNum
|
||||
b, err := aget.HasNewVersion(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
if b {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "版本号重复或小于历史版本!")
|
||||
return
|
||||
}
|
||||
agt := agent.AgentInfo{}
|
||||
json.Unmarshal(agetJson, &agt)
|
||||
agt.OsType = t
|
||||
agt.VersionNum = int64(versionNum)
|
||||
if t == agent.OS_WINDOWS {
|
||||
agt.OsPlatform = agent.OS_WINDOWS
|
||||
} else if strings.Contains(agent.OS_LINUX_LIST, t) {
|
||||
agt.OsPlatform = agent.OS_LINUX
|
||||
} else {
|
||||
agt.OsPlatform = "Other"
|
||||
}
|
||||
//不同平台+不同操作系统+不同架构添加多条记录
|
||||
agents = append(agents, agt)
|
||||
}
|
||||
_, err = aget.CreateBatch(agents)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "数据库错误!")
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
_ = service.SendUpgradeCommand(agents)
|
||||
}()
|
||||
go func() {
|
||||
dr := &devc.DeviceUpgradeRule{}
|
||||
rules, err := dr.ListAll(nil)
|
||||
if err == nil && len(rules) > 0 {
|
||||
_ = service.SendUpgradePlans(rules, "create")
|
||||
}
|
||||
}()
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
type PageBodyVersion struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
Keyword string `json:"keyword"`
|
||||
}
|
||||
|
||||
// 根据扩展key获取规则
|
||||
func PageVersions(c *gin.Context) {
|
||||
var pageBody PageBodyVersion
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
agt := &agent.AgentInfo{}
|
||||
fields := map[string]interface{}{}
|
||||
fields["keyword"] = pageBody.Keyword
|
||||
page := &model.Page[agent.AgentInfo]{}
|
||||
page.Covert(pageBody.PageInfo)
|
||||
err = agt.Page(page, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, page)
|
||||
}
|
504
server/internal/controller/v1/app_manage/assets/machine.go
Normal file
504
server/internal/controller/v1/app_manage/assets/machine.go
Normal file
@ -0,0 +1,504 @@
|
||||
package assets
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
err1 "errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
node2 "git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/node"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/workspace"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/assets"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/common"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/validator"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type MachinePageBody struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
GroupName string `json:"groupName"`
|
||||
}
|
||||
|
||||
type T struct {
|
||||
GroupName string `json:"groupName"`
|
||||
Version string `json:"version"`
|
||||
Name string `json:"name"`
|
||||
PageInfo struct {
|
||||
CurrentPage int `json:"currentPage"`
|
||||
Order string `json:"order"`
|
||||
OrderField string `json:"order_field"`
|
||||
PageSize int `json:"pageSize"`
|
||||
} `json:"pageInfo"`
|
||||
}
|
||||
|
||||
func PageMachine(c *gin.Context) {
|
||||
var pageBody MachinePageBody
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
//pageBody.PageInfo.Order = "create_time_millis desc"
|
||||
n := node2.NewMachine()
|
||||
fields := map[string]interface{}{}
|
||||
if pageBody.Name != "" {
|
||||
fields["name"] = pageBody.Name
|
||||
}
|
||||
if pageBody.Version != "" {
|
||||
fields["cfn_agent_version"] = pageBody.Version
|
||||
}
|
||||
if pageBody.GroupName != "" {
|
||||
fields["group_name"] = pageBody.GroupName
|
||||
}
|
||||
page := &model.PageConfig{}
|
||||
page.Covert(pageBody.PageInfo)
|
||||
result, err := n.Page(n, page, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
page.Data = result
|
||||
controller.Success(c, page)
|
||||
}
|
||||
|
||||
func EditMachine(c *gin.Context) {
|
||||
n := &node2.MachineNode{}
|
||||
err := validator.CheckPostParams(c, n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
if n.Id == "" {
|
||||
n.Handler = n
|
||||
fields := map[string]interface{}{}
|
||||
fields["cfn_agent_url"] = n.CfnAgentUrl
|
||||
list, err := n.GetAll(n, fields, nil)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "数据库错误!")
|
||||
return
|
||||
}
|
||||
if len(list.([]node2.MachineNode)) > 0 {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "对应的节点已经存在啦")
|
||||
return
|
||||
}
|
||||
}
|
||||
err = assets.TestMachineNode(n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "节点连接失败,请检查节点是否在线")
|
||||
return
|
||||
}
|
||||
status := 1
|
||||
n.Status = status
|
||||
// testHttpProxy()
|
||||
if n.Id == "" {
|
||||
m := 0
|
||||
n.TransportMode = m
|
||||
n.SetUserName(service.GetUserName(c))
|
||||
_, err = n.Create(n)
|
||||
} else {
|
||||
n.SetModifyUserName(service.GetUserName(c))
|
||||
column := []string{"name", "group_name", "cfn_agent_url", "cfn_agent_username", "cfn_agent_password", "template_node", "cfn_agent_timeout", "cfn_agent_http_proxy", "cfn_agent_http_proxy_type", "transport_encryption"}
|
||||
_, err = n.Update(n, column)
|
||||
}
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "数据库错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
func DeleteMachine(c *gin.Context) {
|
||||
id := c.PostForm("id")
|
||||
if id == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
m := &node2.MachineNode{}
|
||||
m.Id = id
|
||||
err := m.GetById(m)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
n := node2.New()
|
||||
fields := make(map[string]interface{})
|
||||
fields["machine_id"] = id
|
||||
list, err := n.GetAll(n, fields, nil)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "数据库错误!")
|
||||
return
|
||||
}
|
||||
count := len(list.([]node2.Node))
|
||||
if count > 0 {
|
||||
controller.FailCode(c, errors.ServerError, err, "当前机器还关联"+strconv.Itoa(count)+"个节点,不能删除")
|
||||
return
|
||||
}
|
||||
|
||||
_, err = m.Delete(m)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "数据库错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
func Distribute(c *gin.Context) {
|
||||
ids := c.PostForm("ids")
|
||||
if ids == "" {
|
||||
controller.Success(c, "")
|
||||
return
|
||||
}
|
||||
mids := strings.Split(ids, ",")
|
||||
if len(mids) == 0 {
|
||||
controller.Success(c, "")
|
||||
return
|
||||
}
|
||||
workspaceId := c.PostForm("workspaceId")
|
||||
w := &workspace.Workspace{}
|
||||
w.Id = workspaceId
|
||||
err := w.GetById(w)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "工作空间不存在!")
|
||||
return
|
||||
}
|
||||
|
||||
fields := map[string]interface{}{}
|
||||
fields["workspace_id"] = workspaceId
|
||||
for _, mid := range mids {
|
||||
m := &node2.MachineNode{}
|
||||
m.Id = mid
|
||||
err = m.GetById(m)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "机器不存在!")
|
||||
return
|
||||
}
|
||||
n := node2.New()
|
||||
fields["machine_id"] = mid
|
||||
list, _ := n.GetAll(n, fields, nil)
|
||||
if len(list.([]node2.Node)) > 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
n = &node2.Node{}
|
||||
n.MachineId = m.Id
|
||||
n.WorkspaceId = workspaceId
|
||||
n.Name = m.Name
|
||||
n.OpenStatus = 1
|
||||
n.Group = m.Group
|
||||
n.Url = m.CfnAgentUrl
|
||||
n.LoginName = m.CfnAgentUsername
|
||||
n.LoginPwd = m.CfnAgentPassword
|
||||
n.SetUserName(service.GetUserName(c))
|
||||
_, err = n.Create(n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "数据库错误!")
|
||||
return
|
||||
}
|
||||
}
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
func ListMachineGroup(c *gin.Context) {
|
||||
m := &node2.MachineNode{}
|
||||
result, _ := m.ListGroup()
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
func ListTemplateNode(c *gin.Context) {
|
||||
m := node2.NewMachine()
|
||||
fields := map[string]interface{}{}
|
||||
fields["template_node"] = 1
|
||||
result, err := m.GetAll(m, fields, nil)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "数据库错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
func Whitelist(c *gin.Context) {
|
||||
machineId := c.PostForm("machineId")
|
||||
m := &node2.MachineNode{}
|
||||
m.Id = machineId
|
||||
err := m.GetById(m)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "没有对应的机器")
|
||||
return
|
||||
}
|
||||
|
||||
result := assets.GetAgentWhitelist(m)
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
func SaveWhitelist(c *gin.Context) {
|
||||
ids := c.PostForm("ids")
|
||||
if ids == "" {
|
||||
controller.Success(c, "")
|
||||
return
|
||||
}
|
||||
mids := strings.Split(ids, ",")
|
||||
if len(mids) == 0 {
|
||||
controller.Success(c, "")
|
||||
return
|
||||
}
|
||||
formData := make(map[string]string)
|
||||
for key, value := range c.Request.PostForm {
|
||||
formData[key] = value[0]
|
||||
}
|
||||
body, _ := json.Marshal(formData)
|
||||
for _, mid := range mids {
|
||||
m := &node2.MachineNode{}
|
||||
m.Id = mid
|
||||
err := m.GetById(m)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "没有对应的机器")
|
||||
return
|
||||
}
|
||||
resp, err := common.Request(m, "", common.WhitelistDirectory_Submit, nil, nil, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "分发节点失败")
|
||||
return
|
||||
}
|
||||
if !resp.IsBusinessSuccess() {
|
||||
controller.FailCode(c, errors.ServerError, err1.New(resp.Result.Msg), "分发节点失败")
|
||||
return
|
||||
}
|
||||
}
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
const config_data = `jpom:
|
||||
# jpom 数据存储路径, 如果调试模式运行默认路径为【${user.home}/jpom/】,安装运行默认为jar包文件的父级
|
||||
path:
|
||||
# 集群配置
|
||||
cluster:
|
||||
# 集群Id,默认为 default 不区分大小写,只能是字母或者数字,长度小于 20
|
||||
id: default
|
||||
# 心跳监控时间 (需要大于零) 单位秒 最小配置 5 秒
|
||||
heart-second: 30
|
||||
node:
|
||||
# 节点心跳监控时间 (需要大于零) 单位秒 最小配置 5秒
|
||||
heart-second: 30
|
||||
# 节点统计日志保留天数,如果小于等于 0 不自动删除
|
||||
stat-log-keep-days: 3
|
||||
# 上传文件的超时时间 单位秒,最短5秒钟
|
||||
upload-file-timeout: 300
|
||||
# 节点文件分片上传大小,单位 M,建议小于 5MB(需要考虑插件端上传文件大小限制)
|
||||
upload-file-slice-size: 1
|
||||
# 节点文件分片上传并发数,最小1 最大 服务端 CPU 核心数
|
||||
upload-file-concurrent: 2
|
||||
# web socket 消息最大长度
|
||||
web-socket-message-size-limit: 5MB
|
||||
system:
|
||||
# cron 定时器是否开启匹配秒
|
||||
timer-match-second: false
|
||||
# 旧包文件保留个数
|
||||
old-jars-count: 2
|
||||
# 系统日志编码格式
|
||||
log-charset: UTF-8
|
||||
# 控制台编码格式
|
||||
console-charset:
|
||||
# 在线升级允许降级-操作
|
||||
allowed-downgrade: false
|
||||
user:
|
||||
# 用户连续登录失败次数,超过此数将被限制登录
|
||||
always-login-error: 5
|
||||
# IP连续登录失败次数,超过此数将被限制登录
|
||||
always-ip-login-error: 10
|
||||
# 当ip连续登录失败,锁定对应IP时长,5h、1d
|
||||
ip-error-lock-time: 5h
|
||||
# 是否强制提醒用户开启 mfa
|
||||
force-mfa: false
|
||||
#登录token失效时间(单位:小时),默认为24
|
||||
token-expired: 24
|
||||
#登录token失效后自动续签时间(单位:分钟),默认为60,不自动续签
|
||||
token-renewal: 60
|
||||
# jwt 签名(加密)的key 长度建议控制到 16位
|
||||
token-jwt-key:
|
||||
web:
|
||||
# 前端接口 超时时间 单位秒(最小 5 秒)
|
||||
api-timeout: 20
|
||||
# 禁用页面引导导航
|
||||
disabled-guide: false
|
||||
# 禁用登录图形验证码 (一般用于服务器没有字体或者开启了两部验证后才关闭图形验证码)
|
||||
disabled-captcha: false
|
||||
# 前端消息弹出位置,可选 topLeft topRight bottomLeft bottomRight
|
||||
notification-placement:
|
||||
# 前端消息传输需要编码或者加密 目前支持:NONE、BASE64
|
||||
transport-encryption: NONE
|
||||
# 查看日志时初始读取最后多少行(默认10,0不读取)
|
||||
init-read-line: 10
|
||||
db:
|
||||
# 数据库默认 支持 :H2、MYSQL
|
||||
mode: H2
|
||||
# 日志存储条数,将自动清理旧数据,配置小于等于零则不清理
|
||||
log-storage-count: 10000
|
||||
# H2 模式无需配置 mysql 配置 jdbc 地址
|
||||
url:
|
||||
# 数据库账号 默认 jpom
|
||||
user-name: jpom
|
||||
# 数据库密码 默认 jpom 如果自行配置请保证密码强度
|
||||
user-pwd: jpom
|
||||
# h2 数据库缓存大小 kilobyte 1KB 1,024 megabyte 1MB 1,048,576
|
||||
cache-size: 50MB
|
||||
# 自动备份间隔天数 小于等于 0 不自动备份
|
||||
auto-backup-interval-day: 1
|
||||
# 自动备份保留天数 小于等于 0,不自动删除自动备份数据
|
||||
auto-backup-reserve-day: 5
|
||||
# 数据库连接池相关配置
|
||||
max-active: 500
|
||||
initial-size: 10
|
||||
max-wait: 10
|
||||
min-idle: 1
|
||||
# 控制台是否打印 sql 信息
|
||||
show-sql: false
|
||||
# 构建相关配置
|
||||
build:
|
||||
# 最多保存多少份历史记录
|
||||
max-history-count: 1000
|
||||
# 单个最多保存多少份历史记录
|
||||
item-max-history-count: 50
|
||||
# 构建命令是否检查 存在删除命令
|
||||
check-delete-command: true
|
||||
# 构建线程池大小,小于 1 则为不限制,默认大小为 5
|
||||
pool-size: 5
|
||||
# 构建任务等待数量,超过此数量将取消构建任务,值最小为 1
|
||||
pool-wait-queue: 10
|
||||
# 日志显示 压缩折叠显示进度比例 范围 1-100
|
||||
log-reduce-progress-ratio: 5
|
||||
file-storage:
|
||||
# 文件中心存储路径
|
||||
save-pah:
|
||||
scan-static-dir-cron: 0 0/1 * * *
|
||||
# 是否开启静态文件目录监听
|
||||
watch-monitor-static-dir: true
|
||||
# 监听静态文件目录层级
|
||||
watch-monitor-max-depth: 5
|
||||
assets:
|
||||
# 监控线程池大小,小于等于0 为CPU核心数
|
||||
monitor-pool-size: 0
|
||||
# 监控任务等待数量,超过此数量将取消监控任务,值最小为 1
|
||||
monitor-pool-wait-queue: 500
|
||||
# ssh 资产
|
||||
ssh:
|
||||
# 监控频率
|
||||
monitor-cron: 0 0/1 * * * ?
|
||||
# 指定分组不启用监控功能(如果想禁用所有配置 * 即可)
|
||||
disable-monitor-group-name:
|
||||
- 禁用监控
|
||||
# docker 资产
|
||||
docker:
|
||||
# 监控频率
|
||||
monitor-cron: 0 0/1 * * * ?
|
||||
server:
|
||||
#运行端口号
|
||||
port: 2122
|
||||
servlet:
|
||||
session:
|
||||
cookie:
|
||||
name: JPOMID-SERVER
|
||||
timeout: 1H
|
||||
encoding:
|
||||
charset: UTF-8
|
||||
force: true
|
||||
enabled: true
|
||||
forceRequest: true
|
||||
forceResponse: true
|
||||
compression:
|
||||
# gzip 压缩
|
||||
enabled: true
|
||||
#mime-types: application/json,application/xml,text/html,text/xml,text/plain,application/javascript,image/png
|
||||
min-response-size: 2048
|
||||
tomcat:
|
||||
uri-encoding: UTF-8
|
||||
spring:
|
||||
web:
|
||||
resources:
|
||||
static-locations: classpath:/dist/
|
||||
cache:
|
||||
period: 1D
|
||||
mvc:
|
||||
throw-exception-if-no-handler-found: true
|
||||
log-request-details: true
|
||||
servlet:
|
||||
multipart:
|
||||
# 上传文件大小限制
|
||||
max-request-size: 2GB
|
||||
max-file-size: 1GB
|
||||
h2:
|
||||
console:
|
||||
# 是否开启 web 访问数据库(url: http://${ip}:${port}/h2-console)
|
||||
enabled: false
|
||||
# 是否允许远程访问(开启此配置有安全风险),默认为 false(当部署到服务器上之后,是否可以通过其他浏览器访问数据库)
|
||||
settings:
|
||||
web-allow-others: false
|
||||
`
|
||||
|
||||
func ConfigData(c *gin.Context) {
|
||||
machineId := c.PostForm("machineId")
|
||||
m := &node2.MachineNode{}
|
||||
m.Id = machineId
|
||||
err := m.GetById(m)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "没有对应的机器")
|
||||
return
|
||||
}
|
||||
resp, err := common.Request3(m, "", common.SystemGetConfig, nil)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "分发节点失败")
|
||||
return
|
||||
}
|
||||
if !resp.IsBusinessSuccess() {
|
||||
controller.FailCode(c, errors.ServerError, err1.New(resp.Result.Msg), "分发节点失败")
|
||||
return
|
||||
}
|
||||
controller.Success(c, resp.Result.Data)
|
||||
}
|
||||
|
||||
// todo 暂不允许修改运行配置
|
||||
func SaveConfig(c *gin.Context) {
|
||||
ids := c.PostForm("ids")
|
||||
if ids == "" {
|
||||
controller.Success(c, "")
|
||||
return
|
||||
}
|
||||
mids := strings.Split(ids, ",")
|
||||
if len(mids) == 0 {
|
||||
controller.Success(c, "")
|
||||
return
|
||||
}
|
||||
|
||||
content := c.PostForm("content")
|
||||
restart := c.PostForm("restart")
|
||||
|
||||
formData := make(map[string]string)
|
||||
formData["content"] = content
|
||||
formData["restart"] = restart
|
||||
|
||||
for _, mid := range mids {
|
||||
m := &node2.MachineNode{}
|
||||
m.Id = mid
|
||||
err := m.GetById(m)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "没有对应的机器")
|
||||
return
|
||||
}
|
||||
resp, err := common.Request4(m, common.SystemSaveConfig, formData)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "分发节点失败")
|
||||
return
|
||||
}
|
||||
if !resp.IsSuccess() {
|
||||
controller.FailCode(c, errors.ServerError, err1.New(resp.Result.Msg), "分发节点失败")
|
||||
return
|
||||
}
|
||||
}
|
||||
controller.Success(c, "修改成功")
|
||||
}
|
322
server/internal/controller/v1/app_manage/common.go
Normal file
322
server/internal/controller/v1/app_manage/common.go
Normal file
@ -0,0 +1,322 @@
|
||||
package app_manage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/node"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/response"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/common"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/pkg/log"
|
||||
"github.com/gin-gonic/gin"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GetWorkspaceId(c *gin.Context) string {
|
||||
return c.GetHeader("workspaceId")
|
||||
}
|
||||
|
||||
var ShardingIdMap = make(map[string]bool, 200)
|
||||
|
||||
func TryGetNode(body map[string]interface{}) (*node.Node, error) {
|
||||
nodeId, _ := body["nodeId"].(string)
|
||||
n := &node.Node{}
|
||||
n.Id = nodeId
|
||||
err := n.GetById(n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// String[] removeKeys, String... appendData
|
||||
// application/json类型请求
|
||||
func TryRequestNode(machineId string, body map[string]interface{}, nodeUrl string, pars ...string) *response.Response {
|
||||
n, _ := TryGetNode(body)
|
||||
marshal, _ := json.Marshal(body)
|
||||
|
||||
if n != nil {
|
||||
resp, err := common.Request5(n, nodeUrl, bytes.NewReader(marshal))
|
||||
if err != nil {
|
||||
log.Errorf("发送请求失败: %s", n.Url+"/"+nodeUrl)
|
||||
resp = &response.Response{
|
||||
HttpCode: errors.ServerError,
|
||||
Result: &response.Result{
|
||||
Msg: "发送请求失败:" + err.Error(),
|
||||
Data: nil,
|
||||
Cost: "",
|
||||
Now: time.Now(),
|
||||
Code: errors.ServerError,
|
||||
},
|
||||
}
|
||||
return resp
|
||||
}
|
||||
return resp
|
||||
} else {
|
||||
if len(machineId) > 0 {
|
||||
m := &node.MachineNode{}
|
||||
m.Id = machineId
|
||||
err := m.GetById(m)
|
||||
if err != nil {
|
||||
log.Errorf("发送请求失败: %s", machineId+":"+nodeUrl)
|
||||
resp := &response.Response{
|
||||
HttpCode: errors.ServerError,
|
||||
Result: &response.Result{
|
||||
Msg: "发送请求失败:" + err.Error(),
|
||||
Data: nil,
|
||||
Cost: "",
|
||||
Now: time.Now(),
|
||||
Code: errors.ServerError,
|
||||
},
|
||||
}
|
||||
return resp
|
||||
}
|
||||
resp, err := common.Request(m, "", nodeUrl, nil, nil, bytes.NewReader(marshal))
|
||||
if err != nil {
|
||||
log.Errorf("发送请求失败: %s", n.Url+"/"+nodeUrl)
|
||||
resp = &response.Response{
|
||||
HttpCode: errors.ServerError,
|
||||
Result: &response.Result{
|
||||
Msg: "发送请求失败:" + err.Error(),
|
||||
Data: nil,
|
||||
Cost: "",
|
||||
Now: time.Now(),
|
||||
Code: errors.ServerError,
|
||||
},
|
||||
}
|
||||
return resp
|
||||
}
|
||||
return resp
|
||||
} else {
|
||||
log.Errorf("没有找到对应的机器: %s", machineId)
|
||||
resp := &response.Response{
|
||||
HttpCode: errors.ServerError,
|
||||
Result: &response.Result{
|
||||
Msg: fmt.Sprintf("没有找到对应的机器: %s", machineId),
|
||||
Data: nil,
|
||||
Cost: "",
|
||||
Now: time.Now(),
|
||||
Code: errors.ServerError,
|
||||
},
|
||||
}
|
||||
return resp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传保存分片信息
|
||||
*
|
||||
* @param file 上传的文件信息
|
||||
* @param tempPath 临时保存目录
|
||||
* @param sliceId 分片id
|
||||
* @param totalSlice 累积分片
|
||||
* @param nowSlice 当前分片
|
||||
* @param fileSumMd5 文件签名信息
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
func UploadShardingImpl(file multipart.File, filename, tempPath, sliceID, totalSliceStr, nowSliceStr, fileSumMD5 string, extNames []string) error {
|
||||
if fileSumMD5 == "" {
|
||||
return fmt.Errorf("没有文件签名信息")
|
||||
}
|
||||
if sliceID == "" {
|
||||
return fmt.Errorf("没有分片 id 信息")
|
||||
}
|
||||
|
||||
totalSlice, err := strconv.Atoi(totalSliceStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("上传信息不完整:totalSlice %s", err)
|
||||
}
|
||||
nowSlice, err := strconv.Atoi(nowSliceStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("上传信息不完整:nowSlice %s", err)
|
||||
}
|
||||
if totalSlice <= 0 || nowSlice < 0 || totalSlice < nowSlice {
|
||||
return fmt.Errorf("当前上传的分片信息错误")
|
||||
}
|
||||
|
||||
slicePath := filepath.Join(tempPath, "slice", sliceID)
|
||||
sliceItemPath := filepath.Join(slicePath, "items")
|
||||
if err := os.MkdirAll(sliceItemPath, 0755); err != nil {
|
||||
return fmt.Errorf("创建保存路径失败:%s", err)
|
||||
}
|
||||
|
||||
originalFilename := filename
|
||||
// 截断序号 xxxxx.avi.1
|
||||
realName := subBefore(originalFilename, ".", true)
|
||||
if len(extNames) > 0 {
|
||||
extName := filepath.Ext(realName)
|
||||
for _, allowedExt := range extNames {
|
||||
if strings.ToLower(extName) == strings.ToLower(allowedExt) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !strings.Contains(strings.ToLower(extName), strings.ToLower(strings.Join(extNames, ","))) {
|
||||
return fmt.Errorf("不支持的文件类型:%s", extName)
|
||||
}
|
||||
}
|
||||
|
||||
slice := filepath.Join(sliceItemPath, originalFilename)
|
||||
if err := os.MkdirAll(filepath.Dir(slice), 0755); err != nil {
|
||||
return fmt.Errorf("创建分片保存路径失败:%s", err)
|
||||
}
|
||||
|
||||
// 将文件写入到slice
|
||||
targetFile, err := os.Create(slice)
|
||||
if err != nil {
|
||||
return fmt.Errorf("创建目标文件失败:%s", err)
|
||||
}
|
||||
defer targetFile.Close()
|
||||
|
||||
_, err = io.Copy(targetFile, file)
|
||||
if err != nil {
|
||||
return fmt.Errorf("保存分片文件失败:%s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并分片
|
||||
*
|
||||
* @param tempPath 临时保存目录
|
||||
* @param sliceId 上传id
|
||||
* @param totalSlice 累积分片
|
||||
* @param fileSumMd5 文件签名
|
||||
* @return 合并后的文件
|
||||
* @throws IOException io
|
||||
*/
|
||||
func ShardingTryMergeImpl(tempPath, sliceID string, totalSlice int, fileSumMD5 string) (*os.File, error) {
|
||||
if fileSumMD5 == "" {
|
||||
return nil, fmt.Errorf("没有文件签名信息")
|
||||
}
|
||||
if sliceID == "" {
|
||||
return nil, fmt.Errorf("没有分片 id 信息")
|
||||
}
|
||||
|
||||
if totalSlice == 0 {
|
||||
return nil, fmt.Errorf("上传信息不完成:totalSlice")
|
||||
}
|
||||
|
||||
// 保存路径
|
||||
slicePath := filepath.Join(tempPath, "slice", sliceID)
|
||||
sliceItemPath := filepath.Join(slicePath, "items")
|
||||
|
||||
// 获取分片文件
|
||||
files, err := ioutil.ReadDir(sliceItemPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(files) != totalSlice {
|
||||
return nil, fmt.Errorf("文件上传失败,存在分片丢失的情况, %d != %d", len(files), totalSlice)
|
||||
}
|
||||
|
||||
// 获取文件真实名称
|
||||
name := files[0].Name()
|
||||
name = subBefore(name, ".", true)
|
||||
|
||||
// 创建合并后的文件
|
||||
successFile, err := os.OpenFile(filepath.Join(slicePath, name), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0755)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer successFile.Close()
|
||||
|
||||
// 排序并合并分片
|
||||
fileOrder := make([]int, len(files))
|
||||
for i, file := range files {
|
||||
ext := filepath.Ext(file.Name())
|
||||
fileOrder[i] = mustToInt(ext)
|
||||
}
|
||||
sort.Slice(fileOrder, func(i, j int) bool {
|
||||
return fileOrder[i] < fileOrder[j]
|
||||
})
|
||||
|
||||
for _, index := range fileOrder {
|
||||
partFile := filepath.Join(sliceItemPath, fmt.Sprintf("%s.%d", name, index))
|
||||
part, err := os.Open(partFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = io.Copy(successFile, part); err != nil {
|
||||
part.Close()
|
||||
return nil, err
|
||||
}
|
||||
part.Close()
|
||||
}
|
||||
|
||||
// 删除分片文件
|
||||
if err = os.RemoveAll(sliceItemPath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 计算新文件的MD5
|
||||
// 读取整个文件内容
|
||||
file, err := os.Open(successFile.Name())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("打开文件失败: %s", err.Error())
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
hasher := md5.New()
|
||||
if _, err := io.Copy(hasher, file); err != nil {
|
||||
return nil, fmt.Errorf("md5Sum error: %s", err.Error())
|
||||
}
|
||||
|
||||
newMD5 := hex.EncodeToString(hasher.Sum(nil))
|
||||
if !strings.EqualFold(newMD5, fileSumMD5) {
|
||||
log.Infof("文件合并异常 %s:%x -> %s", successFile.Name(), newMD5, fileSumMD5)
|
||||
return nil, fmt.Errorf("文件合并后异常,文件不完整可能被损坏")
|
||||
}
|
||||
|
||||
return successFile, nil
|
||||
}
|
||||
|
||||
func subBefore(s, sep string, isLastSeparator bool) string {
|
||||
if sep == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
pos := -1
|
||||
if isLastSeparator {
|
||||
pos = strings.LastIndex(s, sep)
|
||||
} else {
|
||||
pos = strings.Index(s, sep)
|
||||
}
|
||||
|
||||
if pos == -1 {
|
||||
return s
|
||||
} else if pos == 0 {
|
||||
return ""
|
||||
}
|
||||
return s[:pos]
|
||||
}
|
||||
|
||||
// todo 确定是16进制还是字符串
|
||||
func md5Sum(content []byte) string {
|
||||
// 创建一个新的md5哈希器
|
||||
hasher := md5.New()
|
||||
|
||||
// 获取哈希值并转换为16进制字符串
|
||||
hashBytes := hasher.Sum(content)
|
||||
md5Hash := hex.EncodeToString(hashBytes)
|
||||
|
||||
return md5Hash
|
||||
}
|
||||
|
||||
func mustToInt(s string) int {
|
||||
num, _ := strconv.Atoi(strings.Trim(s, "."))
|
||||
return num
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
package manage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
err1 "errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller/v1/app_manage"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/node"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/project_info"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/assets"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/common"
|
||||
node2 "git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/node"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func GetProjectData(c *gin.Context) {
|
||||
nodeId := c.PostForm("nodeId")
|
||||
id := c.PostForm("id")
|
||||
if nodeId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
if id == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
n := &node.Node{}
|
||||
n.Id = nodeId
|
||||
err := n.GetById(n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "没有对应的节点")
|
||||
return
|
||||
}
|
||||
jsonBody := make(map[string]string)
|
||||
jsonBody["id"] = id
|
||||
body, _ := json.Marshal(jsonBody)
|
||||
resp, err := common.Request5(n, common.Manage_GetProjectItem, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "查询失败")
|
||||
return
|
||||
}
|
||||
if !resp.IsBusinessSuccess() {
|
||||
controller.FailCode(c, errors.ServerError, err1.New(resp.Result.Msg), resp.Result.Data)
|
||||
return
|
||||
}
|
||||
controller.Success(c, resp.Result.Data)
|
||||
}
|
||||
|
||||
// ProjectAccessList 同/machine/white-list
|
||||
func ProjectAccessList(c *gin.Context) {
|
||||
machineId := c.PostForm("machineId")
|
||||
m := &node.MachineNode{}
|
||||
m.Id = machineId
|
||||
err := m.GetById(m)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "没有对应的机器")
|
||||
return
|
||||
}
|
||||
|
||||
result := assets.GetAgentWhitelist(m)
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
// http://10.110.141.50:2122/node/manage/saveProject
|
||||
// nodeId=895457ceee8340279d9d92e10242d77c&id=DQWKRY&name=test&runMode=Jar&whitelistDirectory=%2Fhome%2Ftmn%2Fjpom%2Fproject%2F&lib=test&logPath=
|
||||
func SaveProject(c *gin.Context) {
|
||||
|
||||
//params, _ := request.GetPostFormParams(c)
|
||||
//if params["nodeId"] == "" {
|
||||
// controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
// return
|
||||
//}
|
||||
p := project_info.ProjectInfo{}
|
||||
|
||||
err := c.ShouldBindJSON(&p)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
nodeId := p.NodeId
|
||||
if nodeId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
id := p.Id
|
||||
if id == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
n := &node.Node{}
|
||||
n.Id = nodeId
|
||||
err = n.GetById(n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "没有对应的节点")
|
||||
return
|
||||
}
|
||||
p.SetUserName(service.GetUserName(c))
|
||||
p.WorkspaceId = n.WorkspaceId
|
||||
p.NodeName = n.Name
|
||||
body, _ := json.Marshal(p)
|
||||
resp, err := common.Request5(n, common.Manage_SaveProject, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "创建项目失败")
|
||||
return
|
||||
}
|
||||
if !resp.IsBusinessSuccess() {
|
||||
controller.FailCode(c, errors.ServerError, err1.New(resp.Result.Msg), "创建项目失败-逻辑节点")
|
||||
return
|
||||
}
|
||||
node2.SyncNodeProjectInfo(n, id)
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
func ReleaseOutgiving(c *gin.Context) {
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
response := app_manage.TryRequestNode("", bodyToMap, common.Manage_ReleaseOutGiving)
|
||||
|
||||
if response.Result.Code == errors.SUCCESS {
|
||||
projectId, _ := bodyToMap["id"].(string)
|
||||
n, _ := app_manage.TryGetNode(bodyToMap)
|
||||
node2.SyncNodeProjectInfo(n, projectId)
|
||||
|
||||
controller.Success(c, response.Result.Data)
|
||||
} else {
|
||||
controller.FailCode(c, response.Result.Code, errors.NewBusinessError(response.Result.Code, response.Result.Msg), response.Result.Data)
|
||||
}
|
||||
}
|
@ -0,0 +1,369 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
err1 "errors"
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller/v1/app_manage"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/node"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/common"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func GetFileList(c *gin.Context) {
|
||||
nodeId := c.PostForm("nodeId")
|
||||
id := c.PostForm("id")
|
||||
if nodeId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
if id == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
n := &node.Node{}
|
||||
n.Id = nodeId
|
||||
err := n.GetById(n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "没有对应的节点")
|
||||
return
|
||||
}
|
||||
jsonBody := make(map[string]string)
|
||||
jsonBody["id"] = id
|
||||
jsonBody["path"] = c.PostForm("path")
|
||||
body, _ := json.Marshal(jsonBody)
|
||||
resp, err := common.Request5(n, common.Manage_File_GetFileList, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "查询失败")
|
||||
return
|
||||
}
|
||||
if !resp.IsBusinessSuccess() {
|
||||
controller.FailCode(c, errors.ServerError, err1.New(resp.Result.Msg), resp.Result.Data)
|
||||
return
|
||||
}
|
||||
controller.Success(c, resp.Result.Data)
|
||||
}
|
||||
|
||||
var mutex sync.Mutex
|
||||
|
||||
func GenerateShardingId(c *gin.Context) {
|
||||
mutex.Lock()
|
||||
if len(app_manage.ShardingIdMap) > 100 {
|
||||
controller.FailCode(c, errors.ServerError, nil, "分片id最大同时使用100个")
|
||||
return
|
||||
}
|
||||
id := strings.ReplaceAll(uuid.New().String(), "-", "")
|
||||
app_manage.ShardingIdMap[id] = true
|
||||
mutex.Unlock()
|
||||
controller.Success(c, id)
|
||||
}
|
||||
|
||||
// 1aaa34e5be524c868928a6053d487e2d
|
||||
func UploadSharding(c *gin.Context) {
|
||||
nodeId := c.PostForm("nodeId")
|
||||
id := c.PostForm("id")
|
||||
if nodeId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
if id == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
sliceId := c.PostForm("sliceId")
|
||||
if _, ok := app_manage.ShardingIdMap[sliceId]; !ok {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "不合法的分片id")
|
||||
return
|
||||
}
|
||||
n := &node.Node{}
|
||||
n.Id = nodeId
|
||||
err := n.GetById(n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "没有对应的节点")
|
||||
return
|
||||
}
|
||||
_, err = c.MultipartForm()
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
file, header, err := c.Request.FormFile("file")
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
body := new(bytes.Buffer)
|
||||
mpw := multipart.NewWriter(body)
|
||||
fw, err := mpw.CreateFormFile("file", header.Filename)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
_, err = io.Copy(fw, file)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
_ = mpw.WriteField("nowSlice", c.PostForm("nowSlice"))
|
||||
_ = mpw.WriteField("totalSlice", c.PostForm("totalSlice"))
|
||||
_ = mpw.WriteField("sliceId", sliceId)
|
||||
_ = mpw.WriteField("fileSumMd5", c.PostForm("fileSumMd5"))
|
||||
_ = mpw.WriteField("id", id)
|
||||
_ = mpw.WriteField("levelName", c.PostForm("levelName"))
|
||||
_ = mpw.Close()
|
||||
h := make(map[string]string)
|
||||
h["Content-Type"] = mpw.FormDataContentType()
|
||||
resp, err := common.Request1(n, common.Manage_File_Upload_Sharding, h, nil, body)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "上传失败")
|
||||
return
|
||||
}
|
||||
if !resp.IsBusinessSuccess() {
|
||||
controller.FailCode(c, errors.ServerError, err1.New(resp.Result.Msg), resp.Result.Data)
|
||||
return
|
||||
}
|
||||
controller.Success(c, resp.Result.Msg)
|
||||
}
|
||||
|
||||
func ShardingMerge(c *gin.Context) {
|
||||
nodeId := c.PostForm("nodeId")
|
||||
id := c.PostForm("id")
|
||||
if nodeId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
if id == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
sliceId := c.PostForm("sliceId")
|
||||
if _, ok := app_manage.ShardingIdMap[sliceId]; !ok {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "不合法的分片id")
|
||||
return
|
||||
}
|
||||
n := &node.Node{}
|
||||
n.Id = nodeId
|
||||
err := n.GetById(n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "没有对应的节点")
|
||||
return
|
||||
}
|
||||
jsonBody := make(map[string]interface{})
|
||||
nowSlice := c.PostForm("nowSlice")
|
||||
var nowSliceI int
|
||||
if nowSlice != "" {
|
||||
nowSliceI, _ = strconv.Atoi(nowSlice)
|
||||
}
|
||||
totalSlice := c.PostForm("totalSlice")
|
||||
var totalSliceI int
|
||||
if totalSlice != "" {
|
||||
totalSliceI, _ = strconv.Atoi(totalSlice)
|
||||
}
|
||||
|
||||
stripComponents := c.PostForm("stripComponents")
|
||||
var stripComponentsI int
|
||||
if stripComponents != "" {
|
||||
stripComponentsI, _ = strconv.Atoi(stripComponents)
|
||||
}
|
||||
|
||||
jsonBody["nowSlice"] = nowSliceI
|
||||
jsonBody["totalSlice"] = totalSliceI
|
||||
jsonBody["sliceId"] = sliceId
|
||||
jsonBody["fileSumMd5"] = c.PostForm("fileSumMd5")
|
||||
jsonBody["id"] = id
|
||||
jsonBody["levelName"] = c.PostForm("levelName")
|
||||
jsonBody["stripComponents"] = stripComponentsI
|
||||
|
||||
type_ := c.PostForm("type")
|
||||
if type_ != "" {
|
||||
jsonBody["type"] = type_
|
||||
}
|
||||
|
||||
body, _ := json.Marshal(jsonBody)
|
||||
resp, err := common.Request5(n, common.Manage_File_Sharding_Merge, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "合并失败")
|
||||
return
|
||||
}
|
||||
if !resp.IsBusinessSuccess() {
|
||||
controller.FailCode(c, errors.ServerError, err1.New(resp.Result.Msg), resp.Result.Data)
|
||||
return
|
||||
}
|
||||
delete(app_manage.ShardingIdMap, sliceId)
|
||||
controller.Success(c, resp.Result.Msg)
|
||||
}
|
||||
|
||||
// remote-download
|
||||
func RemoteDownload(c *gin.Context) {
|
||||
nodeId := c.PostForm("nodeId")
|
||||
id := c.PostForm("id")
|
||||
if nodeId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
if id == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
n := &node.Node{}
|
||||
n.Id = nodeId
|
||||
err := n.GetById(n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "没有对应的节点")
|
||||
return
|
||||
}
|
||||
jsonBody := make(map[string]string)
|
||||
jsonBody["id"] = id
|
||||
jsonBody["url"] = c.PostForm("url")
|
||||
jsonBody["levelName"] = c.PostForm("levelName")
|
||||
jsonBody["unzip"] = c.PostForm("unzip")
|
||||
jsonBody["stripComponents"] = c.PostForm("stripComponents")
|
||||
jsonBody["filename"] = c.PostForm("filename")
|
||||
|
||||
body, _ := json.Marshal(jsonBody)
|
||||
resp, err := common.Request5(n, common.Manage_File_Remote_Download, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "下载失败")
|
||||
return
|
||||
}
|
||||
if !resp.IsBusinessSuccess() {
|
||||
controller.FailCode(c, errors.ServerError, err1.New(resp.Result.Msg), resp.Result.Data)
|
||||
return
|
||||
}
|
||||
controller.Success(c, resp.Result.Data)
|
||||
}
|
||||
|
||||
func DeleteFile(c *gin.Context) {
|
||||
nodeId := c.PostForm("nodeId")
|
||||
id := c.PostForm("id")
|
||||
if nodeId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
if id == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
n := &node.Node{}
|
||||
n.Id = nodeId
|
||||
err := n.GetById(n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "没有对应的节点")
|
||||
return
|
||||
}
|
||||
jsonBody := make(map[string]string)
|
||||
jsonBody["id"] = id
|
||||
jsonBody["levelName"] = c.PostForm("levelName")
|
||||
jsonBody["filename"] = c.PostForm("filename")
|
||||
body, _ := json.Marshal(jsonBody)
|
||||
resp, err := common.Request5(n, common.Manage_File_DeleteFile, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "删除失败")
|
||||
return
|
||||
}
|
||||
if !resp.IsBusinessSuccess() {
|
||||
controller.FailCode(c, errors.ServerError, err1.New(resp.Result.Msg), resp.Result.Data)
|
||||
return
|
||||
}
|
||||
controller.Success(c, resp.Result.Data)
|
||||
}
|
||||
|
||||
func NewFileFolder(c *gin.Context) {
|
||||
nodeId := c.Query("nodeId")
|
||||
id := c.Query("id")
|
||||
if nodeId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
if id == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
n := &node.Node{}
|
||||
n.Id = nodeId
|
||||
err := n.GetById(n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "没有对应的节点")
|
||||
return
|
||||
}
|
||||
jsonBody := make(map[string]string)
|
||||
jsonBody["id"] = id
|
||||
jsonBody["levelName"] = c.Query("levelName")
|
||||
jsonBody["filename"] = c.Query("filename")
|
||||
jsonBody["unFolder"] = c.Query("unFolder")
|
||||
body, _ := json.Marshal(jsonBody)
|
||||
resp, err := common.Request5(n, common.MANAGE_FILE_NEW_FILE_FOLDER, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "创建失败")
|
||||
return
|
||||
}
|
||||
if !resp.IsBusinessSuccess() {
|
||||
controller.FailCode(c, errors.ServerError, err1.New(resp.Result.Msg), resp.Result.Data)
|
||||
return
|
||||
}
|
||||
controller.Success(c, resp.Result.Data)
|
||||
}
|
||||
|
||||
// ?nodeId=28d5792b2d3d11ef854b9e95766d6418&id=78XBM1&filePath=/gway&filename=manifest.yml
|
||||
func ReadFile(c *gin.Context) {
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
|
||||
nodeId := c.Query("nodeId")
|
||||
n := &node.Node{}
|
||||
n.Id = nodeId
|
||||
err := n.GetById(n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "未查询到节点信息")
|
||||
return
|
||||
}
|
||||
|
||||
query := c.Request.URL.RawQuery
|
||||
query = fmt.Sprintf("%s?%s", common.Manage_File_ReadFile, query)
|
||||
resp, err := common.RequestGet(n, workspaceId, query)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "未查询到节点信息:")
|
||||
return
|
||||
}
|
||||
|
||||
if resp.Result.Code != errors.SUCCESS {
|
||||
controller.Fail(c, errors.ServerError, resp.Result.Msg)
|
||||
return
|
||||
}
|
||||
|
||||
controller.Success(c, resp.Result.Data)
|
||||
}
|
||||
|
||||
// nodeId: this.nodeId,
|
||||
//
|
||||
// id: this.projectId,
|
||||
// filePath: this.uploadPath,
|
||||
// filename: this.filename,
|
||||
// fileText: this.fileContent,
|
||||
func UpdateConfigFile(c *gin.Context) {
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
|
||||
n, err := app_manage.TryGetNode(bodyToMap)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
resp := app_manage.TryRequestNode(n.MachineId, bodyToMap, common.Manage_File_UpdateConfigFile)
|
||||
if resp.Result.Code == errors.SUCCESS {
|
||||
controller.Success(c, resp.Result.Data)
|
||||
return
|
||||
}
|
||||
|
||||
controller.Fail(c, errors.ServerError, resp.Result.Msg)
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
err1 "errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller/v1/app_manage"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/common"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func LogSize(c *gin.Context) {
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
|
||||
n, err := app_manage.TryGetNode(bodyToMap)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "获取节点失败")
|
||||
return
|
||||
}
|
||||
|
||||
body, _ := json.Marshal(bodyToMap)
|
||||
resp, err := common.Request5(n, common.Manage_Log_LogSize, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "获取日志大小失败")
|
||||
return
|
||||
}
|
||||
if !resp.IsBusinessSuccess() {
|
||||
controller.FailCode(c, errors.ServerError, err1.New(resp.Result.Msg), resp.Result.Data)
|
||||
return
|
||||
}
|
||||
controller.Success(c, resp.Result.Data)
|
||||
|
||||
}
|
@ -0,0 +1,239 @@
|
||||
package manage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
err1 "errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller/v1/app_manage"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/node"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/project_info"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/common"
|
||||
node2 "git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/node"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/outgiving"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// GS4Z2X
|
||||
func GetProjectPort(c *gin.Context) {
|
||||
nodeId := c.PostForm("nodeId")
|
||||
ids := c.PostForm("ids")
|
||||
if nodeId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
if ids == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
var idArray []string
|
||||
err := json.Unmarshal([]byte(ids), &idArray)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
if len(idArray) == 0 {
|
||||
controller.FailCode(c, errors.ServerError, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
n := &node.Node{}
|
||||
n.Id = nodeId
|
||||
err = n.GetById(n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "没有对应的节点")
|
||||
return
|
||||
}
|
||||
jsonBody := make(map[string][]string)
|
||||
jsonBody["ids"] = idArray
|
||||
body, _ := json.Marshal(jsonBody)
|
||||
resp, err := common.Request5(n, common.Manage_GetProjectPort, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "查询失败")
|
||||
return
|
||||
}
|
||||
if !resp.IsBusinessSuccess() {
|
||||
controller.FailCode(c, errors.ServerError, err1.New(resp.Result.Msg), resp.Result.Data)
|
||||
return
|
||||
}
|
||||
controller.Success(c, resp.Result.Data)
|
||||
}
|
||||
|
||||
type ProjectPageBody struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
NodeId string `json:"nodeId"`
|
||||
Group string `json:"group"`
|
||||
Keyword string `json:"keyword"`
|
||||
RunMode string `json:"runMode"`
|
||||
}
|
||||
|
||||
func PageProject(c *gin.Context) {
|
||||
var pageBody ProjectPageBody
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
if pageBody.NodeId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
p := project_info.New()
|
||||
fields := map[string]interface{}{}
|
||||
fields["node_id"] = pageBody.NodeId
|
||||
|
||||
if len(pageBody.Group) > 0 {
|
||||
fields["\"group\""] = pageBody.Group
|
||||
}
|
||||
if len(pageBody.RunMode) > 0 {
|
||||
fields["run_mode"] = pageBody.RunMode
|
||||
}
|
||||
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
fields["workspace_id"] = workspaceId
|
||||
|
||||
page := &model.PageConfig{}
|
||||
page.Covert(pageBody.PageInfo)
|
||||
result, err := p.Page(p, page, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
page.Data = result
|
||||
controller.Success(c, page)
|
||||
}
|
||||
|
||||
func DeleteProject(c *gin.Context) {
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
|
||||
n, err := app_manage.TryGetNode(bodyToMap)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
projectId, _ := bodyToMap["id"].(string)
|
||||
if projectId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数:projectId!")
|
||||
return
|
||||
}
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
|
||||
err = outgiving.CheckNodeProject(n.Id, projectId, workspaceId, "当前项目存在节点分发,不能直接删除")
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "当前项目存在节点分发,不能直接删除")
|
||||
return
|
||||
}
|
||||
|
||||
// todo 检查日志阅读 项目监控
|
||||
// logReadServer.checkNodeProject(nodeModel.getId(), id, request, "当前项目存在日志阅读,不能直接删除");
|
||||
resp := app_manage.TryRequestNode("", bodyToMap, common.Manage_DeleteProject)
|
||||
if resp.Result.Code == errors.SUCCESS {
|
||||
node2.SyncExecuteNode(n)
|
||||
controller.Success(c, resp.Result.Data)
|
||||
return
|
||||
}
|
||||
|
||||
controller.Fail(c, errors.ServerError, resp.Result.Msg)
|
||||
|
||||
}
|
||||
|
||||
func StartProject(c *gin.Context) {
|
||||
nodeId := c.PostForm("nodeId")
|
||||
id := c.PostForm("id")
|
||||
if nodeId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数:nodeId!")
|
||||
return
|
||||
}
|
||||
if id == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数:id!")
|
||||
return
|
||||
}
|
||||
n := &node.Node{}
|
||||
n.Id = nodeId
|
||||
err := n.GetById(n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "没有对应的节点")
|
||||
return
|
||||
}
|
||||
jsonBody := make(map[string]string)
|
||||
jsonBody["id"] = id
|
||||
body, _ := json.Marshal(jsonBody)
|
||||
resp, err := common.Request5(n, common.Manage_StartProject, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "下载失败")
|
||||
return
|
||||
}
|
||||
if !resp.IsBusinessSuccess() {
|
||||
controller.FailCode(c, errors.ServerError, err1.New(resp.Result.Msg), resp.Result.Data)
|
||||
return
|
||||
}
|
||||
controller.Success(c, resp.Result.Data)
|
||||
}
|
||||
|
||||
func StopProject(c *gin.Context) {
|
||||
nodeId := c.PostForm("nodeId")
|
||||
id := c.PostForm("id")
|
||||
if nodeId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
if id == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
n := &node.Node{}
|
||||
n.Id = nodeId
|
||||
err := n.GetById(n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "没有对应的节点")
|
||||
return
|
||||
}
|
||||
jsonBody := make(map[string]string)
|
||||
jsonBody["id"] = id
|
||||
body, _ := json.Marshal(jsonBody)
|
||||
resp, err := common.Request5(n, common.Manage_StopProject, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "下载失败")
|
||||
return
|
||||
}
|
||||
if !resp.IsBusinessSuccess() {
|
||||
controller.FailCode(c, errors.ServerError, err1.New(resp.Result.Msg), resp.Result.Data)
|
||||
return
|
||||
}
|
||||
controller.Success(c, resp.Result.Data)
|
||||
}
|
||||
|
||||
func RestartProject(c *gin.Context) {
|
||||
nodeId := c.PostForm("nodeId")
|
||||
id := c.PostForm("id")
|
||||
if nodeId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
if id == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
n := &node.Node{}
|
||||
n.Id = nodeId
|
||||
err := n.GetById(n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "没有对应的节点")
|
||||
return
|
||||
}
|
||||
jsonBody := make(map[string]string)
|
||||
jsonBody["id"] = id
|
||||
body, _ := json.Marshal(jsonBody)
|
||||
resp, err := common.Request5(n, common.Manage_RestartProject, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "下载失败")
|
||||
return
|
||||
}
|
||||
if !resp.IsBusinessSuccess() {
|
||||
controller.FailCode(c, errors.ServerError, err1.New(resp.Result.Msg), resp.Result.Data)
|
||||
return
|
||||
}
|
||||
controller.Success(c, resp.Result.Data)
|
||||
}
|
@ -0,0 +1,302 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller/v1/app_manage"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
node2 "git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/node"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/out_giving"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/project_info"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/script_info"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/validator"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func GetAllNodesByWorkspaceId(c *gin.Context) {
|
||||
workspaceId := c.Query("workspaceId")
|
||||
if workspaceId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
n := node2.New()
|
||||
fields := map[string]interface{}{}
|
||||
fields["workspace_id"] = workspaceId
|
||||
result, err := n.GetAll(n, fields, nil)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "无法查找到对象!")
|
||||
return
|
||||
}
|
||||
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
type NodePageBody struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
WorkspaceId string `json:"workspaceId"`
|
||||
Name string `json:"name"`
|
||||
Group string `json:"group"`
|
||||
Keyword string `json:"keyword"`
|
||||
}
|
||||
|
||||
func PageNodesByWorkspaceId(c *gin.Context) {
|
||||
var pageBody NodePageBody
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
if pageBody.WorkspaceId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
n := node2.New()
|
||||
fields := map[string]interface{}{}
|
||||
fields["workspace_id"] = pageBody.WorkspaceId
|
||||
if pageBody.Name != "" {
|
||||
fields["name"] = pageBody.Name
|
||||
}
|
||||
if pageBody.Group != "" {
|
||||
fields["\"group\""] = pageBody.Group
|
||||
}
|
||||
page := &model.PageConfig{}
|
||||
page.Covert(pageBody.PageInfo)
|
||||
result, err := n.Page(n, page, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
nodes := result.([]node2.Node)
|
||||
if len(nodes) > 0 {
|
||||
for i, node := range nodes {
|
||||
m := &node2.MachineNode{}
|
||||
m.Id = node.MachineId
|
||||
err = m.GetById(m)
|
||||
|
||||
projects, _ := project_info.GetProjectByNodeId(node.Id)
|
||||
scripts, err := script_info.GetNodeScriptByNodeId(node.Id)
|
||||
|
||||
if err == nil {
|
||||
m.CfnAgentProjectCount = len(projects)
|
||||
m.CfnAgentScriptCount = len(scripts)
|
||||
nodes[i].MachineNodeData = m
|
||||
}
|
||||
}
|
||||
}
|
||||
page.Data = nodes
|
||||
controller.Success(c, page)
|
||||
}
|
||||
|
||||
func SyncToWorkspace(c *gin.Context) {
|
||||
ids := c.Query("ids")
|
||||
if ids == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
workspaceId := c.Query("workspaceId")
|
||||
if workspaceId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
fields := map[string]interface{}{}
|
||||
idArray := strings.Split(ids, ",")
|
||||
username := service.GetUserName(c)
|
||||
for _, id := range idArray {
|
||||
nd := node2.New()
|
||||
nd.Id = id
|
||||
err := nd.GetById(nd)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "节点不存在!")
|
||||
return
|
||||
}
|
||||
fields = map[string]interface{}{}
|
||||
fields["workspace_id"] = workspaceId
|
||||
fields["machine_id"] = nd.MachineId
|
||||
result, _ := nd.GetAll(nd, fields, nil)
|
||||
if len(result.([]node2.Node)) > 0 {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "目标工作空间已存在该节点!")
|
||||
return
|
||||
}
|
||||
nd.Id = ""
|
||||
nd.WorkspaceId = workspaceId
|
||||
nd.CreateUser = username
|
||||
nd.ModifyUser = username
|
||||
nd.LoginName = ""
|
||||
nd.Url = ""
|
||||
nd.LoginPwd = ""
|
||||
nd.Protocol = ""
|
||||
nd.HttpProxy = ""
|
||||
nd.HttpProxyType = ""
|
||||
_, err = nd.Create(nd)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
func EditNode(c *gin.Context) {
|
||||
n := &node2.Node{}
|
||||
err := validator.CheckPostParams(c, n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
n1 := &node2.Node{}
|
||||
err = n.GetById(n1)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "无法查找到对象!")
|
||||
return
|
||||
}
|
||||
n.ModifyUser = service.GetUserName(c)
|
||||
_, err = n.Update(n, nil)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "数据库错误!")
|
||||
return
|
||||
}
|
||||
// TODO projectInfoCacheService.syncNode(nodeModel);
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
func ListNodeGroup(c *gin.Context) {
|
||||
n := &node2.Node{}
|
||||
result, _ := n.ListGroup()
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
type UnbindNodeBody struct {
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
func UnbindNode(c *gin.Context) {
|
||||
|
||||
var body UnbindNodeBody
|
||||
err := c.ShouldBindJSON(&body)
|
||||
|
||||
id := body.Id
|
||||
if id == "" {
|
||||
controller.Fail(c, errors.InvalidParameter, "id为空")
|
||||
return
|
||||
}
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
|
||||
//
|
||||
{
|
||||
exists, _ := out_giving.ExistsOutGivingModel(workspaceId, id)
|
||||
if exists {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "该节点存在分发项目,不能删除")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
exists, _ := project_info.Exists_1(workspaceId, id)
|
||||
if exists {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "该节点下还存在项目,不能删除")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
exists, _ := script_info.ExistsNodeScriptCacheModel(workspaceId, id)
|
||||
if exists {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "该节点下还存在脚本模版,不能删除")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
n := &node2.Node{}
|
||||
n.Id = id
|
||||
err = n.GetById(n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "无法查找到对象!")
|
||||
return
|
||||
}
|
||||
_, err = n.Delete(n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "数据库错误!")
|
||||
return
|
||||
}
|
||||
|
||||
script_info.DeleteNodeScriptExecuteLogByNodeIdAndWorkspaceIds(id, []string{workspaceId, "GLOBAL"})
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
func DeleteNode(c *gin.Context) {
|
||||
id := c.PostForm("id")
|
||||
if id == "" {
|
||||
controller.Success(c, "")
|
||||
return
|
||||
}
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
|
||||
//
|
||||
{
|
||||
exists, _ := out_giving.ExistsOutGivingModel(workspaceId, id)
|
||||
if exists {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "该节点存在分发项目,不能删除")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
_, err := project_info.DeleteProjectByNodeIdAndWorkspaceId(id, workspaceId)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "删除项目失败!")
|
||||
return
|
||||
}
|
||||
|
||||
_, err = script_info.DeleteNodeScriptByNodeIdAndWorkspaceId(id, workspaceId)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "删除脚本失败!")
|
||||
return
|
||||
}
|
||||
|
||||
n := &node2.Node{}
|
||||
n.Id = id
|
||||
err = n.GetById(n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "无法查找到对象!")
|
||||
return
|
||||
}
|
||||
_, err = n.Delete(n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "数据库错误!")
|
||||
return
|
||||
}
|
||||
|
||||
script_info.DeleteNodeScriptExecuteLogByNodeIdAndWorkspaceIds(id, []string{workspaceId, "GLOBAL"})
|
||||
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
func SortItem(c *gin.Context) {
|
||||
/*n := &node.Node{}
|
||||
err := validator.CheckPostParams(c, n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
fields := map[string]interface{}{}
|
||||
fields["id"] = n.Id
|
||||
_, err = n.Get(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "无法查找到对象!")
|
||||
return
|
||||
}
|
||||
userName := service.GetUserName(c)
|
||||
n.ModifyUser = userName
|
||||
var updateColumns []string
|
||||
_, err = n.Update(updateColumns)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "数据库错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "")*/
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller/v1/app_manage"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/project_info"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/node"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type ProjectPageBody struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
NodeId string `json:"nodeId"`
|
||||
Group string `json:"group"`
|
||||
Keyword string `json:"keyword"`
|
||||
RunMode string `json:"runMode"`
|
||||
}
|
||||
|
||||
// ProjectList 加载节点项目列表
|
||||
func ProjectList(c *gin.Context) {
|
||||
var pageBody *ProjectPageBody
|
||||
body := request.GetBody(c)
|
||||
err := json.Unmarshal(body, &pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
p := project_info.New()
|
||||
fields := map[string]interface{}{}
|
||||
if len(pageBody.NodeId) > 0 {
|
||||
fields["node_id"] = pageBody.NodeId
|
||||
}
|
||||
if len(pageBody.Group) > 0 {
|
||||
fields["\"group\""] = pageBody.Group
|
||||
}
|
||||
if len(pageBody.RunMode) > 0 {
|
||||
fields["run_mode"] = pageBody.RunMode
|
||||
}
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
fields["workspace_id"] = workspaceId
|
||||
|
||||
page := &model.PageConfig{}
|
||||
page.Covert(pageBody.PageInfo)
|
||||
result, err := p.Page(p, page, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
page.Data = result
|
||||
controller.Success(c, page)
|
||||
}
|
||||
|
||||
// ProjectListAll 加载节点项目列表
|
||||
func ProjectListAll(c *gin.Context) {
|
||||
p := project_info.New()
|
||||
|
||||
fields := map[string]interface{}{}
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
fields["workspace_id"] = workspaceId
|
||||
all, err := p.GetAll(p, fields, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
controller.Success(c, all)
|
||||
}
|
||||
|
||||
// ListProjectGroup 查询所有的分组
|
||||
func ListProjectGroup(c *gin.Context) {
|
||||
p := &project_info.ProjectInfo{}
|
||||
result, _ := p.ListGroup()
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
// SyncProject 同步节点项目
|
||||
func SyncProject(c *gin.Context) {
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
n, err := app_manage.TryGetNode(bodyToMap)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
workspaceId := c.Request.Header.Get("workspaceId")
|
||||
|
||||
count, err := project_info.DeleteProjectByNodeIdAndWorkspaceId(n.Id, workspaceId)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "删除节点缓存项目信息失败!")
|
||||
return
|
||||
}
|
||||
|
||||
msg := node.SyncExecuteNode(n)
|
||||
controller.Success(c, fmt.Sprintf("主动清除:%d个项目, 同步信息:%s", count, msg))
|
||||
|
||||
}
|
||||
|
||||
func ClearAll(c *gin.Context) {
|
||||
all, err := project_info.ClearAll()
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "删除节点缓存项目失败!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, fmt.Sprintf("成功删除 %d 条项目缓存", all))
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"github.com/gin-gonic/gin"
|
||||
"os"
|
||||
)
|
||||
|
||||
func FastInstallNode(c *gin.Context) {
|
||||
result := make(map[string]interface{})
|
||||
result["key"] = "--auto-push-to-server"
|
||||
result["token"] = os.Getenv("JPOM_SERVER_TEMP_TOKEN")
|
||||
shUrls := `[
|
||||
{
|
||||
"name": "主地址(默认安装)",
|
||||
"url": "curl -fsSL https://jpom.top/docs/install.sh | bash -s Agent jdk+default"
|
||||
},
|
||||
{
|
||||
"name": "备用地址(默认安装)",
|
||||
"url": "curl -fsSL https://gitee.com/dromara/Jpom/raw/docs/docs/.vuepress/public/docs/install.sh | bash -s Agent jdk+default"
|
||||
},
|
||||
{
|
||||
"name": "主地址(自定义安装)",
|
||||
"url": "yum install -y wget && wget -O install.sh https://jpom.top/docs/install.sh && bash install.sh Agent jdk"
|
||||
},
|
||||
{
|
||||
"name": "备用地址(自定义安装)",
|
||||
"url": "yum install -y wget && wget -O install.sh https://gitee.com/dromara/Jpom/raw/docs/docs/.vuepress/public/docs/install.sh && bash install.sh Agent jdk"
|
||||
}
|
||||
]`
|
||||
var shUrlsArray []map[string]string
|
||||
json.Unmarshal([]byte(shUrls), &shUrlsArray)
|
||||
result["shUrls"] = shUrlsArray
|
||||
result["url"] = "/api/node/receive_push"
|
||||
controller.Success(c, result)
|
||||
}
|
@ -0,0 +1,162 @@
|
||||
package script
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller/v1/app_manage"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/script_info"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/common"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/node/script"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type ProjectPageBody struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
NodeId string `json:"nodeId"`
|
||||
Group string `json:"group"`
|
||||
Keyword string `json:"keyword"`
|
||||
RunMode string `json:"runMode"`
|
||||
}
|
||||
|
||||
func ScriptList(c *gin.Context) {
|
||||
var pageBody ProjectPageBody
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
if pageBody.NodeId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
n := script_info.NewNodeScriptCacheModel()
|
||||
fields := map[string]interface{}{}
|
||||
fields["node_id"] = pageBody.NodeId
|
||||
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
fields["workspace_id"] = []string{workspaceId, "GLOBAL"}
|
||||
|
||||
page := &model.PageConfig{}
|
||||
page.Covert(pageBody.PageInfo)
|
||||
scripts, err := n.Page(n, page, fields)
|
||||
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
|
||||
page.Data = scripts
|
||||
controller.Success(c, page)
|
||||
}
|
||||
|
||||
func ScriptListAll(c *gin.Context) {
|
||||
var pageBody ProjectPageBody
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
n := script_info.NewNodeScriptCacheModel()
|
||||
fields := map[string]interface{}{}
|
||||
if pageBody.NodeId != "" {
|
||||
fields["node_id"] = pageBody.NodeId
|
||||
}
|
||||
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
fields["workspace_id"] = []string{workspaceId, "GLOBAL"}
|
||||
|
||||
page := &model.PageConfig{}
|
||||
page.Covert(pageBody.PageInfo)
|
||||
scripts, err := n.Page(n, page, fields)
|
||||
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
|
||||
page.Data = scripts
|
||||
controller.Success(c, page)
|
||||
}
|
||||
|
||||
func Item(c *gin.Context) {
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
response := app_manage.TryRequestNode("", bodyToMap, common.Script_Item)
|
||||
if response.Result.Code == errors.SUCCESS {
|
||||
// todo 同步服务端
|
||||
controller.Success(c, response.Result.Data)
|
||||
} else {
|
||||
controller.FailCode(c, response.Result.Code, errors.NewBusinessError(response.Result.Code, response.Result.Msg), response.Result.Data)
|
||||
}
|
||||
}
|
||||
|
||||
func Save(c *gin.Context) {
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
machineId, _ := bodyToMap["machineId"].(string)
|
||||
response := app_manage.TryRequestNode(machineId, bodyToMap, common.Script_Save)
|
||||
if response.Result.Code == errors.SUCCESS {
|
||||
// todo 同步服务端
|
||||
node, _ := app_manage.TryGetNode(bodyToMap)
|
||||
go script.SyncExecuteNode(node)
|
||||
controller.Success(c, response.Result.Data)
|
||||
} else {
|
||||
controller.FailCode(c, response.Result.Code, errors.NewBusinessError(response.Result.Code, response.Result.Msg), response.Result.Data)
|
||||
}
|
||||
}
|
||||
|
||||
func Del(c *gin.Context) {
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
response := app_manage.TryRequestNode("", bodyToMap, common.Script_Del)
|
||||
if response.Result.Code == errors.SUCCESS {
|
||||
// todo 同步服务端
|
||||
node, _ := app_manage.TryGetNode(bodyToMap)
|
||||
go script.SyncExecuteNode(node)
|
||||
controller.Success(c, response.Result.Data)
|
||||
} else {
|
||||
controller.FailCode(c, response.Result.Code, errors.NewBusinessError(response.Result.Code, response.Result.Msg), response.Result.Data)
|
||||
}
|
||||
}
|
||||
|
||||
func SyncScript(c *gin.Context) {
|
||||
nodeId := c.Query("nodeId")
|
||||
workspaceId := c.Request.Header.Get("workspaceId")
|
||||
|
||||
node, err := app_manage.TryGetNode(map[string]interface{}{"nodeId": nodeId})
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "节点信息有误")
|
||||
return
|
||||
}
|
||||
_, err = script_info.DeleteNodeScriptByNodeIdAndWorkspaceId(nodeId, workspaceId)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "删除脚本失败")
|
||||
return
|
||||
}
|
||||
|
||||
res := script.SyncExecuteNode(node)
|
||||
controller.Success(c, res)
|
||||
}
|
||||
|
||||
func ClearAll(c *gin.Context) {
|
||||
count, err := script_info.DeleteAllNodeScript()
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "删除脚本失败")
|
||||
return
|
||||
}
|
||||
controller.Success(c, fmt.Sprintf("成功删除%d条脚本模版缓存", count))
|
||||
}
|
||||
|
||||
func Unbind(c *gin.Context) {
|
||||
id := c.Query("id")
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
|
||||
_, err := script_info.DeleteNodeScriptByIdAndWorkspaceId(id, workspaceId)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "解绑失败:删除脚本失败")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "解绑成功")
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
package script
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller/v1/app_manage"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/middleware"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/script_info"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/user"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/base_service"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/common"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type LogPageBody struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
NodeId string `json:"nodeId"`
|
||||
Name string `json:"%name%"`
|
||||
TriggerExecType string `json:"triggerExecType"`
|
||||
}
|
||||
|
||||
// ScriptLogList 处理器
|
||||
func ScriptLogList(c *gin.Context) {
|
||||
var pageBody LogPageBody
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
if pageBody.NodeId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!(nodeId)")
|
||||
return
|
||||
}
|
||||
|
||||
fields := map[string]interface{}{}
|
||||
fields["node_id"] = pageBody.NodeId
|
||||
|
||||
if len(pageBody.TriggerExecType) != 0 {
|
||||
fields["trigger_exec_type"] = pageBody.TriggerExecType
|
||||
}
|
||||
|
||||
if pageBody.Name != "" {
|
||||
fields["%script_name%"] = pageBody.Name
|
||||
}
|
||||
|
||||
page := &model.Page[script_info.NodeScriptExecuteLogCacheModel]{
|
||||
CurrentPage: pageBody.PageInfo.CurrentPage,
|
||||
PageSize: pageBody.PageInfo.PageSize,
|
||||
Order: pageBody.PageInfo.Order,
|
||||
}
|
||||
|
||||
log := script_info.NewNodeScriptExecuteLogCacheModel()
|
||||
err = log.Page(page, fields)
|
||||
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "查询脚本日志失败!")
|
||||
return
|
||||
}
|
||||
|
||||
controller.Success(c, page)
|
||||
}
|
||||
|
||||
// Log 处理器
|
||||
func Log(c *gin.Context) {
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
machineId, _ := bodyToMap["machineId"].(string)
|
||||
response := app_manage.TryRequestNode(machineId, bodyToMap, common.SCRIPT_LOG)
|
||||
|
||||
if response.Result.Code == errors.SUCCESS {
|
||||
controller.Success(c, response.Result.Data)
|
||||
} else {
|
||||
controller.FailCode(c, response.Result.Code, errors.NewBusinessError(response.Result.Code, response.Result.Msg), response.Result.Data)
|
||||
}
|
||||
}
|
||||
|
||||
// DelLog 处理器
|
||||
/**
|
||||
* @param id 模版ID
|
||||
* @param executeId 日志ID
|
||||
*/
|
||||
func DelLog(c *gin.Context) {
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
|
||||
id, _ := bodyToMap["id"].(string)
|
||||
executeId, _ := bodyToMap["executeId"].(string)
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
userObject, _ := c.Get(middleware.LoginUserKey)
|
||||
userModel := userObject.(*user.UserObj)
|
||||
|
||||
hasWorkspace := base_service.CheckUserWorkspace(workspaceId, userModel)
|
||||
if !hasWorkspace {
|
||||
controller.FailCode(c, errors.RBACError, nil, "没有对应的工作空间权限!")
|
||||
return
|
||||
}
|
||||
|
||||
executeLogModel, err := script_info.GetNodeScriptExecuteLogByIdAndWorkspaceIds(executeId, []string{workspaceId, "GLOBAL"})
|
||||
if err != nil || executeLogModel.Id == "" {
|
||||
controller.FailCode(c, errors.ServerError, err, "没有对应的执行日志!")
|
||||
return
|
||||
}
|
||||
|
||||
if executeLogModel.ScriptId != id {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "数据关联的id 不一致!")
|
||||
return
|
||||
}
|
||||
|
||||
response := app_manage.TryRequestNode("", bodyToMap, common.SCRIPT_DEL_LOG)
|
||||
if response.Result.Code == errors.SUCCESS {
|
||||
script_info.DeleteNodeScriptExecuteLogByIdAndWorkspaceIds(executeId, []string{workspaceId, "GLOBAL"})
|
||||
controller.Success(c, response.Result.Data)
|
||||
} else {
|
||||
controller.FailCode(c, response.Result.Code, errors.NewBusinessError(response.Result.Code, response.Result.Msg), response.Result.Data)
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller/v1/app_manage"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/common"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// WhiteList 同/machine/white-list
|
||||
func WhiteList(c *gin.Context) {
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
machineId, _ := bodyToMap["machineId"].(string)
|
||||
response := app_manage.TryRequestNode(machineId, bodyToMap, common.WhitelistDirectory_data, "")
|
||||
|
||||
if response.Result.Code == errors.SUCCESS {
|
||||
controller.Success(c, response.Result.Data)
|
||||
} else {
|
||||
controller.FailCode(c, response.Result.Code, errors.NewBusinessError(response.Result.Code, response.Result.Msg), response.Result.Data)
|
||||
}
|
||||
|
||||
//bodyToMap := request.GetBodyToMap(c)
|
||||
//nodeId, _ := bodyToMap["nodeId"].(string)
|
||||
//n := &node.Node{}
|
||||
//n.Id = nodeId
|
||||
//err := n.GetById(n)
|
||||
//if err != nil {
|
||||
// machineId, _ := bodyToMap["machineId"].(string)
|
||||
// m := &node.MachineNode{}
|
||||
// m.Id = machineId
|
||||
// err = m.GetById(m)
|
||||
// if err != nil {
|
||||
// controller.FailCode(c, errors.ServerError, err, "获取白名单失败")
|
||||
// return
|
||||
// }
|
||||
// response, err := common.Request(m, "", common.WhitelistDirectory_data, nil, nil, nil)
|
||||
// if err != nil {
|
||||
// controller.FailCode(c, errors.ServerError, err, "获取白名单失败")
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// controller.Success(c, response.Result.Data)
|
||||
//} else {
|
||||
// response, err := common.Request5(n, common.WhitelistDirectory_data, nil)
|
||||
// if err != nil {
|
||||
// controller.FailCode(c, errors.ServerError, err, "获取白名单失败")
|
||||
// return
|
||||
// }
|
||||
// controller.Success(c, response.Result.Data)
|
||||
//}
|
||||
}
|
||||
|
||||
func WhitelistDirectorySubmit(c *gin.Context) {
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
machineId, _ := bodyToMap["machineId"].(string)
|
||||
response := app_manage.TryRequestNode(machineId, bodyToMap, common.WhitelistDirectory_Submit, "")
|
||||
|
||||
if response.Result.Code == errors.SUCCESS {
|
||||
controller.Success(c, response.Result.Data)
|
||||
} else {
|
||||
controller.FailCode(c, response.Result.Code, errors.NewBusinessError(response.Result.Code, response.Result.Msg), response.Result.Data)
|
||||
}
|
||||
}
|
65
server/internal/controller/v1/app_manage/node_for_cfn.go
Normal file
65
server/internal/controller/v1/app_manage/node_for_cfn.go
Normal file
@ -0,0 +1,65 @@
|
||||
package app_manage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/node"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/device"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/common"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func GetNodeBySerialNo(c *gin.Context) {
|
||||
serialNo := c.Query("serialno")
|
||||
workspaceId := c.Query("workspaceId")
|
||||
|
||||
d := &device.DeviceInfo{}
|
||||
deviceInfo, err := d.GetBySerialNo(serialNo)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "未查询到节点信息")
|
||||
return
|
||||
}
|
||||
|
||||
// todo 临时
|
||||
n := node.New()
|
||||
fields := map[string]interface{}{}
|
||||
fields["url"] = fmt.Sprintf("%s:%d", deviceInfo.IPAddress, deviceInfo.Port)
|
||||
fields["workspace_id"] = workspaceId
|
||||
result, err := n.GetAll(n, fields, nil)
|
||||
|
||||
nodes := result.([]node.Node)
|
||||
if len(nodes) == 0 {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "未查询到节点信息!")
|
||||
return
|
||||
}
|
||||
|
||||
controller.Success(c, nodes[0])
|
||||
}
|
||||
|
||||
func GetRandomPorts(c *gin.Context) {
|
||||
nodeId := c.Query("nodeId")
|
||||
n := &node.Node{}
|
||||
n.Id = nodeId
|
||||
err := n.GetById(n)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "未查询到节点信息")
|
||||
return
|
||||
}
|
||||
|
||||
query := c.Request.URL.RawQuery
|
||||
query = fmt.Sprintf("%s?%s", common.RANDOM_PORTS, query)
|
||||
resp, err := common.RequestGet(n, "", query)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "未查询到节点信息:")
|
||||
return
|
||||
}
|
||||
|
||||
if resp.Result.Code != errors.SUCCESS {
|
||||
controller.Fail(c, errors.ServerError, resp.Result.Msg)
|
||||
return
|
||||
}
|
||||
|
||||
controller.Success(c, resp.Result.Data)
|
||||
|
||||
}
|
@ -0,0 +1,354 @@
|
||||
package outgiving
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
err1 "errors"
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller/v1/app_manage"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/middleware"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/node"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/out_giving"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/project_info"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/user"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/utils"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/common"
|
||||
"github.com/gin-gonic/gin"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type OutGivgingPageBody struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
Group string `json:"group"`
|
||||
OutGivingProject string `json:"outGivingProject"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
func DispatchList(c *gin.Context) {
|
||||
var pageBody OutGivgingPageBody
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
fields := map[string]interface{}{}
|
||||
if pageBody.Group != "" {
|
||||
fields["\"group\""] = pageBody.Group
|
||||
}
|
||||
if pageBody.OutGivingProject != "" {
|
||||
// 将字符串转化为布尔值
|
||||
toBool := utils.StringToBool(pageBody.OutGivingProject)
|
||||
fields["outGivingProject"] = toBool
|
||||
}
|
||||
if pageBody.Status != "" {
|
||||
fields["status"] = pageBody.Status
|
||||
}
|
||||
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
fields["workspace_id"] = workspaceId
|
||||
|
||||
page := &model.Page[out_giving.OutGivingModel]{
|
||||
CurrentPage: pageBody.PageInfo.CurrentPage,
|
||||
PageSize: pageBody.PageInfo.PageSize,
|
||||
Order: pageBody.PageInfo.Order,
|
||||
}
|
||||
|
||||
model := out_giving.NewOutGivingModel()
|
||||
err = model.Page(page, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "查询分发列表失败!")
|
||||
return
|
||||
}
|
||||
|
||||
controller.Success(c, page)
|
||||
}
|
||||
|
||||
func DispatchListAll(c *gin.Context) {
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
models := out_giving.ListOutGivingModelByWorkspace(workspaceId)
|
||||
controller.Success(c, models)
|
||||
}
|
||||
|
||||
// 关联分发项目
|
||||
func SaveConnected(c *gin.Context) {
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
typeStr, _ := bodyToMap["type"].(string)
|
||||
id, _ := bodyToMap["id"].(string)
|
||||
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
bodyToMap["workspace_id"] = workspaceId
|
||||
|
||||
userObject, _ := c.Get(middleware.LoginUserKey)
|
||||
userModel := userObject.(*user.UserObj)
|
||||
|
||||
if "add" == typeStr {
|
||||
checkId := strings.ReplaceAll(id, "-", "")
|
||||
checkId = strings.ReplaceAll(checkId, "_", "")
|
||||
err := validateID(checkId)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, err.Error())
|
||||
return
|
||||
}
|
||||
addOutGivingConnected(c, id, bodyToMap, userModel)
|
||||
} else {
|
||||
updateGivingConnected(c, id, bodyToMap, userModel)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// validateID 验证项目ID
|
||||
func validateID(id string) error {
|
||||
re := regexp.MustCompile(`^[a-zA-Z0-9_]{2,50}$`)
|
||||
matchString := re.MatchString(id)
|
||||
if !matchString {
|
||||
return fmt.Errorf("项目id 长度范围2-%d(英文字母 、数字和下划线)", 20)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func addOutGivingConnected(c *gin.Context, id string, body map[string]interface{}, userObj *user.UserObj) {
|
||||
byId := out_giving.GetOutGivingModelById(id)
|
||||
if byId.Id != "" {
|
||||
controller.FailCode(c, errors.ServerError, nil, "项目id已存在")
|
||||
return
|
||||
}
|
||||
outGivingModel := out_giving.NewOutGivingModel()
|
||||
outGivingModel.Id = id
|
||||
outGivingModel.CreateUser = userObj.UserID
|
||||
outGivingModel.ModifyUser = userObj.UserID
|
||||
|
||||
err := doDataConnected(outGivingModel, body)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
_, err = outGivingModel.Create(outGivingModel)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, nil, "项目id已存在")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "添加成功")
|
||||
}
|
||||
|
||||
func updateGivingConnected(c *gin.Context, id string, body map[string]interface{}, userObj *user.UserObj) {
|
||||
outGivingModel := out_giving.GetOutGivingModelById(id)
|
||||
if outGivingModel == nil {
|
||||
controller.Fail(c, errors.ServerError, "没有找到对应的分发id")
|
||||
return
|
||||
}
|
||||
|
||||
err := doDataConnected(outGivingModel, body)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
outGivingModel.ModifyUser = userObj.UserID
|
||||
outGivingModel.ModifyTimeMillis = time.Now().UnixMilli()
|
||||
err = out_giving.UpdateOutGivingModel(outGivingModel, []string{"name", "group", "workspace_id", "after_opt", "secondary_directory",
|
||||
"out_giving_node_project_list", "clear_old", "upload_close_first", "secondary_directory", "modify_user", "modify_time_millis"})
|
||||
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "修改失败")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "修改成功")
|
||||
}
|
||||
|
||||
// {
|
||||
// "type": "add",
|
||||
// "id": "0K1GRY",
|
||||
// "name": "sdafas",
|
||||
// "projectId": "",
|
||||
// "group": "gg",
|
||||
// "afterOpt": "0",
|
||||
// "secondaryDirectory": "tssss",
|
||||
// "clearOld": "true",
|
||||
// "uploadCloseFirst": "true",
|
||||
// "node_56e192c8e76742fa85c72342212ef466_0": "27G909",
|
||||
// "node_5722cd7a4e7a475cac61da2507088a9d_1": "T88633"
|
||||
// }
|
||||
func doDataConnected(outGivingModel *out_giving.OutGivingModel, body map[string]interface{}) error {
|
||||
outGivingModel.Name = body["name"].(string)
|
||||
outGivingModel.WorkspaceId = body["workspace_id"].(string)
|
||||
|
||||
if outGivingModel.Name == "" {
|
||||
return fmt.Errorf("分发名称不能为空")
|
||||
}
|
||||
|
||||
if groupStr, ok := body["group"]; ok {
|
||||
if groupStr != nil {
|
||||
s := groupStr.(string)
|
||||
outGivingModel.Group = &s
|
||||
}
|
||||
}
|
||||
|
||||
outGivingModels := out_giving.ListOutGivingModel()
|
||||
|
||||
paramMap := make(map[string]string)
|
||||
for k, v := range body {
|
||||
if strings.HasPrefix(k, "node_") {
|
||||
paramMap[k] = v.(string)
|
||||
}
|
||||
}
|
||||
|
||||
outGivingNodeProjects := make([]out_giving.OutGivingNodeProject, 0)
|
||||
for key, projectId := range paramMap {
|
||||
// "node_5722cd7a4e7a475cac61da2507088a9d_1": "T88633"
|
||||
if strings.HasPrefix(key, "node_") {
|
||||
nodeId := strings.TrimPrefix(key, "node_")
|
||||
nodeId = strings.Split(nodeId, "_")[0]
|
||||
|
||||
nodeModel := node.GetNodeById(nodeId)
|
||||
if nodeModel.Id == "" {
|
||||
return fmt.Errorf("不存在对应的节点: %s", nodeId)
|
||||
}
|
||||
|
||||
exists, _ := project_info.Exists(nodeModel.WorkspaceId, nodeModel.Id, projectId)
|
||||
if !exists {
|
||||
return fmt.Errorf("没有找到对应的项目id: %s", projectId)
|
||||
}
|
||||
|
||||
outGivingNodeProjectList := outGivingModel.GetOutGivingNodeProjectList()
|
||||
outGivingNodeProject := outGivingModel.GetNodeProject(outGivingNodeProjectList, nodeModel.Id, projectId)
|
||||
if outGivingNodeProject == nil {
|
||||
outGivingNodeProject = &out_giving.OutGivingNodeProject{}
|
||||
}
|
||||
outGivingNodeProject.NodeId = nodeModel.Id
|
||||
outGivingNodeProject.ProjectId = projectId
|
||||
|
||||
// 检查项目是否已被使用
|
||||
for _, model := range outGivingModels {
|
||||
if strings.EqualFold(model.Id, outGivingModel.Id) {
|
||||
continue
|
||||
}
|
||||
contains := model.CheckContains(outGivingNodeProject.NodeId, outGivingNodeProject.ProjectId)
|
||||
if contains {
|
||||
return fmt.Errorf("已经存在相同的分发项目: %s", outGivingNodeProject.ProjectId)
|
||||
}
|
||||
}
|
||||
|
||||
outGivingNodeProjects = append(outGivingNodeProjects, *outGivingNodeProject)
|
||||
}
|
||||
}
|
||||
|
||||
if len(outGivingNodeProjects) == 0 {
|
||||
return fmt.Errorf("至少选择1个节点项目")
|
||||
}
|
||||
|
||||
outGivingModel.SetOutGivingNodeProjectList(outGivingNodeProjects)
|
||||
|
||||
if afterOpt, ok := body["afterOpt"]; ok {
|
||||
afterOptInt := int(afterOpt.(float64))
|
||||
outGivingModel.AfterOpt = afterOptInt
|
||||
} else {
|
||||
return fmt.Errorf("请选择分发后的操作")
|
||||
}
|
||||
|
||||
outGivingModel.IntervalTime = 10
|
||||
|
||||
if clearOld, ok := body["clearOld"]; ok {
|
||||
outGivingModel.ClearOld = clearOld.(bool)
|
||||
}
|
||||
|
||||
if secondaryDirectory, ok := body["secondaryDirectory"]; ok {
|
||||
if secondaryDirectory != nil {
|
||||
s := secondaryDirectory.(string)
|
||||
outGivingModel.SecondaryDirectory = &s
|
||||
}
|
||||
}
|
||||
|
||||
if uploadCloseFirst, ok := body["uploadCloseFirst"]; ok {
|
||||
outGivingModel.UploadCloseFirst = uploadCloseFirst.(bool)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 释放关联分发项目
|
||||
func ReleaseDel(c *gin.Context) {
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
id, ok := bodyToMap["id"]
|
||||
if !ok {
|
||||
controller.Fail(c, errors.ServerError, "id不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
// todo 验证是否需要workspaceId
|
||||
outGivingModel := out_giving.GetOutGivingModelById(id.(string))
|
||||
if outGivingModel == nil {
|
||||
controller.Fail(c, errors.ServerError, "没有找到对应的分发id")
|
||||
return
|
||||
}
|
||||
|
||||
outGivingNodeProjectList := outGivingModel.GetOutGivingNodeProjectList()
|
||||
|
||||
for _, outGivingNodeProject := range outGivingNodeProjectList {
|
||||
nodeModel := node.GetNodeById(outGivingNodeProject.NodeId)
|
||||
if nodeModel.Id == "" {
|
||||
controller.Fail(c, errors.ServerError, "没有找到对应的节点")
|
||||
return
|
||||
}
|
||||
|
||||
body := map[string]string{
|
||||
"id": outGivingNodeProject.ProjectId,
|
||||
}
|
||||
body1, _ := json.Marshal(body)
|
||||
resp, err := common.Request5(nodeModel, common.Manage_ReleaseOutGiving, bytes.NewReader(body1))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "释放节点项目失败")
|
||||
return
|
||||
}
|
||||
if resp.Result.Code != errors.SUCCESS {
|
||||
controller.FailCode(c, errors.ServerError, err1.New(resp.Result.Msg), "释放节点项目失败: "+resp.Result.Msg)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
rows, err := out_giving.DeleteOutGivingModelById(id.(string))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "删除分发失败")
|
||||
return
|
||||
}
|
||||
if rows >= 0 {
|
||||
out_giving.DeleteOutGivingLogByOutGivingId(id.(string))
|
||||
}
|
||||
|
||||
controller.Success(c, "释放成功")
|
||||
}
|
||||
|
||||
// 解绑关联分发项目
|
||||
func Unbind(c *gin.Context) {
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
id, ok := bodyToMap["id"]
|
||||
if !ok {
|
||||
controller.Fail(c, errors.ServerError, "id不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
outGivingModel := out_giving.GetOutGivingModelById(id.(string))
|
||||
if outGivingModel == nil {
|
||||
controller.Fail(c, errors.ServerError, "没有找到对应的分发id")
|
||||
return
|
||||
}
|
||||
|
||||
rows, err := out_giving.DeleteOutGivingModelById(id.(string))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "删除分发失败")
|
||||
return
|
||||
}
|
||||
if rows >= 0 {
|
||||
out_giving.DeleteOutGivingLogByOutGivingId(id.(string))
|
||||
}
|
||||
|
||||
// todo 删除日志
|
||||
controller.Success(c, "解绑成功")
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package outgiving
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller/v1/app_manage"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/out_giving"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type OutGivingLogPageBody struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
NodeId string `json:"nodeId"`
|
||||
OutGivingId string `json:"outGivingId"`
|
||||
Status string `json:"status"`
|
||||
CreateTimeMillis string `json:"createTimeMillis"`
|
||||
}
|
||||
|
||||
// {
|
||||
// "page": "1",
|
||||
// "limit": "10",
|
||||
// "total": "0",
|
||||
// "nodeId": "56e192c8e76742fa85c72342212ef466",
|
||||
// "outGivingId": "8KY1Y1",
|
||||
// "status": "0",
|
||||
// }
|
||||
func ListData(c *gin.Context) {
|
||||
var pageBody OutGivingLogPageBody
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
fields := map[string]interface{}{}
|
||||
if pageBody.NodeId != "" {
|
||||
fields["node_id"] = pageBody.NodeId
|
||||
}
|
||||
if pageBody.OutGivingId != "" {
|
||||
fields["out_giving_id"] = pageBody.OutGivingId
|
||||
}
|
||||
if pageBody.Status != "" {
|
||||
fields["status"] = pageBody.Status
|
||||
}
|
||||
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
fields["workspace_id"] = workspaceId
|
||||
|
||||
page := &model.Page[out_giving.OutGivingLog]{
|
||||
CurrentPage: pageBody.PageInfo.CurrentPage,
|
||||
PageSize: pageBody.PageInfo.PageSize,
|
||||
Order: pageBody.PageInfo.Order,
|
||||
}
|
||||
|
||||
log := out_giving.NewOutGivingLog()
|
||||
err = log.Page(page, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "查询分发日志失败!")
|
||||
return
|
||||
}
|
||||
|
||||
controller.Success(c, page)
|
||||
}
|
||||
|
||||
func GetLogsIdByExecId(c *gin.Context) {
|
||||
value := c.Query("execId")
|
||||
id, err := out_giving.GetOutGivingExecLogById(value)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "查询分发日志失败!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, id)
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
{
|
||||
"id": "6MH5DC",
|
||||
"name": "asdf",
|
||||
"type": "edit",
|
||||
"afterOpt": "0",
|
||||
"runMode": "Jar",
|
||||
"whitelistDirectory": "/home/tmn/jpom/project/ds/",
|
||||
"lib": "aaaaa",
|
||||
"logPath": "",
|
||||
"intervalTime": "10",
|
||||
"clearOld": "false",
|
||||
"secondaryDirectory": "",
|
||||
"uploadCloseFirst": "false",
|
||||
"56e192c8e76742fa85c72342212ef466_jvm": "-Xms=512m",
|
||||
"56e192c8e76742fa85c72342212ef466_token": "",
|
||||
"56e192c8e76742fa85c72342212ef466_args": "--server.port=8080",
|
||||
"56e192c8e76742fa85c72342212ef466_autoStart": "true",
|
||||
"56e192c8e76742fa85c72342212ef466_dslEnv": "key1=v1",
|
||||
"5722cd7a4e7a475cac61da2507088a9d_jvm": "-Xms=512m",
|
||||
"5722cd7a4e7a475cac61da2507088a9d_token": "",
|
||||
"5722cd7a4e7a475cac61da2507088a9d_args": "--server.port=8080",
|
||||
"5722cd7a4e7a475cac61da2507088a9d_autoStart": "true",
|
||||
"5722cd7a4e7a475cac61da2507088a9d_dslEnv": "",
|
||||
"nodeIds": "56e192c8e76742fa85c72342212ef466,5722cd7a4e7a475cac61da2507088a9d"
|
||||
},
|
||||
{
|
||||
"type": "add",
|
||||
"id": "D5ZQF4",
|
||||
"name": "dsldsl",
|
||||
"afterOpt": "0",
|
||||
"runMode": "Dsl",
|
||||
"whitelistDirectory": "/home/tmn/jpom/project/ds/",
|
||||
"lib": "dsfsadd",
|
||||
"clearOld": "true",
|
||||
"dslContent": "# scriptId 可以是项目路径下脚本文件名或者系统中的脚本模版ID\ndescription: 测试\nrun:\n start:\n# scriptId: project.sh\n scriptId: \n scriptArgs: start\n scriptEnv:\n \"boot_active\": test\n status:\n# scriptId: project.sh\n scriptId: \n scriptArgs: status\n stop:\n# scriptId: project.sh\n scriptId: \n scriptArgs: stop\n# restart:\n## scriptId: project.sh\n# scriptId: \n# scriptArgs: restart\n# scriptEnv:\n# \"boot_active\": test\nfile:\n# 备份文件保留个数\n# backupCount: 5\n# 限制备份指定文件后缀(支持正则)\n# backupSuffix: [ '.jar','.html','^.+\\.(?i)(txt)$' ]\n# 项目文件备份路径\n# backupPath: /data/jpom_backup\nconfig:\n# 是否开启日志备份功能\n# autoBackToFile: true\n\n",
|
||||
"secondaryDirectory": "/second",
|
||||
"group": "gg",
|
||||
"logPath": "",
|
||||
"uploadCloseFirst": "true",
|
||||
"56e192c8e76742fa85c72342212ef466_dslEnv": "k1=v1",
|
||||
"5722cd7a4e7a475cac61da2507088a9d_dslEnv": "k1=v2",
|
||||
"nodeIds": "56e192c8e76742fa85c72342212ef466,5722cd7a4e7a475cac61da2507088a9d"
|
||||
}
|
||||
|
@ -0,0 +1,458 @@
|
||||
package outgiving
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
err1 "errors"
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller/v1/app_manage"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/middleware"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/node"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/out_giving"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/server_white_list"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/system_parameters"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/user"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/response"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/common"
|
||||
node2 "git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/node"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/pkg/log"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 创建分发项目
|
||||
func SavePorject(c *gin.Context) {
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
typeStr, _ := bodyToMap["type"].(string)
|
||||
id, _ := bodyToMap["id"].(string)
|
||||
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
bodyToMap["workspace_id"] = workspaceId
|
||||
|
||||
userObject, _ := c.Get(middleware.LoginUserKey)
|
||||
userModel := userObject.(*user.UserObj)
|
||||
|
||||
if "add" == typeStr {
|
||||
checkId := strings.ReplaceAll(id, "-", "")
|
||||
checkId = strings.ReplaceAll(checkId, "_", "")
|
||||
err := validateID(checkId)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, err.Error())
|
||||
return
|
||||
}
|
||||
addOutGiving(c, id, bodyToMap, userModel)
|
||||
} else {
|
||||
updateGiving(c, id, bodyToMap, userModel)
|
||||
}
|
||||
|
||||
}
|
||||
func DeletePorject(c *gin.Context) {
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
id, ok := bodyToMap["id"]
|
||||
if !ok {
|
||||
controller.Fail(c, errors.ServerError, "id不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
thorough, ok := bodyToMap["thorough"]
|
||||
if !ok {
|
||||
controller.Fail(c, errors.ServerError, "id不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
outGivingModel := out_giving.GetOutGivingModelById(id.(string))
|
||||
if outGivingModel == nil {
|
||||
controller.Fail(c, errors.ServerError, "没有找到对应的分发项目")
|
||||
return
|
||||
}
|
||||
|
||||
// 该项目不是节点分发项目,不能在此次删除
|
||||
if !outGivingModel.OutGivingProject {
|
||||
controller.Fail(c, errors.ServerError, "该项目不是节点分发项目,不能在此处删除")
|
||||
return
|
||||
}
|
||||
|
||||
outGivingNodeProjectList := outGivingModel.GetOutGivingNodeProjectList()
|
||||
|
||||
for _, outGivingNodeProject := range outGivingNodeProjectList {
|
||||
nodeModel := node.GetNodeById(outGivingNodeProject.NodeId)
|
||||
if nodeModel.Id == "" {
|
||||
controller.Fail(c, errors.ServerError, "没有找到对应的节点")
|
||||
return
|
||||
}
|
||||
|
||||
resp := deleteNodeProject(nodeModel, outGivingModel.Id, thorough.(string))
|
||||
|
||||
if resp.Result.Code != errors.SUCCESS {
|
||||
controller.FailCode(c, errors.ServerError, err1.New(resp.Result.Msg), nodeModel.Name+"节点失败: "+resp.Result.Msg)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
rows, err := out_giving.DeleteOutGivingModelById(id.(string))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "删除分发失败")
|
||||
return
|
||||
}
|
||||
if rows >= 0 {
|
||||
out_giving.DeleteOutGivingLogByOutGivingId(id.(string))
|
||||
}
|
||||
|
||||
controller.Success(c, "删除成功")
|
||||
}
|
||||
|
||||
func addOutGiving(c *gin.Context, id string, body map[string]interface{}, userObj *user.UserObj) {
|
||||
byId := out_giving.GetOutGivingModelById(id)
|
||||
if byId.Id != "" {
|
||||
controller.FailCode(c, errors.ServerError, nil, "项目id已存在")
|
||||
return
|
||||
}
|
||||
outGivingModel := out_giving.NewOutGivingModel()
|
||||
outGivingModel.Id = id
|
||||
outGivingModel.OutGivingProject = true
|
||||
outGivingModel.CreateUser = userObj.UserID
|
||||
outGivingModel.ModifyUser = userObj.UserID
|
||||
|
||||
tuples, err := doData(outGivingModel, body, false)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
_, err = outGivingModel.Create(outGivingModel)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, nil, "项目id已存在")
|
||||
return
|
||||
}
|
||||
|
||||
// saveNodeData
|
||||
res := saveNodeData(outGivingModel, tuples, false)
|
||||
if res != nil {
|
||||
controller.Fail(c, errors.ServerError, res.Result.Msg)
|
||||
return
|
||||
}
|
||||
|
||||
controller.Success(c, "添加成功")
|
||||
}
|
||||
|
||||
func updateGiving(c *gin.Context, id string, body map[string]interface{}, userObj *user.UserObj) {
|
||||
outGivingModel := out_giving.GetOutGivingModelById(id)
|
||||
if outGivingModel == nil {
|
||||
controller.Fail(c, errors.ServerError, "没有找到对应的分发id")
|
||||
return
|
||||
}
|
||||
|
||||
tuples, err := doData(outGivingModel, body, true)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
outGivingModel.ModifyUser = userObj.UserID
|
||||
outGivingModel.ModifyTimeMillis = time.Now().UnixMilli()
|
||||
err = out_giving.UpdateOutGivingModel(outGivingModel, []string{"name", "group", "workspace_id", "after_opt", "secondary_directory",
|
||||
"out_giving_node_project_list", "clear_old", "upload_close_first", "secondary_directory", "modify_user", "modify_time_millis"})
|
||||
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "修改失败")
|
||||
return
|
||||
}
|
||||
// saveNodeData 保存节点项目数据
|
||||
res := saveNodeData(outGivingModel, tuples, true)
|
||||
if res != nil {
|
||||
controller.Fail(c, errors.ServerError, res.Result.Msg)
|
||||
return
|
||||
}
|
||||
|
||||
controller.Success(c, "修改成功")
|
||||
}
|
||||
|
||||
// 保存节点项目数据
|
||||
func saveNodeData(outGivingModel *out_giving.OutGivingModel, tuples map[string]map[string]interface{}, edit bool) *response.Response {
|
||||
successTuples := map[string]interface{}{}
|
||||
fail := false
|
||||
|
||||
for key, value := range tuples {
|
||||
nodeModelId := key
|
||||
n, _ := app_manage.TryGetNode(map[string]interface{}{"nodeId": nodeModelId})
|
||||
|
||||
dataJSON := value
|
||||
jsonMessage := sendData(n, dataJSON, true)
|
||||
if jsonMessage.Result.Code != errors.SUCCESS {
|
||||
if !edit {
|
||||
out_giving.DeleteOutGivingModelById(outGivingModel.Id)
|
||||
fail = true
|
||||
}
|
||||
|
||||
if fail {
|
||||
for nodeModelId, _ = range successTuples {
|
||||
resp := deleteNodeProject(n, outGivingModel.Id, "")
|
||||
if resp.Result.Code != errors.SUCCESS {
|
||||
log.Errorf("还原项目失败:" + resp.Result.Msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jsonMessage.Result.Msg = n.Name + "节点失败:" + jsonMessage.Result.Msg
|
||||
return jsonMessage
|
||||
}
|
||||
|
||||
successTuples[key] = value
|
||||
// 同步项目信息
|
||||
node2.SyncNodeProjectInfo(n, outGivingModel.Id)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 创建项目管理的默认数据
|
||||
func getDefData(outGivingModel *out_giving.OutGivingModel, body map[string]interface{}, edit bool) (map[string]interface{}, error) {
|
||||
defData := make(map[string]interface{})
|
||||
defData["id"] = outGivingModel.Id
|
||||
defData["name"] = outGivingModel.Name
|
||||
defData["group"] = outGivingModel.Group
|
||||
|
||||
runMode := body["runMode"]
|
||||
defData["runMode"] = runMode
|
||||
|
||||
if runMode == "Dsl" {
|
||||
dslContent := body["dslContent"]
|
||||
defData["dslContent"] = dslContent
|
||||
}
|
||||
|
||||
whitelistDirectory := body["whitelistDirectory"]
|
||||
// 获取白名单
|
||||
s := &system_parameters.SystemParameters{}
|
||||
s.Id = server_white_list.GetId(outGivingModel.WorkspaceId)
|
||||
_ = s.GetById(s)
|
||||
serverWhitelist := &server_white_list.ServerWhitelist{}
|
||||
if s.Value != "" {
|
||||
err := json.Unmarshal([]byte(s.Value), serverWhitelist)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var outGivingArray []string
|
||||
if strings.Contains(serverWhitelist.OutGiving, "\r\n") == true {
|
||||
outGivingArray = strings.Split(serverWhitelist.OutGiving, "\r\n")
|
||||
} else {
|
||||
outGivingArray = strings.Split(serverWhitelist.OutGiving, "\n")
|
||||
}
|
||||
|
||||
checkPath := server_white_list.CheckPath(outGivingArray, whitelistDirectory.(string))
|
||||
if !checkPath {
|
||||
return nil, fmt.Errorf("请选择正确的项目路径,或者还没有配置白名单")
|
||||
}
|
||||
defData["whitelistDirectory"] = whitelistDirectory
|
||||
|
||||
logPath := body["logPath"]
|
||||
if logPath != nil && strings.TrimSpace(logPath.(string)) != "" {
|
||||
checkPath = server_white_list.CheckPath(outGivingArray, whitelistDirectory.(string))
|
||||
if !checkPath {
|
||||
return nil, fmt.Errorf("请选择正确的日志路径,或者还没有配置白名单")
|
||||
}
|
||||
defData["logPath"] = logPath
|
||||
}
|
||||
lib := body["lib"]
|
||||
defData["lib"] = lib
|
||||
|
||||
if edit {
|
||||
defData["edit"] = "on"
|
||||
}
|
||||
defData["previewData"] = true
|
||||
|
||||
return defData, nil
|
||||
}
|
||||
|
||||
// 参考outGivingProjectEditController.example.json
|
||||
func doData(outGivingModel *out_giving.OutGivingModel, body map[string]interface{}, edit bool) (map[string]map[string]interface{}, error) {
|
||||
tuples := make(map[string]map[string]interface{})
|
||||
|
||||
outGivingModel.Name = body["name"].(string)
|
||||
if outGivingModel.Name == "" {
|
||||
return tuples, fmt.Errorf("分发名称不能为空")
|
||||
}
|
||||
outGivingModel.WorkspaceId = body["workspace_id"].(string)
|
||||
|
||||
if groupStr, ok := body["group"]; ok {
|
||||
if groupStr != nil {
|
||||
s := groupStr.(string)
|
||||
outGivingModel.Group = &s
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if afterOpt, ok := body["afterOpt"]; ok {
|
||||
afterOptInt, err := afterOpt.(float64)
|
||||
if err != true {
|
||||
return tuples, fmt.Errorf("参数有误:afterOpt")
|
||||
}
|
||||
outGivingModel.AfterOpt = int(afterOptInt)
|
||||
} else {
|
||||
return tuples, fmt.Errorf("请选择分发后的操作")
|
||||
}
|
||||
|
||||
outGivingModel.IntervalTime = 10
|
||||
|
||||
if clearOld, ok := body["clearOld"]; ok {
|
||||
//toBool := utils.StringToBool(clearOld.(string))
|
||||
outGivingModel.ClearOld = clearOld.(bool)
|
||||
}
|
||||
|
||||
if secondaryDirectory, ok := body["secondaryDirectory"]; ok {
|
||||
if secondaryDirectory != nil {
|
||||
s := secondaryDirectory.(string)
|
||||
outGivingModel.SecondaryDirectory = &s
|
||||
}
|
||||
}
|
||||
|
||||
if uploadCloseFirst, ok := body["uploadCloseFirst"]; ok {
|
||||
//toBool := utils.StringToBool(uploadCloseFirst.(string))
|
||||
outGivingModel.UploadCloseFirst = uploadCloseFirst.(bool)
|
||||
}
|
||||
|
||||
// 填充其他数据
|
||||
defData, err := getDefData(outGivingModel, body, edit)
|
||||
if err != nil {
|
||||
return tuples, err
|
||||
}
|
||||
|
||||
//
|
||||
nodeIdsStr := body["nodeIds"]
|
||||
nodeIds := strings.Split(nodeIdsStr.(string), ",")
|
||||
if len(nodeIds) == 0 {
|
||||
return tuples, fmt.Errorf("没有任何节点信息")
|
||||
}
|
||||
|
||||
outGivingModels := out_giving.ListOutGivingModel()
|
||||
outGivingNodeProjects := make([]out_giving.OutGivingNodeProject, 0)
|
||||
var outGivingNodeProject *out_giving.OutGivingNodeProject
|
||||
|
||||
for _, nodeId := range nodeIds {
|
||||
nodeModel, err := app_manage.TryGetNode(map[string]interface{}{"nodeId": nodeId})
|
||||
if err != nil {
|
||||
return tuples, fmt.Errorf("对应的节点不存在")
|
||||
}
|
||||
|
||||
// 判断项目是否已被使用,还要兼容新增和编辑两种场景!
|
||||
if outGivingModels != nil {
|
||||
for _, model := range outGivingModels {
|
||||
if strings.EqualFold(model.Id, outGivingModel.Id) {
|
||||
continue
|
||||
}
|
||||
contains := model.CheckContains(nodeId, outGivingModel.Id)
|
||||
if contains {
|
||||
return tuples, fmt.Errorf("已经存在相同的分发项目: %s", outGivingModel.Id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nodeProjectList := outGivingModel.GetOutGivingNodeProjectList()
|
||||
// 分发 ID 等同于项目 ID
|
||||
outGivingNodeProject = outGivingModel.GetNodeProject(nodeProjectList, nodeModel.Id, outGivingModel.Id)
|
||||
if outGivingNodeProject == nil {
|
||||
outGivingNodeProject = &out_giving.OutGivingNodeProject{}
|
||||
}
|
||||
outGivingNodeProject.NodeId = nodeModel.Id
|
||||
// 分发id为项目id
|
||||
outGivingNodeProject.ProjectId = outGivingModel.Id
|
||||
outGivingNodeProjects = append(outGivingNodeProjects, *outGivingNodeProject)
|
||||
|
||||
// 准备并检查数据
|
||||
allData := cloneMap(defData)
|
||||
token := body[(fmt.Sprintf("%s_token", nodeModel.Id))]
|
||||
allData["token"] = token
|
||||
jvm := body[fmt.Sprintf("%s_jvm", nodeModel.Id)]
|
||||
allData["jvm"] = jvm
|
||||
args := body[fmt.Sprintf("%s_args", nodeModel.Id)]
|
||||
allData["args"] = args
|
||||
autoStart := body[fmt.Sprintf("%s_autoStart", nodeModel.Id)]
|
||||
//allData["autoStart"] = autoStart.(bool)
|
||||
if _, ok := autoStart.(bool); ok {
|
||||
allData["autoStart"] = autoStart.(bool)
|
||||
}
|
||||
dslEnv := body[fmt.Sprintf("%s_dslEnv", nodeModel.Id)]
|
||||
allData["dslEnv"] = dslEnv
|
||||
|
||||
jsonMessage := sendData(nodeModel, allData, false)
|
||||
if jsonMessage.Result.Code != errors.SUCCESS {
|
||||
return tuples, fmt.Errorf("%s节点失败:%s", nodeModel.Name, jsonMessage.Result.Msg)
|
||||
}
|
||||
|
||||
tuples[nodeModel.Id] = allData
|
||||
}
|
||||
|
||||
if len(outGivingNodeProjects) == 0 {
|
||||
return tuples, fmt.Errorf("至少选择1个节点项目")
|
||||
}
|
||||
// 删除已经删除的项目
|
||||
err = deleteProject(outGivingModel, outGivingNodeProjects)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("删除项目失败: %s", err.Error())
|
||||
}
|
||||
|
||||
outGivingModel.SetOutGivingNodeProjectList(outGivingNodeProjects)
|
||||
|
||||
return tuples, nil
|
||||
}
|
||||
|
||||
// 删除已经删除过的项目
|
||||
func deleteProject(outGivingModel *out_giving.OutGivingModel, outGivingNodeProjects []out_giving.OutGivingNodeProject) error {
|
||||
// 获取需要删除的节点项目
|
||||
deleteNodeProjects := outGivingModel.GetDelete(outGivingNodeProjects)
|
||||
if deleteNodeProjects != nil {
|
||||
for _, outGivingNodeProject := range deleteNodeProjects {
|
||||
nodeModel, err := app_manage.TryGetNode(map[string]interface{}{"nodeId": outGivingNodeProject.NodeId})
|
||||
if err != nil {
|
||||
return fmt.Errorf("节点不存在")
|
||||
}
|
||||
//outGivingNodeProject.GetNodeData(true) // 假设这是获取某些数据的操作,需根据实际情况实现或忽略
|
||||
|
||||
// 彻底删除节点项目
|
||||
jsonMessage := deleteNodeProject(nodeModel, outGivingNodeProject.ProjectId, "thorough")
|
||||
if jsonMessage.Result.Code != errors.SUCCESS {
|
||||
return fmt.Errorf("%s节点失败:%s", nodeModel.Name, jsonMessage.Result.Msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 删除项目
|
||||
func deleteNodeProject(nodeModel *node.Node, projectId, thorough string) *response.Response {
|
||||
data := make(map[string]interface{})
|
||||
data["id"] = projectId
|
||||
data["thorough"] = thorough
|
||||
data["nodeId"] = nodeModel.Id
|
||||
|
||||
resp := app_manage.TryRequestNode("", data, common.Manage_DeleteProject)
|
||||
if resp.Result.Code == errors.SUCCESS {
|
||||
node2.SyncNodeProjectInfo(nodeModel, projectId)
|
||||
}
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
func sendData(nodeModel *node.Node, data map[string]interface{}, save bool) *response.Response {
|
||||
if save {
|
||||
delete(data, "previewData")
|
||||
}
|
||||
data["outGivingProject"] = true
|
||||
data["nodeId"] = nodeModel.Id
|
||||
return app_manage.TryRequestNode("", data, common.Manage_SaveProject)
|
||||
}
|
||||
|
||||
func cloneMap(body map[string]interface{}) map[string]interface{} {
|
||||
clone := make(map[string]interface{})
|
||||
for k, v := range body {
|
||||
// 注意:这里仅实现了浅拷贝,如果value本身是复杂的数据结构(如嵌套的map或slice),
|
||||
// 那么这个拷贝过程不会递归拷贝内部结构,它们仍然会被共享。
|
||||
clone[k] = v
|
||||
}
|
||||
return clone
|
||||
}
|
@ -0,0 +1,520 @@
|
||||
package outgiving
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller/v1/app_manage"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/middleware"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/node"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/out_giving"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/out_giving/status"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/project_info"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/user"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/file_download_client"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/response"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/secure"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/utils"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/utils/file_utils"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/outgiving"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/pkg/log"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 分发文件管理
|
||||
|
||||
func GetItemData(c *gin.Context) {
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
id, ok := bodyToMap["id"].(string)
|
||||
if !ok {
|
||||
controller.Fail(c, http.StatusBadRequest, "参数错误:id")
|
||||
return
|
||||
}
|
||||
|
||||
outGivingModel := out_giving.GetOutGivingModelById(id)
|
||||
if outGivingModel.Id == "" {
|
||||
controller.Fail(c, http.StatusBadRequest, "没有数据")
|
||||
return
|
||||
}
|
||||
|
||||
outGivingNodeProjectList := outGivingModel.GetOutGivingNodeProjectList()
|
||||
nodeMap := mapNodeModels(outGivingNodeProjectList)
|
||||
projectMap := mapProjectInfoCacheModels(outGivingNodeProjectList, workspaceId)
|
||||
|
||||
collect := transformOutGivingNodeProjects(outGivingNodeProjectList, workspaceId, nodeMap, projectMap, id)
|
||||
|
||||
data := map[string]interface{}{
|
||||
"data": outGivingModel,
|
||||
"projectList": collect,
|
||||
}
|
||||
|
||||
controller.Success(c, data)
|
||||
}
|
||||
|
||||
func mapNodeModels(outGivingNodeProjectList []out_giving.OutGivingNodeProject) map[string]node.Node {
|
||||
var nodeIds []string
|
||||
for _, project := range outGivingNodeProjectList {
|
||||
nodeIds = append(nodeIds, project.NodeId)
|
||||
}
|
||||
|
||||
nodeModels := node.GetNodeByIds(nodeIds)
|
||||
nodeMap := make(map[string]node.Node)
|
||||
for _, model := range nodeModels {
|
||||
nodeMap[model.Id] = model
|
||||
}
|
||||
return nodeMap
|
||||
}
|
||||
|
||||
func mapProjectInfoCacheModels(outGivingNodeProjectList []out_giving.OutGivingNodeProject, workspaceId string) map[string]project_info.ProjectInfo {
|
||||
var ids []string
|
||||
for _, project := range outGivingNodeProjectList {
|
||||
projectId := secure.Sha1Encrypt(workspaceId + project.NodeId + project.ProjectId)
|
||||
// todo 检查projectId是否能对得上
|
||||
ids = append(ids, projectId)
|
||||
}
|
||||
|
||||
var projectInfoCacheModels = project_info.GetProjectByIds(ids)
|
||||
projectMap := make(map[string]project_info.ProjectInfo)
|
||||
for _, model := range projectInfoCacheModels {
|
||||
projectMap[model.Id] = model
|
||||
}
|
||||
return projectMap
|
||||
}
|
||||
|
||||
func transformOutGivingNodeProjects(outGivingNodeProjectList []out_giving.OutGivingNodeProject, workspaceId string, nodeMap map[string]node.Node, projectMap map[string]project_info.ProjectInfo, id string) []map[string]interface{} {
|
||||
var collect []map[string]interface{}
|
||||
for _, outGivingNodeProject := range outGivingNodeProjectList {
|
||||
nodeModel, exists := nodeMap[outGivingNodeProject.NodeId]
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
|
||||
// 填充数据ID,项目数据是先保存至逻辑节点后又同步的思路,所以NodeScriptCacheModel在逻辑节点的Id就是ProjectId,在服务端保存时,将Id保存至ProjectId字段,
|
||||
// 然后根据secure.Sha1Encrypt(item.WorkspaceId + item.NodeId + item.ProjectId)生成Id
|
||||
fullId := secure.Sha1Encrypt(workspaceId + outGivingNodeProject.NodeId + outGivingNodeProject.ProjectId)
|
||||
projectInfoCacheModel, exists := projectMap[fullId]
|
||||
var cacheProjectName interface{}
|
||||
if exists {
|
||||
cacheProjectName = projectInfoCacheModel.Name
|
||||
}
|
||||
|
||||
outGivingLog, _ := outgiving.GetByProject(id, outGivingNodeProject)
|
||||
var outGivingStatus, outGivingResult, lastTime, fileSize, progressSize interface{}
|
||||
if outGivingLog != nil {
|
||||
outGivingStatus = outGivingLog.Status
|
||||
outGivingResult = outGivingLog.Result
|
||||
lastTime = outGivingLog.CreateTimeMillis
|
||||
fileSize = outGivingLog.FileSize
|
||||
progressSize = outGivingLog.ProgressSize
|
||||
}
|
||||
|
||||
jsonObject := map[string]interface{}{
|
||||
"sortValue": outGivingNodeProject.SortValue,
|
||||
"disabled": outGivingNodeProject.Disabled,
|
||||
"nodeId": outGivingNodeProject.NodeId,
|
||||
"projectId": outGivingNodeProject.ProjectId,
|
||||
"nodeName": nodeModel.Name,
|
||||
"id": fullId,
|
||||
"cacheProjectName": cacheProjectName,
|
||||
"outGivingStatus": outGivingStatus,
|
||||
"outGivingResult": outGivingResult,
|
||||
"lastTime": lastTime,
|
||||
"fileSize": fileSize,
|
||||
"progressSize": progressSize,
|
||||
}
|
||||
collect = append(collect, jsonObject)
|
||||
}
|
||||
return collect
|
||||
}
|
||||
|
||||
func UploadSharding(c *gin.Context) {
|
||||
// 获取FormData
|
||||
form, err := c.MultipartForm()
|
||||
if err != nil {
|
||||
controller.FailCode(c, http.StatusInternalServerError, err, "解析请求参数失败")
|
||||
return
|
||||
}
|
||||
id := form.Value["id"][0]
|
||||
|
||||
// 状态判断
|
||||
_, err = check(id, func(statusCode int, o *out_giving.OutGivingModel) error {
|
||||
if statusCode == status.ING {
|
||||
return fmt.Errorf("当前还在分发中,请等待分发结束")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
controller.FailCode(c, http.StatusInternalServerError, err, "当前还在分发中,请等待分发结束")
|
||||
return
|
||||
}
|
||||
|
||||
// 提取表单字段
|
||||
nowSlice := form.Value["nowSlice"][0]
|
||||
totalSlice := form.Value["totalSlice"][0]
|
||||
sliceID := form.Value["sliceId"][0]
|
||||
fileSumMD5 := form.Value["fileSumMd5"][0]
|
||||
|
||||
// 获取上传的文件
|
||||
file, header, err := c.Request.FormFile("file")
|
||||
if err != nil {
|
||||
controller.FailCode(c, http.StatusInternalServerError, err, "Failed to get file")
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
userObject, _ := c.Get(middleware.LoginUserKey)
|
||||
userModel := userObject.(*user.UserObj)
|
||||
tempPathName, err := utils.GetUserTempPath(userModel.UserID)
|
||||
|
||||
if err != nil {
|
||||
controller.FailCode(c, http.StatusInternalServerError, err, "上传失败:创建临时目录失败")
|
||||
return
|
||||
}
|
||||
|
||||
err = app_manage.UploadShardingImpl(file, header.Filename, tempPathName, sliceID, totalSlice, nowSlice, fileSumMD5, nil)
|
||||
if err != nil {
|
||||
controller.FailCode(c, http.StatusInternalServerError, err, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
controller.Success(c, "上传成功")
|
||||
}
|
||||
|
||||
func check(id string, consumer func(int, *out_giving.OutGivingModel) error) (*out_giving.OutGivingModel, error) {
|
||||
outGivingModel := out_giving.GetOutGivingModelById(id)
|
||||
if outGivingModel.Id == "" {
|
||||
return nil, fmt.Errorf("上传失败,没有找到对应的分发项目: %s", id)
|
||||
}
|
||||
|
||||
// 检查状态
|
||||
statusCode := outGivingModel.Status
|
||||
return outGivingModel, consumer(statusCode, outGivingModel)
|
||||
}
|
||||
|
||||
func ShardingMerge(c *gin.Context) {
|
||||
var (
|
||||
autoUnzip bool
|
||||
secondaryDirectory string
|
||||
stripComponents float64
|
||||
sliceID string
|
||||
totalSlice float64
|
||||
fileSumMD5 string
|
||||
afterOpt float64
|
||||
clearOld bool
|
||||
id string
|
||||
selectProject string
|
||||
)
|
||||
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
autoUnzip, ok := bodyToMap["autoUnzip"].(bool) // type
|
||||
|
||||
secondaryDirectory, ok = bodyToMap["secondaryDirectory"].(string)
|
||||
if !ok {
|
||||
controller.Fail(c, http.StatusBadRequest, "参数错误:levelName")
|
||||
return
|
||||
}
|
||||
|
||||
stripComponents, ok = bodyToMap["stripComponents"].(float64)
|
||||
|
||||
sliceID, ok = bodyToMap["sliceId"].(string)
|
||||
if !ok {
|
||||
controller.Fail(c, http.StatusBadRequest, "参数错误:sliceID")
|
||||
return
|
||||
}
|
||||
|
||||
totalSlice, ok = bodyToMap["totalSlice"].(float64)
|
||||
if !ok {
|
||||
controller.Fail(c, http.StatusBadRequest, "参数错误:totalSlice")
|
||||
return
|
||||
}
|
||||
|
||||
fileSumMD5, ok = bodyToMap["fileSumMd5"].(string)
|
||||
if !ok {
|
||||
controller.Fail(c, http.StatusBadRequest, "参数错误:fileSumMD5")
|
||||
return
|
||||
}
|
||||
|
||||
afterOpt, ok = bodyToMap["afterOpt"].(float64)
|
||||
|
||||
id, ok = bodyToMap["id"].(string)
|
||||
if !ok {
|
||||
controller.Fail(c, http.StatusBadRequest, "参数错误:id")
|
||||
return
|
||||
}
|
||||
|
||||
clearOld, ok = bodyToMap["clearOld"].(bool)
|
||||
selectProject, ok = bodyToMap["selectProject"].(string)
|
||||
|
||||
// 状态判断
|
||||
_, err := check(id, func(statusCode int, o *out_giving.OutGivingModel) error {
|
||||
if statusCode == status.ING {
|
||||
return fmt.Errorf("当前还在分发中,请等待分发结束")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
controller.FailCode(c, http.StatusInternalServerError, err, "当前还在分发中,请等待分发结束")
|
||||
return
|
||||
}
|
||||
|
||||
userObject, _ := c.Get(middleware.LoginUserKey)
|
||||
userModel := userObject.(*user.UserObj)
|
||||
tempPathName, err := utils.GetUserTempPath(userModel.UserID)
|
||||
if err != nil {
|
||||
controller.FailCode(c, http.StatusInternalServerError, err, "上传失败:创建临时目录失败[tempPathName]")
|
||||
return
|
||||
}
|
||||
|
||||
path, err := utils.GetDataPath()
|
||||
if err != nil {
|
||||
controller.FailCode(c, http.StatusInternalServerError, err, "上传失败:创建临时目录失败[data]")
|
||||
return
|
||||
}
|
||||
destDir := filepath.Join(path, "outGiving", id)
|
||||
err = file_utils.MkdirAll(destDir)
|
||||
if err != nil {
|
||||
controller.FailCode(c, http.StatusInternalServerError, err, "上传失败:创建临时目录失败[outGiving Dir]")
|
||||
return
|
||||
}
|
||||
|
||||
successFile, err := app_manage.ShardingTryMergeImpl(tempPathName, sliceID, int(totalSlice), fileSumMD5)
|
||||
if err != nil {
|
||||
controller.FailCode(c, http.StatusInternalServerError, err, err.Error())
|
||||
return
|
||||
}
|
||||
// 从绝对路径successFile.Name中获取文件名
|
||||
successFileName := filepath.Base(successFile.Name())
|
||||
destFile := filepath.Join(destDir, successFileName)
|
||||
|
||||
destFile, err = checkZip(destFile, autoUnzip)
|
||||
if err != nil {
|
||||
controller.FailCode(c, http.StatusInternalServerError, err, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
err = file_utils.MoveFileOrDir(successFile.Name(), destDir, true)
|
||||
if err != nil {
|
||||
controller.FailCode(c, http.StatusInternalServerError, err, "上传失败:创建临时目录失败[outGiving dest]")
|
||||
return
|
||||
}
|
||||
|
||||
outGivingModel := out_giving.NewOutGivingModel()
|
||||
outGivingModel.Id = id
|
||||
outGivingModel.ClearOld = clearOld
|
||||
after := int(afterOpt)
|
||||
outGivingModel.AfterOpt = after
|
||||
outGivingModel.SecondaryDirectory = &secondaryDirectory
|
||||
outGivingModel.ModifyUser = userModel.UserID
|
||||
outGivingModel.ModifyTimeMillis = time.Now().UnixMilli()
|
||||
out_giving.UpdateOutGivingModel(outGivingModel, []string{"after_opt", "secondary_directory", "clear_old", "secondary_directory", "modify_user", "modify_time_millis"})
|
||||
|
||||
stripComponentsInt := int(stripComponents)
|
||||
|
||||
outGivingExecId := uuid.New().String()
|
||||
|
||||
outGivingRun := outgiving.NewOutGivingRun(id, destFile, userModel, autoUnzip, stripComponentsInt, true)
|
||||
go outGivingRun.StartRun(selectProject, outGivingExecId)
|
||||
//outGivingRun.StartRun(selectProject)
|
||||
|
||||
dataResp := response.Resp()
|
||||
dataResp.SetCode(http.StatusOK)
|
||||
dataResp.Result.Data = map[string]string{
|
||||
"result": "上传成功,开始分发!",
|
||||
"outGivingExecId": outGivingExecId,
|
||||
}
|
||||
dataResp.Success(c)
|
||||
//controller.Success(c, "上传成功,开始分发!")
|
||||
}
|
||||
|
||||
func RemoteDownload(c *gin.Context) {
|
||||
var (
|
||||
id string
|
||||
afterOpt float64
|
||||
clearOld bool
|
||||
url string
|
||||
autoUnzip bool
|
||||
secondaryDirectory string
|
||||
stripComponents float64
|
||||
selectProject string
|
||||
filename string
|
||||
)
|
||||
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
|
||||
id, ok := bodyToMap["id"].(string)
|
||||
if !ok {
|
||||
controller.Fail(c, http.StatusBadRequest, "参数错误:id")
|
||||
return
|
||||
}
|
||||
afterOpt, ok = bodyToMap["afterOpt"].(float64)
|
||||
clearOld, ok = bodyToMap["clearOld"].(bool)
|
||||
url, ok = bodyToMap["url"].(string)
|
||||
if !ok {
|
||||
controller.Fail(c, http.StatusBadRequest, "参数错误:url")
|
||||
return
|
||||
}
|
||||
autoUnzip, ok = bodyToMap["autoUnzip"].(bool) // type
|
||||
secondaryDirectory, ok = bodyToMap["secondaryDirectory"].(string)
|
||||
if !ok {
|
||||
controller.Fail(c, http.StatusBadRequest, "参数错误:secondaryDirectory")
|
||||
return
|
||||
}
|
||||
|
||||
stripComponents, ok = bodyToMap["stripComponents"].(float64)
|
||||
selectProject, ok = bodyToMap["selectProject"].(string)
|
||||
filename, ok = bodyToMap["filename"].(string)
|
||||
|
||||
// 状态判断
|
||||
outGivingModel, err := check(id, func(statusCode int, o *out_giving.OutGivingModel) error {
|
||||
if statusCode == status.ING {
|
||||
return fmt.Errorf("当前还在分发中,请等待分发结束")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
controller.FailCode(c, http.StatusInternalServerError, err, "当前还在分发中,请等待分发结束")
|
||||
return
|
||||
}
|
||||
|
||||
userObject, _ := c.Get(middleware.LoginUserKey)
|
||||
userModel := userObject.(*user.UserObj)
|
||||
|
||||
outGivingModel.ClearOld = clearOld
|
||||
after := afterOpt
|
||||
outGivingModel.AfterOpt = int(after)
|
||||
outGivingModel.SecondaryDirectory = &secondaryDirectory
|
||||
outGivingModel.ModifyUser = userModel.UserID
|
||||
outGivingModel.ModifyTimeMillis = time.Now().UnixMilli()
|
||||
out_giving.UpdateOutGivingModel(outGivingModel, []string{"after_opt", "secondary_directory", "clear_old", "secondary_directory", "modify_user", "modify_time_millis"})
|
||||
|
||||
// 下载
|
||||
path, err := utils.GetDataPath()
|
||||
if err != nil {
|
||||
controller.FailCode(c, http.StatusInternalServerError, err, "上传失败:创建临时目录失败[data]")
|
||||
return
|
||||
}
|
||||
destDir := filepath.Join(path, "outGiving", id)
|
||||
err = file_utils.MkdirAll(destDir)
|
||||
if err != nil {
|
||||
controller.FailCode(c, http.StatusInternalServerError, err, "上传失败:创建临时目录失败[outGiving Dir]")
|
||||
return
|
||||
}
|
||||
|
||||
var destFile string
|
||||
if len(filename) == 0 {
|
||||
destFile = filepath.Join(destDir, uuid.New().String())
|
||||
} else {
|
||||
destFile = filepath.Join(destDir, filename)
|
||||
}
|
||||
|
||||
err = file_download_client.DownloadFileToLocal(url, destFile, 2)
|
||||
if err != nil {
|
||||
controller.FailCode(c, http.StatusInternalServerError, err, "下载文件失败")
|
||||
return
|
||||
}
|
||||
|
||||
destFile, err = CheckType(destFile, autoUnzip)
|
||||
if err != nil {
|
||||
controller.FailCode(c, http.StatusInternalServerError, err, err.Error())
|
||||
return
|
||||
}
|
||||
// 开启
|
||||
stripComponentsInt := int(stripComponents)
|
||||
|
||||
outGivingExecId := uuid.New().String()
|
||||
outGivingRun := outgiving.NewOutGivingRun(id, destFile, userModel, autoUnzip, stripComponentsInt, true)
|
||||
go outGivingRun.StartRun(selectProject, outGivingExecId)
|
||||
|
||||
dataResp := response.Resp()
|
||||
dataResp.SetCode(http.StatusOK)
|
||||
dataResp.Result.Data = map[string]string{
|
||||
"result": "上传成功,开始分发!",
|
||||
"outGivingExecId": outGivingExecId,
|
||||
}
|
||||
dataResp.Success(c)
|
||||
//controller.Success(c, "上传成功,开始分发!")
|
||||
}
|
||||
|
||||
func CheckType(filePath string, unzip bool) (string, error) {
|
||||
if !unzip {
|
||||
return filePath, nil
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
log.Errorf("Error reading file: %v", err)
|
||||
return "", fmt.Errorf("读取文件失败: %s", filePath)
|
||||
}
|
||||
|
||||
switch {
|
||||
case bytes.HasPrefix(data, []byte{0x50, 0x4b, 0x03, 0x04}): // ZIP format
|
||||
return filePath, nil
|
||||
case bytes.HasPrefix(data, []byte{0x1f, 0x8b}):
|
||||
return filePath, nil
|
||||
default:
|
||||
log.Errorf("UnSupported file type.")
|
||||
return "", fmt.Errorf("不支持的文件类型: %s", filePath)
|
||||
}
|
||||
}
|
||||
|
||||
var PACKAGE_EXT = []string{"tar.gz", "zip"}
|
||||
|
||||
// 检查并处理ZIP文件
|
||||
func checkZip(path string, unzip bool) (string, error) {
|
||||
if unzip {
|
||||
zip := false
|
||||
for _, ext := range PACKAGE_EXT {
|
||||
if strings.HasSuffix(strings.ToLower(path), strings.ToLower(ext)) {
|
||||
zip = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !zip {
|
||||
return "", fmt.Errorf("不支持的文件类型: %s", filepath.Base(path))
|
||||
}
|
||||
}
|
||||
|
||||
// 这里仅返回文件对象,未执行解压逻辑,如需解压还需额外实现
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func Cancel(c *gin.Context) {
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
|
||||
id, ok := bodyToMap["id"].(string)
|
||||
if !ok {
|
||||
controller.Fail(c, http.StatusBadRequest, "参数错误:id")
|
||||
return
|
||||
}
|
||||
|
||||
// 状态判断
|
||||
outGigving, err := check(id, func(statusCode int, o *out_giving.OutGivingModel) error {
|
||||
if statusCode != status.ING {
|
||||
return fmt.Errorf("当前状态不是分发中")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
controller.FailCode(c, http.StatusInternalServerError, err, "当前状态不是分发中")
|
||||
return
|
||||
}
|
||||
|
||||
userObject, _ := c.Get(middleware.LoginUserKey)
|
||||
userModel := userObject.(*user.UserObj)
|
||||
outgiving.Cancel(outGigving.Id, userModel)
|
||||
|
||||
controller.Success(c, "取消成功")
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package outgiving
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/server_white_list"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/system_parameters"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/workspace"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func GetWhiteList(c *gin.Context) {
|
||||
workspaceId := c.Query("workspaceId")
|
||||
if workspaceId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
s := &system_parameters.SystemParameters{}
|
||||
s.Id = server_white_list.GetId(workspaceId)
|
||||
_ = s.GetById(s)
|
||||
|
||||
controller.Success(c, s.Value)
|
||||
}
|
||||
|
||||
func SaveWhiteList(c *gin.Context) {
|
||||
workspaceId := c.PostForm("workspaceId")
|
||||
if workspaceId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
w := &workspace.Workspace{}
|
||||
w.Id = workspaceId
|
||||
err := w.GetById(w)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
value := c.PostForm("value")
|
||||
s := &system_parameters.SystemParameters{}
|
||||
s.Id = server_white_list.GetId(workspaceId)
|
||||
err = s.GetById(s)
|
||||
if err == nil {
|
||||
s.Value = value
|
||||
s.SetModifyUserName(service.GetUserName(c))
|
||||
_, err = s.Update(s, []string{"value"})
|
||||
} else if err == gorm.ErrRecordNotFound {
|
||||
s.Value = value
|
||||
s.SetUserName(service.GetUserName(c))
|
||||
_, err = s.Create(s)
|
||||
} else {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "服务异常!")
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "服务异常!")
|
||||
return
|
||||
}
|
||||
|
||||
controller.Success(c, "")
|
||||
}
|
@ -0,0 +1,367 @@
|
||||
package server_script
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller/v1/app_manage"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/middleware"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
node2 "git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/node"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/script_info"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/workspace"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/user"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/utils/collect"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/utils/string_utils"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/base_service"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/common"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/node/script"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/server_script"
|
||||
"github.com/gin-gonic/gin"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ProjectPageBody struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
}
|
||||
|
||||
func ScriptList(c *gin.Context) {
|
||||
var pageBody ProjectPageBody
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
fields := map[string]interface{}{}
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
fields["workspace_id"] = []string{workspaceId, "GLOBAL"}
|
||||
|
||||
page := &model.Page[script_info.ScriptModel]{
|
||||
CurrentPage: pageBody.PageInfo.CurrentPage,
|
||||
PageSize: pageBody.PageInfo.PageSize,
|
||||
Order: pageBody.PageInfo.Order,
|
||||
}
|
||||
|
||||
model := script_info.NewScriptModel()
|
||||
err = model.Page(page, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "查询脚本失败!")
|
||||
return
|
||||
}
|
||||
|
||||
controller.Success(c, page)
|
||||
}
|
||||
|
||||
func ScriptListAll(c *gin.Context) {
|
||||
fields := map[string]interface{}{}
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
fields["workspace_id"] = []string{workspaceId, "GLOBAL"}
|
||||
|
||||
model := script_info.NewScriptModel()
|
||||
all, err := model.GetAll(model, fields, nil)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "查询脚本失败!")
|
||||
return
|
||||
}
|
||||
|
||||
controller.Success(c, all)
|
||||
}
|
||||
|
||||
// Save 保存脚本
|
||||
// 1.服务端保存脚本 2.分发脚本
|
||||
func Save(c *gin.Context) {
|
||||
body := request.GetBody(c)
|
||||
model := script_info.NewScriptModel()
|
||||
err := json.Unmarshal(body, model)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
if len(model.Context) == 0 {
|
||||
controller.FailCode(c, errors.ServerError, err, "内容为空!")
|
||||
}
|
||||
|
||||
err = string_utils.CheckCron(model.AutoExecCron)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "cron表达式错误!")
|
||||
return
|
||||
}
|
||||
|
||||
userObject, _ := c.Get(middleware.LoginUserKey)
|
||||
userModel := userObject.(*user.UserObj)
|
||||
|
||||
var oldNodeIds string
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
|
||||
// 检查用户工作空间权限? 好像没用
|
||||
checkUserWorkspace := base_service.CheckUserWorkspace(workspaceId, userModel)
|
||||
if !checkUserWorkspace {
|
||||
controller.Fail(c, errors.ServerError, "没有对应的工作空间权限")
|
||||
}
|
||||
|
||||
toMap := request.GetBodyToMap(c)
|
||||
global := toMap["global"].(bool)
|
||||
if !global {
|
||||
model.WorkspaceId = workspaceId
|
||||
} else {
|
||||
model.WorkspaceId = "GLOBAL"
|
||||
}
|
||||
|
||||
if len(model.Id) == 0 {
|
||||
model.ModifyUser = userModel.UserID
|
||||
model.CreateUser = userModel.UserID
|
||||
model.CreateTimeMillis = time.Now().UnixNano() / 1e6
|
||||
model.ModifyTimeMillis = time.Now().UnixNano() / 1e6
|
||||
|
||||
_, err = model.Create(model)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "保存失败")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
scriptModel, err := script_info.GetServerScriptModelByIdAndWorkspaceIds(model.Id, []string{workspaceId, "GLOBAL"})
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "没有对应的数据")
|
||||
return
|
||||
}
|
||||
|
||||
if scriptModel.Id == "" {
|
||||
controller.FailCode(c, errors.ServerError, err, "没有对应的数据")
|
||||
return
|
||||
}
|
||||
oldNodeIds = scriptModel.NodeIds
|
||||
|
||||
model.ModifyUser = userModel.UserID
|
||||
model.ModifyTimeMillis = time.Now().UnixNano() / 1e6
|
||||
_, err = model.Update(model, []string{"name", "context", "auto_exec_cron", "def_args", "description", "node_ids", "workspace_id", "modify_user", "modify_time_millis"})
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "更新失败")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = syncNodeScript(model, oldNodeIds)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "同步脚本失败")
|
||||
return
|
||||
}
|
||||
|
||||
controller.Success(c, "修改成功")
|
||||
}
|
||||
|
||||
func syncDelNodeScript(scriptModel *script_info.ScriptModel, delNode []string) {
|
||||
for _, nodeId := range delNode {
|
||||
bodyToMap := map[string]interface{}{
|
||||
"id": scriptModel.Id,
|
||||
"nodeId": nodeId,
|
||||
}
|
||||
|
||||
node, err := app_manage.TryGetNode(bodyToMap)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
response := app_manage.TryRequestNode(node.MachineId, bodyToMap, common.Script_Del)
|
||||
if response.Result.Code == errors.SUCCESS {
|
||||
// 每个涉及到的节点均需要刷新
|
||||
go script.SyncExecuteNode(node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func syncNodeScript(scriptModel *script_info.ScriptModel, oldNode string) error {
|
||||
oldNodeIds := strings.Split(strings.TrimSpace(oldNode), ",") // [1,2,3]
|
||||
newNodeIds := strings.Split(strings.TrimSpace(scriptModel.NodeIds), ",") // [2,3,4]
|
||||
|
||||
// 删除oldNodeIds中的空字符串
|
||||
oldNodeIds = collect.SubtractCollections(oldNodeIds, []string{"", " "})
|
||||
newNodeIds = collect.SubtractCollections(newNodeIds, []string{"", " "})
|
||||
|
||||
delNode := collect.SubtractCollections(oldNodeIds, newNodeIds) // [1]
|
||||
|
||||
// 同步删除了次脚本的节点 // [1]
|
||||
syncDelNodeScript(scriptModel, delNode)
|
||||
|
||||
// 更新 // [2,3,4]
|
||||
for _, newNodeId := range newNodeIds {
|
||||
bodyToMap := map[string]interface{}{
|
||||
"nodeId": newNodeId,
|
||||
}
|
||||
|
||||
node, err := app_manage.TryGetNode(bodyToMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bodyToMap = map[string]interface{}{
|
||||
"id": scriptModel.Id,
|
||||
"type": "sync",
|
||||
"context": scriptModel.Context,
|
||||
"autoExecCron": scriptModel.AutoExecCron,
|
||||
"defArgs": scriptModel.DefArgs,
|
||||
"description": scriptModel.Description,
|
||||
"name": scriptModel.Name,
|
||||
"workspaceId": node.WorkspaceId,
|
||||
"global": strconv.FormatBool(scriptModel.Global()),
|
||||
"nodeId": node.Id,
|
||||
}
|
||||
|
||||
response := app_manage.TryRequestNode(node.MachineId, bodyToMap, common.Script_Save)
|
||||
if response.Result.Code == errors.SUCCESS {
|
||||
go script.SyncExecuteNode(node)
|
||||
} else {
|
||||
return fmt.Errorf("处理 %s 节点同步脚本失败: %s", node.Name, response.Result.Msg)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Del(c *gin.Context) {
|
||||
bodyToMap := request.GetBodyToMap(c)
|
||||
id, _ := bodyToMap["id"].(string)
|
||||
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
|
||||
userObject, _ := c.Get(middleware.LoginUserKey)
|
||||
userModel := userObject.(*user.UserObj)
|
||||
|
||||
scriptModel, err := server_script.GetByKeyAndGlobal(id, workspaceId, userModel)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// server.scriptPath() 的逻辑需要根据实际情况实现
|
||||
file, _ := scriptModel.ScriptPath()
|
||||
err = os.RemoveAll(file)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, fmt.Sprintf("清理脚本文件失败: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
// nodeIds 的分割逻辑
|
||||
nodeIds := scriptModel.NodeIds
|
||||
delNode := strings.Split(strings.TrimSpace(nodeIds), ",")
|
||||
|
||||
// syncDelNodeScript 和 scriptServer.delByKey 的逻辑需要根据实际情况实现
|
||||
syncDelNodeScript(scriptModel, delNode)
|
||||
|
||||
_, err = script_info.DeleteServerScriptByIdAndWorkspaceIds(scriptModel.Id, []string{workspaceId, "GLOBAL"})
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "删除脚本失败:")
|
||||
return
|
||||
}
|
||||
|
||||
//// scriptExecuteLogServer.delByWorkspace 的逻辑需要根据实际情况实现
|
||||
//entity := map[string]interface{}{"scriptId": id}
|
||||
//err = scriptExecuteLogServer.delByWorkspace(request, entity)
|
||||
//if err != nil {
|
||||
// panic(err)
|
||||
//}
|
||||
|
||||
controller.Success(c, "删除成功")
|
||||
}
|
||||
|
||||
func Get(c *gin.Context) {
|
||||
userObject, _ := c.Get(middleware.LoginUserKey)
|
||||
userModel := userObject.(*user.UserObj)
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
|
||||
checkUserWorkspace := base_service.CheckUserWorkspace(workspaceId, userModel)
|
||||
if !checkUserWorkspace {
|
||||
controller.Fail(c, errors.ServerError, "没有对应的工作空间权限")
|
||||
}
|
||||
|
||||
id := c.Query("id")
|
||||
scriptModel, err := server_script.GetByKeyAndGlobal(id, workspaceId, userModel)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
nodeIds := scriptModel.NodeIds
|
||||
newNodeIds := strings.Split(strings.TrimSpace(nodeIds), ",")
|
||||
nodeList := make([]gin.H, 0, len(newNodeIds))
|
||||
for _, nodeId := range newNodeIds {
|
||||
node := node2.GetNodeById(nodeId)
|
||||
if node.Id == "" {
|
||||
nodeList = append(nodeList, gin.H{"nodeName": "未知(数据丢失)", "nodeId": nodeId, "workspaceId": nodeId})
|
||||
} else {
|
||||
jsonObj := gin.H{
|
||||
"nodeName": node.Name,
|
||||
"nodeId": node.Id,
|
||||
"workspaceId": node.WorkspaceId,
|
||||
}
|
||||
ws, err := workspace.GetWorkspaceById(node.WorkspaceId)
|
||||
if err != nil || ws == nil {
|
||||
jsonObj["workspaceName"] = "未知(数据丢失)"
|
||||
} else {
|
||||
jsonObj["workspaceName"] = ws.Name
|
||||
}
|
||||
nodeList = append(nodeList, jsonObj)
|
||||
}
|
||||
}
|
||||
// 判断是否可以编辑节点,不属于自己管理的node,则不具备管理权权限
|
||||
var prohibitSync bool
|
||||
for _, n := range nodeList {
|
||||
if wsID, ok := n["workspaceId"].(string); ok && wsID != workspaceId {
|
||||
prohibitSync = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
jsonOut := gin.H{
|
||||
"data": scriptModel,
|
||||
"nodeList": nodeList,
|
||||
"prohibitSync": prohibitSync,
|
||||
}
|
||||
|
||||
controller.Success(c, jsonOut)
|
||||
}
|
||||
|
||||
func Unbind(c *gin.Context) {
|
||||
id := c.Query("id")
|
||||
fields := map[string]interface{}{}
|
||||
fields["node_ids"] = ""
|
||||
_, err := script_info.UpdateServerScriptById(id, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "解绑失败")
|
||||
return
|
||||
}
|
||||
|
||||
controller.Success(c, "解绑成功")
|
||||
}
|
||||
|
||||
func SyncToWorkspace(c *gin.Context) {
|
||||
userObject, _ := c.Get(middleware.LoginUserKey)
|
||||
userModel := userObject.(*user.UserObj)
|
||||
|
||||
nowWorkspaceId := app_manage.GetWorkspaceId(c)
|
||||
ids := c.Query("ids")
|
||||
toWorkspaceId := c.Query("toWorkspaceId")
|
||||
|
||||
checkUserWorkspace := base_service.CheckUserWorkspace(nowWorkspaceId, userModel)
|
||||
if !checkUserWorkspace {
|
||||
controller.Fail(c, errors.ServerError, "没有对应的工作空间权限")
|
||||
}
|
||||
|
||||
checkUserWorkspace = base_service.CheckUserWorkspace(toWorkspaceId, userModel)
|
||||
if !checkUserWorkspace {
|
||||
controller.Fail(c, errors.ServerError, "没有对应的工作空间权限")
|
||||
}
|
||||
|
||||
err := server_script.SyncToWorkspace(ids, nowWorkspaceId, toWorkspaceId)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "同步失败")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "同步成功")
|
||||
}
|
@ -0,0 +1,355 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
err1 "errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/middleware"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/node"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/out_giving"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/project_info"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/script_info"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/workspace"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/workspace_env"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/user"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/assets"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/base_service"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/validator"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func EditWorkspace(c *gin.Context) {
|
||||
w := &workspace.Workspace{}
|
||||
err := validator.CheckPostParams(c, w)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
if w.Name == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "名称不能为空!")
|
||||
return
|
||||
}
|
||||
err = checkWorkspaceInfo(w.Id, w.Name)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if w.Id == "" {
|
||||
w.SetUserName(service.GetUserName(c))
|
||||
_, err = w.Create(w)
|
||||
} else {
|
||||
w.SetModifyUserName(service.GetUserName(c))
|
||||
_, err = w.Update(w, nil)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "数据库错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
func checkWorkspaceInfo(id, name string) error {
|
||||
w := workspace.New()
|
||||
fields := make(map[string]interface{}, 1)
|
||||
fields["name"] = name
|
||||
var notFields map[string]interface{}
|
||||
if id != "" {
|
||||
notFields = make(map[string]interface{}, 1)
|
||||
notFields["id"] = id
|
||||
}
|
||||
result, _ := w.GetAll(w, fields, notFields)
|
||||
if len(result.([]workspace.Workspace)) > 0 {
|
||||
return err1.New("工作空间名称已存在")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ListWorkSpaceGroup(c *gin.Context) {
|
||||
w := &workspace.Workspace{}
|
||||
result, _ := w.ListGroup()
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
type WorkspacePageBody struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Group string `json:"group"`
|
||||
}
|
||||
|
||||
func PageWorkspaces(c *gin.Context) {
|
||||
var pageBody WorkspacePageBody
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
w := workspace.New()
|
||||
fields := map[string]interface{}{}
|
||||
if pageBody.Id != "" {
|
||||
fields["id"] = pageBody.Id
|
||||
}
|
||||
if pageBody.Name != "" {
|
||||
fields["name"] = pageBody.Name
|
||||
}
|
||||
if pageBody.Group != "" {
|
||||
fields["\"group\""] = pageBody.Group
|
||||
}
|
||||
page := &model.PageConfig{}
|
||||
page.Covert(pageBody.PageInfo)
|
||||
result, err := w.Page(w, page, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
page.Data = result
|
||||
controller.Success(c, page)
|
||||
}
|
||||
|
||||
func ListAllWorkspaces(c *gin.Context) {
|
||||
userObject, _ := c.Get(middleware.LoginUserKey)
|
||||
userModel := userObject.(*user.UserObj)
|
||||
list := base_service.GetUserWorkspaceList(userModel)
|
||||
controller.Success(c, list)
|
||||
|
||||
//w := workspace.New()
|
||||
//result, err := w.GetAll(w, nil, nil)
|
||||
//if err != nil {
|
||||
// controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
// return
|
||||
//}
|
||||
//controller.Success(c, result)
|
||||
}
|
||||
|
||||
// TreeNode represents a node in a tree structure.
|
||||
type TreeNode struct {
|
||||
Id string `json:"id"`
|
||||
ParentId string `json:"parentId"`
|
||||
Weight int `json:"weight"`
|
||||
Name string `json:"name"`
|
||||
WorkspaceBind int `json:"workspaceBind"`
|
||||
Count int `json:"count"`
|
||||
Children []*TreeNode `json:"children"`
|
||||
}
|
||||
|
||||
// NewTreeNode creates a new TreeNode with given parameters.
|
||||
func NewTreeNode(id, parent, name string, weight, workspaceBind, count int) *TreeNode {
|
||||
treeNode := &TreeNode{
|
||||
Id: id,
|
||||
ParentId: parent,
|
||||
Weight: weight,
|
||||
Name: name,
|
||||
WorkspaceBind: workspaceBind,
|
||||
Count: count,
|
||||
Children: nil,
|
||||
}
|
||||
|
||||
return treeNode
|
||||
}
|
||||
|
||||
// Tree is a placeholder for the Tree structure.
|
||||
type Tree struct {
|
||||
Name string `json:"name"`
|
||||
Id string `json:"id"`
|
||||
Children []*TreeNode `json:"children"`
|
||||
}
|
||||
|
||||
// BuildSingle builds a tree from a list of nodes.
|
||||
func BuildSingle(nodes []*TreeNode) *Tree {
|
||||
// Implementation goes here.
|
||||
return &Tree{
|
||||
Name: "",
|
||||
Id: "",
|
||||
Children: nodes,
|
||||
}
|
||||
}
|
||||
|
||||
// PreCheckDelete 删除工作空间前检查
|
||||
func PreCheckDelete(c *gin.Context) {
|
||||
workspaceId := c.Query("id")
|
||||
|
||||
var nodes []*TreeNode
|
||||
|
||||
{
|
||||
// 节点信息
|
||||
cnt, err := node.CountNodeByWorkspaceId(workspaceId)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, nil, "节点信息获取失败!")
|
||||
return
|
||||
}
|
||||
treeNode := NewTreeNode("node", "", "节点信息", 0, 1, int(cnt))
|
||||
nodes = append(nodes, treeNode)
|
||||
}
|
||||
|
||||
{
|
||||
// 工作空间环境变量
|
||||
cnt, err := workspace_env.CountWorkspaceEnvVarByWorkspaceId(workspaceId)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, nil, "工作空间环境变量获取失败!")
|
||||
return
|
||||
}
|
||||
treeNode := NewTreeNode("workspace_env_var", "", "工作空间环境变量", 0, 2, int(cnt))
|
||||
nodes = append(nodes, treeNode)
|
||||
}
|
||||
|
||||
{
|
||||
// 项目信息
|
||||
cnt, err := project_info.CountProjectByWorkspaceId(workspaceId)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, nil, "项目信息获取失败!")
|
||||
return
|
||||
}
|
||||
treeNode := NewTreeNode("project_info", "", "项目信息", 0, 1, int(cnt))
|
||||
nodes = append(nodes, treeNode)
|
||||
}
|
||||
|
||||
{
|
||||
// 节点脚本模版
|
||||
// 节点脚本模版执行记录
|
||||
cnt1, err := script_info.CountNodeScriptByWorkspaceId(workspaceId)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, nil, "节点脚本模版获取失败!")
|
||||
return
|
||||
}
|
||||
|
||||
cnt2, err := script_info.CountNodeScriptExecuteLogByWorkspaceId(workspaceId)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, nil, "节点脚本模版执行记录获取失败!")
|
||||
return
|
||||
}
|
||||
treeNode := NewTreeNode("node_script_execute_log", "node_script_cache", "节点脚本模版执行记录", 0, 1, int(cnt2))
|
||||
newTreeNode := NewTreeNode("node_script_cache", "", "节点脚本模版", 0, 1, int(cnt1))
|
||||
newTreeNode.Children = append(newTreeNode.Children, treeNode)
|
||||
nodes = append(nodes, newTreeNode)
|
||||
}
|
||||
|
||||
{
|
||||
// 节点分发
|
||||
// 分发日志
|
||||
cnt1, err := out_giving.CountOutGivingModelByWorkspaceId(workspaceId)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, nil, "节点分发获取失败")
|
||||
return
|
||||
}
|
||||
|
||||
cnt2, err := out_giving.CountOutGivingLogByWorkspaceId(workspaceId)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, nil, "分发日志获取失败")
|
||||
return
|
||||
}
|
||||
treeNode := NewTreeNode("out_giving_log", "", "分发日志", 0, 3, int(cnt2))
|
||||
newTreeNode := NewTreeNode("out_giving_model", "", "节点分发", 0, 1, int(cnt1))
|
||||
newTreeNode.Children = append(newTreeNode.Children, treeNode)
|
||||
nodes = append(nodes, newTreeNode)
|
||||
}
|
||||
|
||||
{
|
||||
// 脚本模版
|
||||
cnt, err := script_info.CountScriptByWorkspaceId(workspaceId)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, nil, "脚本模版获取失败")
|
||||
return
|
||||
}
|
||||
treeNode := NewTreeNode("script", "", "脚本模版", 0, 1, int(cnt))
|
||||
nodes = append(nodes, treeNode)
|
||||
}
|
||||
|
||||
stringTree := BuildSingle(nodes)
|
||||
controller.Success(c, stringTree)
|
||||
}
|
||||
|
||||
func DeleteWorkspace(c *gin.Context) {
|
||||
workspaceId := c.Param("id")
|
||||
if workspaceId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数:workspaceId!")
|
||||
return
|
||||
}
|
||||
|
||||
if workspaceId == assets.DefaultWorkspace {
|
||||
controller.Fail(c, errors.InvalidParameter, "默认命名空间不允许删除!", "默认命名空间不允许删除!")
|
||||
return
|
||||
}
|
||||
|
||||
{
|
||||
// 节点信息
|
||||
cnt, _ := node.CountNodeByWorkspaceId(workspaceId)
|
||||
if cnt != 0 {
|
||||
controller.FailCode(c, errors.ServerError, nil, "当前工作空间下还存在关联数据:节点信息")
|
||||
return
|
||||
}
|
||||
|
||||
// 项目信息
|
||||
cnt, _ = project_info.CountProjectByWorkspaceId(workspaceId)
|
||||
if cnt != 0 {
|
||||
controller.FailCode(c, errors.ServerError, nil, "当前工作空间下还存在关联数据:项目信息")
|
||||
return
|
||||
}
|
||||
|
||||
// 节点脚本模版
|
||||
cnt, _ = script_info.CountNodeScriptByWorkspaceId(workspaceId)
|
||||
if cnt != 0 {
|
||||
controller.FailCode(c, errors.ServerError, nil, "当前工作空间下还存在关联数据:节点脚本模版")
|
||||
return
|
||||
}
|
||||
|
||||
// 节点脚本模版执行记录
|
||||
cnt, _ = script_info.CountNodeScriptExecuteLogByWorkspaceId(workspaceId)
|
||||
if cnt != 0 {
|
||||
controller.FailCode(c, errors.ServerError, nil, "当前工作空间下还存在关联数据:节点脚本模版执行记录")
|
||||
return
|
||||
}
|
||||
|
||||
// 节点分发
|
||||
cnt, _ = out_giving.CountOutGivingModelByWorkspaceId(workspaceId)
|
||||
if cnt != 0 {
|
||||
controller.FailCode(c, errors.ServerError, nil, "当前工作空间下还存在关联数据:节点分发")
|
||||
return
|
||||
}
|
||||
|
||||
// 脚本模版
|
||||
cnt, _ = script_info.CountScriptByWorkspaceId(workspaceId)
|
||||
if cnt != 0 {
|
||||
controller.FailCode(c, errors.ServerError, nil, "当前工作空间下还存在关联数据:脚本模版")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 判断用户绑定关系
|
||||
allUsers, _ := user.NewUserModel().GetAll(nil, nil)
|
||||
var users []string
|
||||
for _, allUser := range allUsers {
|
||||
contains := strings.Contains(allUser.Namespace, workspaceId)
|
||||
if contains {
|
||||
users = append(users, allUser.Displayname)
|
||||
}
|
||||
}
|
||||
if len(users) > 0 {
|
||||
controller.FailCode(c, errors.ServerError, nil, "当前工作空间下还存在关联数据:用户绑定关系,请先解除绑定关系!"+strings.Join(users, ","))
|
||||
return
|
||||
}
|
||||
|
||||
// 删除环境变量
|
||||
workspace_env.DeleteWorkspaceEnvVarByWorkspaceId(workspaceId)
|
||||
// 删除分发日志
|
||||
out_giving.DeleteOutGivingLogByWorkspaceId(workspaceId)
|
||||
|
||||
w := &workspace.Workspace{}
|
||||
w.Id = workspaceId
|
||||
err := w.GetById(w)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "无法查找到对象!")
|
||||
return
|
||||
}
|
||||
_, err = w.Delete(w)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "删除失败!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "")
|
||||
}
|
@ -0,0 +1,275 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
err1 "errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller/v1/app_manage"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/node"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/workspace_env"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/common"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/validator"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func EditWorkspaceEnv(c *gin.Context) {
|
||||
w := &workspace_env.WorkspaceEnvVar{}
|
||||
err := validator.CheckPostParams(c, w)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
if w.Id == "" {
|
||||
if w.Name == "" || w.Value == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
}
|
||||
err = checkInfo(w.Name, w.WorkspaceId)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, err.Error())
|
||||
return
|
||||
}
|
||||
w.SetUserName(service.GetUserName(c))
|
||||
_, err = w.Create(w)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
|
||||
if w.NodeIds == "" {
|
||||
return
|
||||
}
|
||||
err = syncUpdateNodeEnvVar(w, strings.Split(w.NodeIds, ","))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
w1 := &workspace_env.WorkspaceEnvVar{}
|
||||
w1.Id = w.Id
|
||||
err = w1.GetById(w1)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "数据不存在!")
|
||||
return
|
||||
}
|
||||
if w1.Privacy == 0 && w.Value == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
}
|
||||
w1.Description = w.Description
|
||||
if w.Value != "" {
|
||||
w1.Value = w.Value
|
||||
}
|
||||
w1.Name = w.Name
|
||||
oldNodeIds := w1.NodeIds
|
||||
w1.NodeIds = w.NodeIds
|
||||
w1.SetModifyUserName(service.GetUserName(c))
|
||||
_, err = w.Update(w1, nil)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
if w.NodeIds != "" {
|
||||
newNodeIdArray := strings.Split(w.NodeIds, ",")
|
||||
if oldNodeIds != "" && oldNodeIds != w.NodeIds {
|
||||
var delNodeIds []string
|
||||
oldNodeIdArray := strings.Split(oldNodeIds, ",")
|
||||
for _, oldId := range oldNodeIdArray {
|
||||
find := false
|
||||
for _, newId := range newNodeIdArray {
|
||||
if oldId == newId {
|
||||
find = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !find {
|
||||
delNodeIds = append(delNodeIds, oldId)
|
||||
}
|
||||
}
|
||||
if len(delNodeIds) > 0 {
|
||||
err = syncDelNodeEnvVar(w1.Name, delNodeIds)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "删除节点变量异常!")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
err = syncUpdateNodeEnvVar(w, strings.Split(w.NodeIds, ","))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "更新节点变量异常!")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if oldNodeIds != "" {
|
||||
err = syncDelNodeEnvVar(w1.Name, strings.Split(oldNodeIds, ","))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "删除节点变量异常!")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
func syncUpdateNodeEnvVar(w *workspace_env.WorkspaceEnvVar, nodeIds []string) error {
|
||||
if len(nodeIds) == 0 {
|
||||
return nil
|
||||
}
|
||||
form := make(map[string]interface{}, 1)
|
||||
form["name"] = w.Name
|
||||
form["value"] = w.Value
|
||||
form["description"] = w.Description
|
||||
form["privacy"] = w.Privacy
|
||||
jsonBody, _ := json.Marshal(form)
|
||||
|
||||
for _, nodeId := range nodeIds {
|
||||
n := &node.Node{}
|
||||
n.Id = nodeId
|
||||
err := n.GetById(n)
|
||||
if err != nil {
|
||||
return err1.New("数据不存在")
|
||||
}
|
||||
resp, err := common.Request5(n, common.Workspace_EnvVar_Update, bytes.NewReader(jsonBody))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !resp.IsBusinessSuccess() {
|
||||
return err1.New(resp.Result.Msg)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func syncDelNodeEnvVar(name string, nodeIds []string) error {
|
||||
if len(nodeIds) == 0 {
|
||||
return nil
|
||||
}
|
||||
body := make(map[string]string, 1)
|
||||
body["name"] = name
|
||||
jsonBody, _ := json.Marshal(body)
|
||||
for _, nodeId := range nodeIds {
|
||||
n := &node.Node{}
|
||||
n.Id = nodeId
|
||||
err := n.GetById(n)
|
||||
if err != nil {
|
||||
return err1.New("数据不存在")
|
||||
}
|
||||
resp, err := common.Request5(n, common.Workspace_EnvVar_Delete, bytes.NewReader(jsonBody))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !resp.IsBusinessSuccess() {
|
||||
return err1.New(resp.Result.Msg)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkInfo(name, workspaceId string) error {
|
||||
w := workspace_env.New()
|
||||
fields := make(map[string]interface{}, 2)
|
||||
fields["name"] = name
|
||||
if workspaceId != "GLOBAL" {
|
||||
fields["workspace_id"] = []string{workspaceId, "GLOBAL"}
|
||||
}
|
||||
result, _ := w.GetAll(w, fields, nil)
|
||||
if len(result.([]workspace_env.WorkspaceEnvVar)) > 0 {
|
||||
return err1.New("数据已存在")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeleteWorkspaceEnv(c *gin.Context) {
|
||||
id := c.Query("id")
|
||||
if id == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
w := &workspace_env.WorkspaceEnvVar{}
|
||||
w.Id = id
|
||||
err := w.GetById(w)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "无法查找到对象!")
|
||||
return
|
||||
}
|
||||
|
||||
if w.NodeIds != "" {
|
||||
err = syncDelNodeEnvVar(w.Name, strings.Split(w.NodeIds, ","))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "删除节点变量异常!")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
_, err = w.Delete(w)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
type WorkspaceEnvPageBody struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
WorkspaceId string `json:"workspaceId"`
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
func PageWorkspaceEnvs(c *gin.Context) {
|
||||
var pageBody WorkspaceEnvPageBody
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
if pageBody.WorkspaceId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
w := workspace_env.New()
|
||||
fields := map[string]interface{}{}
|
||||
workspaceId := app_manage.GetWorkspaceId(c)
|
||||
if len(workspaceId) == 0 {
|
||||
split := strings.Split(pageBody.WorkspaceId, ",")
|
||||
fields["workspace_id"] = split
|
||||
} else {
|
||||
fields["workspace_id"] = []string{workspaceId, "GLOBAL"}
|
||||
}
|
||||
|
||||
if pageBody.Name != "" {
|
||||
fields["name"] = pageBody.Name
|
||||
}
|
||||
if pageBody.Value != "" {
|
||||
fields["value"] = pageBody.Value
|
||||
}
|
||||
if pageBody.Description != "" {
|
||||
fields["description"] = pageBody.Description
|
||||
}
|
||||
page := &model.PageConfig{}
|
||||
page.Covert(pageBody.PageInfo)
|
||||
tResult, err := w.Page(w, page, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
result := tResult.([]workspace_env.WorkspaceEnvVar)
|
||||
if result != nil && len(result) > 0 {
|
||||
for i := range result {
|
||||
if result[i].Privacy == 1 {
|
||||
result[i].Value = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
page.Data = result
|
||||
controller.Success(c, page)
|
||||
}
|
126
server/internal/controller/v1/app_manage/user.go
Normal file
126
server/internal/controller/v1/app_manage/user.go
Normal file
@ -0,0 +1,126 @@
|
||||
package app_manage
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/workspace"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/user"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type UserPageBody struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func PageUsers(c *gin.Context) {
|
||||
var pageBody UserPageBody
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
um := user.NewUserModel()
|
||||
fields := map[string]interface{}{}
|
||||
if pageBody.Id != "" {
|
||||
fields["user_id"] = pageBody.Id
|
||||
}
|
||||
if pageBody.Name != "" {
|
||||
fields["user_name"] = pageBody.Name
|
||||
}
|
||||
page := &model.Page[user.UserModel]{}
|
||||
page.Covert(pageBody.PageInfo)
|
||||
err = um.Page(page, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, page)
|
||||
}
|
||||
|
||||
func GetUserWorkSpace(c *gin.Context) {
|
||||
userId := c.Query("userId")
|
||||
if userId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
um := &user.UserModel{}
|
||||
um.UserID = userId
|
||||
err := um.Get()
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
if um.AdminRole == 1 {
|
||||
w := workspace.New()
|
||||
result, err := w.GetAll(w, nil, nil)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, result)
|
||||
return
|
||||
}
|
||||
|
||||
namespace := um.Namespace
|
||||
if namespace == "" {
|
||||
controller.Success(c, "")
|
||||
return
|
||||
}
|
||||
ns := strings.Split(namespace, ",")
|
||||
if len(ns) == 0 {
|
||||
controller.Success(c, "")
|
||||
return
|
||||
}
|
||||
|
||||
w := workspace.New()
|
||||
fields := make(map[string]interface{}, 1)
|
||||
fields["id"] = ns
|
||||
result, err := w.GetAll(w, fields, nil)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
type EditUserWorkSpaceBody struct {
|
||||
UserId string `json:"userId"`
|
||||
WorkspaceIds string `json:"workspaceIds"`
|
||||
}
|
||||
|
||||
func EditUserWorkSpace(c *gin.Context) {
|
||||
var body EditUserWorkSpaceBody
|
||||
err := c.ShouldBindJSON(&body)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
if body.UserId == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
um := user.NewUserModel()
|
||||
um.UserID = body.UserId
|
||||
err = um.Get()
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
|
||||
um.Namespace = body.WorkspaceIds
|
||||
err = um.Update([]string{"namespace"})
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
|
||||
controller.Success(c, "")
|
||||
}
|
21
server/internal/controller/v1/demo.go
Normal file
21
server/internal/controller/v1/demo.go
Normal file
@ -0,0 +1,21 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func HelloWorld(c *gin.Context) {
|
||||
//str, ok := c.GetQuery("name")
|
||||
//if !ok {
|
||||
// str = "gin-layout"
|
||||
//}
|
||||
|
||||
//err := service.EventHandler(0, "")
|
||||
//if err != nil {
|
||||
// controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
// return
|
||||
//}
|
||||
|
||||
controller.Success(c, "res")
|
||||
}
|
353
server/internal/controller/v1/deviceinfo.go
Normal file
353
server/internal/controller/v1/deviceinfo.go
Normal file
@ -0,0 +1,353 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/data"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/agent"
|
||||
devc "git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/device"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/message"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/validator"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 每30s的健康检查接口
|
||||
func CheckHeartBeat(c *gin.Context) {
|
||||
device := &devc.DeviceInfo{}
|
||||
err := validator.CheckPostParams(c, device)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
_, err = device.SaveHealth()
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "保存成功!")
|
||||
}
|
||||
|
||||
// 设备基础信息上报
|
||||
func PushDeviceInfo(c *gin.Context) {
|
||||
device := &devc.DeviceInfo{}
|
||||
err := validator.CheckPostParams(c, device)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
_, err = device.SaveBase()
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "保存成功!")
|
||||
}
|
||||
|
||||
type PageBodyDevice struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
Name string `json:"name"`
|
||||
IsNew string `json:"isNew"`
|
||||
}
|
||||
|
||||
// 分页查询设备信息-关联资产属性
|
||||
func PageDevices(c *gin.Context) {
|
||||
var pageBody PageBodyDevice
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
device := &devc.AssetDeviceInfo{}
|
||||
fields := map[string]interface{}{}
|
||||
if pageBody.Name != "" {
|
||||
fields["pr.name"] = pageBody.Name
|
||||
}
|
||||
if pageBody.IsNew != "" {
|
||||
fields["is_new"] = pageBody.IsNew
|
||||
}
|
||||
page := &model.Page[devc.AssetDeviceInfo]{}
|
||||
page.Covert(pageBody.PageInfo)
|
||||
err = device.Page(page, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, page)
|
||||
|
||||
}
|
||||
|
||||
// 统计设备升级数统计
|
||||
func CountDeviceUpgrade(c *gin.Context) {
|
||||
fields := map[string]interface{}{}
|
||||
device := &devc.DeviceInfo{}
|
||||
result, err := device.CountUpgradeNum(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
// 获取设备基本信息
|
||||
func GetDeviceInfo(c *gin.Context) {
|
||||
device := &devc.AssetDeviceInfo{}
|
||||
serialNo := c.Param("serialNo")
|
||||
fields := map[string]interface{}{}
|
||||
fields["serial_no"] = serialNo
|
||||
asset, err := device.Get(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, asset)
|
||||
}
|
||||
|
||||
// 获取设备的组件列表信息
|
||||
func ListDeviceConfigs(c *gin.Context) {
|
||||
serialNo := c.Param("serialNo")
|
||||
device := &devc.AssetDeviceInfo{}
|
||||
fields := map[string]interface{}{}
|
||||
fields["serial_no"] = serialNo
|
||||
_, err := device.Get(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "未找到设备!")
|
||||
return
|
||||
}
|
||||
sub := strings.ReplaceAll(message.TO_AGENT_UNICAST_SUBJECT, "{rid}", serialNo)
|
||||
dat := message.MsgModel{
|
||||
Body: nil,
|
||||
Func: message.FUNC_COMPONENTINFO,
|
||||
Rid: serialNo,
|
||||
Version: "v1",
|
||||
}
|
||||
payload, _ := json.Marshal(dat)
|
||||
msg, err := data.Nc.Request(sub, payload, 6*time.Second)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
res, err := message.UnmarshalMsgRespModel(msg.Data)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "无法解析的消息格式!")
|
||||
return
|
||||
}
|
||||
if res.Code != 200 {
|
||||
controller.FailCode(c, errors.ServerError, err, "小助手消息错误!")
|
||||
return
|
||||
}
|
||||
deStr, err := base64.StdEncoding.DecodeString(fmt.Sprint(res.Data))
|
||||
result := make([]map[string]interface{}, 0)
|
||||
json.Unmarshal(deStr, &result)
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
// 创建设备升级记录
|
||||
func CreateDeviceUpgradeRecord(c *gin.Context) {
|
||||
record := &devc.DeviceUpgradeRecord{}
|
||||
err := validator.CheckPostParams(c, record)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
_, err = record.Create()
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
type PageBodyRecord struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
}
|
||||
|
||||
// 获取设备升级记录
|
||||
func PageDeviceUpgradeRecord(c *gin.Context) {
|
||||
var pageBody PageBodyRecord
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
serialNo := c.Param("serialNo")
|
||||
fields := map[string]interface{}{}
|
||||
fields["serial_no"] = serialNo
|
||||
|
||||
record := &devc.DeviceUpgradeRecord{}
|
||||
page := &model.Page[devc.UpgradeRecord]{}
|
||||
page.Covert(pageBody.PageInfo)
|
||||
err = record.Page(page, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, page)
|
||||
}
|
||||
|
||||
// 创建设备升级规则
|
||||
func CreateDeviceUpgradeRule(c *gin.Context) {
|
||||
rule := &devc.DeviceUpgradeRule{}
|
||||
err := validator.CheckPostParams(c, rule)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
//企业+一体机类型唯一
|
||||
fields := map[string]interface{}{}
|
||||
fields["vendor_id"] = rule.VendorId
|
||||
rules, err := rule.ListAll(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
if len(rules) > 0 && rule.DeviceType == "0" {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "与已有公司规则冲突!")
|
||||
return
|
||||
}
|
||||
for _, r := range rules {
|
||||
if r.DeviceType == rule.DeviceType || r.DeviceType == "0" {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "与已有公司规则冲突!")
|
||||
return
|
||||
}
|
||||
}
|
||||
num, err := rule.Create()
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "创建失败!")
|
||||
return
|
||||
}
|
||||
if num > 0 {
|
||||
go func(ru devc.DeviceUpgradeRule) {
|
||||
rules := make([]devc.DeviceUpgradeRule, 0)
|
||||
rules = append(rules, ru)
|
||||
if err == nil && len(rules) > 0 {
|
||||
_ = service.SendUpgradePlans(rules, "create")
|
||||
}
|
||||
}(*rule)
|
||||
}
|
||||
controller.Success(c, "保存成功!")
|
||||
}
|
||||
|
||||
type PageRule struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
VendorId string `json:"vendorId"`
|
||||
}
|
||||
|
||||
// 获取设备升级规则
|
||||
func PageDeviceUpgradeRule(c *gin.Context) {
|
||||
var pageBody PageRule
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
fields := map[string]interface{}{}
|
||||
if pageBody.VendorId != "" {
|
||||
fields["vendor_id"] = pageBody.VendorId
|
||||
}
|
||||
rule := &devc.DeviceUpgradeRule{}
|
||||
page := &model.Page[devc.DeviceUpgradeRule]{}
|
||||
page.Covert(pageBody.PageInfo)
|
||||
err = rule.Page(page, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, page)
|
||||
}
|
||||
|
||||
type DeleteUpgradeRuleBody struct {
|
||||
Ids []int64 `json:"ids" binding:"required"`
|
||||
}
|
||||
|
||||
// 删除设备升级规则
|
||||
func DeleteDeviceUpgradeRule(c *gin.Context) {
|
||||
rule := &devc.DeviceUpgradeRule{}
|
||||
var deleteBody DeleteUpgradeRuleBody
|
||||
err := c.ShouldBindJSON(&deleteBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
rules, err := rule.GetBatch(deleteBody.Ids)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
var num int64
|
||||
if len(rules) > 0 {
|
||||
num, err = rule.DeleteBatch(deleteBody.Ids)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "删除失败!")
|
||||
return
|
||||
}
|
||||
}
|
||||
if num > 0 {
|
||||
go func(rules []devc.DeviceUpgradeRule) {
|
||||
_ = service.SendUpgradePlans(rules, "delete")
|
||||
}(rules)
|
||||
}
|
||||
controller.Success(c, "删除成功!")
|
||||
}
|
||||
|
||||
// 触发升级命令
|
||||
func DoDeviceUpgrade(c *gin.Context) {
|
||||
serialNo := c.Param("serialNo")
|
||||
device := &devc.AssetDeviceInfo{}
|
||||
fields := map[string]interface{}{}
|
||||
fields["serial_no"] = serialNo
|
||||
d, err := device.Get(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "未找到设备!")
|
||||
return
|
||||
}
|
||||
|
||||
aget := &agent.AgentInfo{}
|
||||
agents, err := aget.ListLastVersion()
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "未查询到最新版本!")
|
||||
return
|
||||
}
|
||||
for _, a := range agents {
|
||||
if strings.ToLower(a.OsType) == strings.ToLower(d.OsType) && strings.ToLower(a.ArchType) == strings.ToLower(d.ArchType) {
|
||||
aget = &a
|
||||
break
|
||||
}
|
||||
}
|
||||
plan, err := service.GetUpgradeCommandNow(aget)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "未找到小助手包!")
|
||||
return
|
||||
}
|
||||
body, _ := json.Marshal(plan)
|
||||
dat := message.MsgModel{
|
||||
Body: body,
|
||||
Func: message.FUNC_UPGRADEIMMEDIATELY,
|
||||
Rid: serialNo,
|
||||
Version: "v1",
|
||||
}
|
||||
payload, _ := json.Marshal(dat)
|
||||
sub := strings.ReplaceAll(message.TO_AGENT_UNICAST_SUBJECT, "{rid}", serialNo)
|
||||
msg, err := data.Nc.Request(sub, payload, 6*time.Second)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误,下发通知失败!")
|
||||
return
|
||||
}
|
||||
res, err := message.UnmarshalMsgRespModel(msg.Data)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "消息格式错误,下发通知失败!")
|
||||
return
|
||||
}
|
||||
if res.Code != 200 {
|
||||
controller.FailCode(c, errors.ServerError, err, "下发通知失败!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "已通知,自动升级!")
|
||||
}
|
124
server/internal/controller/v1/event.go
Normal file
124
server/internal/controller/v1/event.go
Normal file
@ -0,0 +1,124 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/event"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/event_engine"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/validator"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func CreateEvent(c *gin.Context) {
|
||||
event := &event.Event{}
|
||||
err := validator.CheckPostParams(c, event)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
_, err = event.Create()
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "数据库错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
func EditEvent(c *gin.Context) {
|
||||
event := &event.Event{}
|
||||
err := validator.CheckPostParams(c, event)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
fields := map[string]interface{}{}
|
||||
fields["id"] = event.Id
|
||||
_, err = event.Get(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "无法查找到对象!")
|
||||
return
|
||||
}
|
||||
var updateColumns []string
|
||||
_, err = event.Update(updateColumns)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "数据库错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
func GetEventById(c *gin.Context) {
|
||||
event := &event.Event{}
|
||||
eventId := c.Param("eventId")
|
||||
fields := map[string]interface{}{}
|
||||
fields["id"] = eventId
|
||||
mRule, err := event.Get(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, mRule)
|
||||
}
|
||||
|
||||
func GetEventByName(c *gin.Context) {
|
||||
event := &event.Event{}
|
||||
eventName := c.Param("eventName")
|
||||
fields := map[string]interface{}{}
|
||||
fields["event_name"] = eventName
|
||||
result, err := event.Get(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
type EventPageBody struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
EventName string `json:"eventName"`
|
||||
}
|
||||
|
||||
func PageEvents(c *gin.Context) {
|
||||
var pageBody EventPageBody
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
e := &event.Event{}
|
||||
fields := map[string]interface{}{}
|
||||
fields["event_name"] = pageBody.EventName
|
||||
page := &model.Page[event.Event]{}
|
||||
page.Covert(pageBody.PageInfo)
|
||||
err = e.Page(page, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, page)
|
||||
}
|
||||
|
||||
func DeleteEvent(c *gin.Context) {
|
||||
event := &event.Event{}
|
||||
eventId := c.Param("eventId")
|
||||
fields := map[string]interface{}{}
|
||||
fields["id"] = eventId
|
||||
result, err := event.Get(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "事件不存在!")
|
||||
return
|
||||
}
|
||||
result.Delete()
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
func SyncEventFromThreshold(c *gin.Context) {
|
||||
rowsAffected, err := event_engine.BatchSaveEventFromThreshold()
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "同步门限定义至事件定义失败!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, rowsAffected)
|
||||
}
|
166
server/internal/controller/v1/event_record.go
Normal file
166
server/internal/controller/v1/event_record.go
Normal file
@ -0,0 +1,166 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/event"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"github.com/gin-gonic/gin"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GetEventRecordById(c *gin.Context) {
|
||||
er := &event.EventRecordStruct{}
|
||||
eventId := c.Param("eventId")
|
||||
mRule, err := er.GetById(eventId)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, mRule)
|
||||
}
|
||||
|
||||
type EventRecordCondition struct {
|
||||
EventName string `json:"eventName"`
|
||||
ResourceName string `json:"resourceName"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type EventRecordPageBody struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
EventRecordCondition
|
||||
}
|
||||
|
||||
func PageEventRecords(c *gin.Context) {
|
||||
var pageBody EventRecordPageBody
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
er := &event.EventRecordStruct{}
|
||||
fields := map[string]interface{}{}
|
||||
if pageBody.EventName != "" {
|
||||
fields["event_name"] = pageBody.EventName
|
||||
}
|
||||
if pageBody.ResourceName != "" {
|
||||
fields["resource_name"] = pageBody.ResourceName
|
||||
}
|
||||
if pageBody.Status != "" {
|
||||
fields["task_status"] = pageBody.Status
|
||||
}
|
||||
page := &model.Page[event.EventRecordStruct]{}
|
||||
page.Covert(pageBody.PageInfo)
|
||||
err = er.Page(page, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, page)
|
||||
}
|
||||
|
||||
func ExportEventRecords(c *gin.Context) {
|
||||
var condition EventRecordCondition
|
||||
err := c.ShouldBindJSON(&condition)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
er := &event.EventRecordStruct{}
|
||||
fields := map[string]interface{}{}
|
||||
if condition.EventName != "" {
|
||||
fields["event_name"] = condition.EventName
|
||||
}
|
||||
if condition.ResourceName != "" {
|
||||
fields["resource_name"] = condition.ResourceName
|
||||
}
|
||||
if condition.Status != "" {
|
||||
fields["task_status"] = condition.Status
|
||||
}
|
||||
count, err := er.Count(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "服务器错误!")
|
||||
return
|
||||
}
|
||||
|
||||
if count > 1000 {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "数据量过大,请调整查询范围!")
|
||||
return
|
||||
}
|
||||
|
||||
events, err := er.GetEvents(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "服务器错误!")
|
||||
return
|
||||
}
|
||||
|
||||
c.Writer.Header().Set("Content-Disposition", "attachment; filename=events.xlsx")
|
||||
c.Writer.Header().Set("Content-Type", "application/octet-stream")
|
||||
w := csv.NewWriter(c.Writer)
|
||||
c.Writer.Write([]byte("\xEF\xBB\xBF"))
|
||||
w.Write([]string{"事件等级", "事件编号", "事件名称", "资源名称", "资源类型", "所在算力节点", "发生时间", "事件内容", "处理状态"})
|
||||
for _, record := range events {
|
||||
w.Write([]string{GetLevel(record.Level), record.Id, record.EventName, record.ResourceName, record.ResourceType, record.ResourceNode, GetTimeStr(record.EventTime), record.EventInfo, GetStatus(record.TaskStatus)})
|
||||
}
|
||||
|
||||
w.Flush()
|
||||
c.Writer.Flush()
|
||||
}
|
||||
|
||||
func GetLevel(level string) string {
|
||||
if level == "WARN" {
|
||||
return "警告"
|
||||
} else if level == "CRITICAL" {
|
||||
return "严重"
|
||||
} else {
|
||||
return "信息"
|
||||
}
|
||||
}
|
||||
|
||||
func GetStatus(status string) string {
|
||||
if status == "0" {
|
||||
return "初始化"
|
||||
} else if status == "1" {
|
||||
return "成功"
|
||||
} else if status == "2" {
|
||||
return "失败"
|
||||
} else if status == "3" {
|
||||
return "执行中"
|
||||
} else if status == "4" {
|
||||
return "触发失败"
|
||||
} else {
|
||||
return "未处理"
|
||||
}
|
||||
}
|
||||
|
||||
func GetTimeStr(t time.Time) string {
|
||||
return t.Local().Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
func EventRecordsStatistic(c *gin.Context) {
|
||||
var condition EventRecordCondition
|
||||
err := c.ShouldBindJSON(&condition)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
fields := map[string]interface{}{}
|
||||
if condition.EventName != "" {
|
||||
fields["event_name"] = condition.EventName
|
||||
}
|
||||
if condition.ResourceName != "" {
|
||||
fields["resource_name"] = condition.ResourceName
|
||||
}
|
||||
if condition.Status != "" {
|
||||
fields["task_status"] = condition.Status
|
||||
}
|
||||
er := &event.EventRecordStruct{}
|
||||
statistic, err := er.Statistic(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "服务器错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, statistic)
|
||||
}
|
176
server/internal/controller/v1/history_event_record.go
Normal file
176
server/internal/controller/v1/history_event_record.go
Normal file
@ -0,0 +1,176 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/event"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"github.com/gin-gonic/gin"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GetHistoryEventRecordById(c *gin.Context) {
|
||||
her := &event.HistoryEventRecordStruct{}
|
||||
eventId := c.Param("eventId")
|
||||
mRule, err := her.GetById(eventId)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, mRule)
|
||||
}
|
||||
|
||||
type HistoryEventRecordCondition struct {
|
||||
EventName string `json:"eventName"`
|
||||
Level string `json:"level"`
|
||||
ResourceName string `json:"resourceName"`
|
||||
ResourceType string `json:"resourceType"`
|
||||
ResourceNode string `json:"ResourceNode"`
|
||||
StartTime *time.Time `json:"StartTime"`
|
||||
EndTime *time.Time `json:"endTime"`
|
||||
}
|
||||
|
||||
type HistoryEventRecordPageBody struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
HistoryEventRecordCondition
|
||||
}
|
||||
|
||||
func PageHistoryEventRecords(c *gin.Context) {
|
||||
var pageBody HistoryEventRecordPageBody
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
her := &event.HistoryEventRecordStruct{}
|
||||
fields := map[string]interface{}{}
|
||||
if pageBody.EventName != "" {
|
||||
fields["event_name"] = pageBody.EventName
|
||||
}
|
||||
if pageBody.Level != "" {
|
||||
fields["level"] = pageBody.Level
|
||||
}
|
||||
if pageBody.ResourceName != "" {
|
||||
fields["resource_name"] = pageBody.ResourceName
|
||||
}
|
||||
if pageBody.ResourceType != "" {
|
||||
fields["resource_type"] = pageBody.ResourceType
|
||||
}
|
||||
if pageBody.ResourceNode != "" {
|
||||
fields["resource_node"] = pageBody.ResourceNode
|
||||
}
|
||||
if pageBody.StartTime != nil {
|
||||
fields["start_time"] = pageBody.StartTime
|
||||
}
|
||||
if pageBody.EndTime != nil {
|
||||
fields["end_time"] = pageBody.EndTime
|
||||
}
|
||||
page := &model.Page[event.HistoryEventRecordStruct]{}
|
||||
page.Covert(pageBody.PageInfo)
|
||||
err = her.Page(page, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, page)
|
||||
}
|
||||
|
||||
func ExportHistoryEventRecords(c *gin.Context) {
|
||||
var condition HistoryEventRecordCondition
|
||||
err := c.ShouldBindJSON(&condition)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
fields := map[string]interface{}{}
|
||||
if condition.EventName != "" {
|
||||
fields["event_name"] = condition.EventName
|
||||
}
|
||||
if condition.Level != "" {
|
||||
fields["level"] = condition.Level
|
||||
}
|
||||
if condition.ResourceName != "" {
|
||||
fields["resource_name"] = condition.ResourceName
|
||||
}
|
||||
if condition.ResourceType != "" {
|
||||
fields["resource_type"] = condition.ResourceType
|
||||
}
|
||||
if condition.ResourceNode != "" {
|
||||
fields["resource_node"] = condition.ResourceNode
|
||||
}
|
||||
if condition.StartTime != nil {
|
||||
fields["start_time"] = condition.StartTime
|
||||
}
|
||||
if condition.EndTime != nil {
|
||||
fields["end_time"] = condition.EndTime
|
||||
}
|
||||
her := &event.HistoryEventRecordStruct{}
|
||||
count, err := her.Count(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "服务器错误!")
|
||||
return
|
||||
}
|
||||
|
||||
if count > 1000 {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "数据量过大,请调整查询范围!")
|
||||
return
|
||||
}
|
||||
|
||||
events, err := her.GetEvents(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "服务器错误!")
|
||||
return
|
||||
}
|
||||
|
||||
c.Writer.Header().Set("Content-Disposition", "attachment; filename=history_events.xlsx")
|
||||
c.Writer.Header().Set("Content-Type", "application/octet-stream")
|
||||
w := csv.NewWriter(c.Writer)
|
||||
c.Writer.Write([]byte("\xEF\xBB\xBF"))
|
||||
w.Write([]string{"事件等级", "事件编号", "事件名称", "资源名称", "资源类型", "所在算力节点", "发生时间", "事件内容", "处理状态"})
|
||||
for _, record := range events {
|
||||
w.Write([]string{GetLevel(record.Level), record.Id, record.EventName, record.ResourceName, record.ResourceType, record.ResourceNode, GetTimeStr(record.EventTime), record.EventInfo, GetStatus(record.TaskStatus)})
|
||||
}
|
||||
|
||||
w.Flush()
|
||||
c.Writer.Flush()
|
||||
}
|
||||
|
||||
func HistoryEventRecordsStatistic(c *gin.Context) {
|
||||
var condition HistoryEventRecordCondition
|
||||
err := c.ShouldBindJSON(&condition)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
fields := map[string]interface{}{}
|
||||
if condition.EventName != "" {
|
||||
fields["event_name"] = condition.EventName
|
||||
}
|
||||
if condition.Level != "" {
|
||||
fields["level"] = condition.Level
|
||||
}
|
||||
if condition.ResourceName != "" {
|
||||
fields["resource_name"] = condition.ResourceName
|
||||
}
|
||||
if condition.ResourceType != "" {
|
||||
fields["resource_type"] = condition.ResourceType
|
||||
}
|
||||
if condition.ResourceNode != "" {
|
||||
fields["resource_node"] = condition.ResourceNode
|
||||
}
|
||||
if condition.StartTime != nil {
|
||||
fields["start_time"] = condition.StartTime
|
||||
}
|
||||
if condition.EndTime != nil {
|
||||
fields["end_time"] = condition.EndTime
|
||||
}
|
||||
her := &event.HistoryEventRecordStruct{}
|
||||
statistic, err := her.Statistic(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "服务器错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, statistic)
|
||||
}
|
275
server/internal/controller/v1/login.go
Normal file
275
server/internal/controller/v1/login.go
Normal file
@ -0,0 +1,275 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/config"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/middleware"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/user"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/auth"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/validator"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/pkg/log"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/golang/glog"
|
||||
"gorm.io/gorm"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const AUTH_HEADER = "Authorization"
|
||||
|
||||
type UserInfo struct {
|
||||
*user.UserObj
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
func LoginInfo(c *gin.Context) {
|
||||
u, exists := c.Get(middleware.LoginUserKey)
|
||||
if !exists {
|
||||
controller.FailCode(c, errors.AuthorizationError, nil)
|
||||
return
|
||||
}
|
||||
userObj, ok := u.(*user.UserObj)
|
||||
if !ok {
|
||||
controller.FailCode(c, errors.AuthorizationError, nil)
|
||||
return
|
||||
}
|
||||
|
||||
if !config.Config.Auth.Enable {
|
||||
controller.FailCode(c, errors.ServerError, nil, "login is disabled!")
|
||||
return
|
||||
}
|
||||
|
||||
url := config.Config.Auth.Url
|
||||
if url == "" {
|
||||
controller.FailCode(c, errors.ServerError, nil, "login config is not set!")
|
||||
return
|
||||
}
|
||||
|
||||
token := c.Request.Header.Get(AUTH_HEADER)
|
||||
|
||||
var client *http.Client
|
||||
var request *http.Request
|
||||
var resp *http.Response
|
||||
client = &http.Client{Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
}}
|
||||
request, err := http.NewRequest("GET", url+config.Config.Auth.LoginInfo, nil)
|
||||
if err != nil {
|
||||
glog.Errorln("failed to create request", err)
|
||||
controller.FailCode(c, errors.ServerError, err, "failed to create request!")
|
||||
return
|
||||
}
|
||||
request.Header.Add(AUTH_HEADER, token)
|
||||
resp, err = client.Do(request)
|
||||
if err != nil {
|
||||
glog.Errorln("failed to request", err)
|
||||
controller.FailCode(c, errors.ServerError, err, "failed to request!")
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
defer client.CloseIdleConnections()
|
||||
if resp.StatusCode != 200 {
|
||||
glog.Errorln("response error")
|
||||
controller.FailCode(c, errors.ServerError, nil, "response error!")
|
||||
return
|
||||
}
|
||||
|
||||
var respBody map[string]interface{}
|
||||
respStr, _ := io.ReadAll(resp.Body)
|
||||
err = json.Unmarshal(respStr, &respBody)
|
||||
if err != nil {
|
||||
glog.Errorln("failed to decode response", err)
|
||||
controller.FailCode(c, errors.ServerError, err, "failed to decode response!")
|
||||
return
|
||||
}
|
||||
|
||||
data := respBody["data"]
|
||||
if data == nil {
|
||||
meta := respBody["meta"]
|
||||
controller.FailCode(c, errors.ServerError, nil, meta.(map[string]interface{})["message"].(string))
|
||||
return
|
||||
}
|
||||
userMap := data.(map[string]interface{})["user"]
|
||||
mobile := userMap.(map[string]interface{})["mobile"]
|
||||
if mobile != nil {
|
||||
userObj.Mobile = mobile.(string)
|
||||
}
|
||||
provinceId := userMap.(map[string]interface{})["provinceId"]
|
||||
if provinceId != nil {
|
||||
userObj.ProvinceId = provinceId.(string)
|
||||
}
|
||||
userObj.Status = userMap.(map[string]interface{})["status"].(string)
|
||||
userinfo := UserInfo{
|
||||
UserObj: userObj,
|
||||
}
|
||||
controller.Success(c, userinfo)
|
||||
}
|
||||
|
||||
type LoginBody struct {
|
||||
AppCode string `json:"appCode"`
|
||||
Password string `json:"password"`
|
||||
SingleLogin bool `json:"singleLogin"`
|
||||
TextCode string `json:"textCode"`
|
||||
UserName string `json:"username"`
|
||||
Uuid string `json:"uuid"`
|
||||
}
|
||||
|
||||
func Login(c *gin.Context) {
|
||||
if !config.Config.Auth.Enable {
|
||||
controller.FailCode(c, errors.ServerError, nil, "login is disabled!")
|
||||
return
|
||||
}
|
||||
|
||||
url := config.Config.Auth.Url
|
||||
if url == "" {
|
||||
controller.FailCode(c, errors.ServerError, nil, "login config is not set!")
|
||||
return
|
||||
}
|
||||
|
||||
loginBody := LoginBody{}
|
||||
err := validator.CheckPostParams(c, &loginBody)
|
||||
if err != nil || (loginBody.AppCode == "" || loginBody.Password == "" || loginBody.TextCode == "" ||
|
||||
loginBody.UserName == "" || loginBody.Uuid == "") {
|
||||
controller.FailCode(c, errors.ServerError, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
client := &http.Client{Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
}}
|
||||
|
||||
authPath := config.Config.Auth.LoginWithCode
|
||||
reqBody, err := json.Marshal(loginBody)
|
||||
resp, err := client.Post(url+authPath, "application/json", bytes.NewReader(reqBody))
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "服务异常!")
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
defer client.CloseIdleConnections()
|
||||
|
||||
var respBody map[string]interface{}
|
||||
respBytes, _ := io.ReadAll(resp.Body)
|
||||
|
||||
log.Info("auth response:" + string(respBytes))
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
glog.Errorln("response error:" + string(respBytes))
|
||||
controller.FailCode(c, errors.ServerError, nil, "服务异常!")
|
||||
return
|
||||
}
|
||||
|
||||
err = json.Unmarshal(respBytes, &respBody)
|
||||
if err != nil {
|
||||
glog.Errorln("failed to decode response", err.Error())
|
||||
controller.FailCode(c, errors.ServerError, nil, "服务异常!")
|
||||
return
|
||||
}
|
||||
|
||||
data := respBody["data"]
|
||||
if data == nil {
|
||||
meta := respBody["meta"]
|
||||
controller.FailCode(c, errors.ServerError, nil, meta.(map[string]interface{})["message"].(string))
|
||||
return
|
||||
}
|
||||
|
||||
accountMap := data.(map[string]interface{})["account"]
|
||||
userName := accountMap.(map[string]interface{})["loginName"].(string)
|
||||
currentUser := user.NewUserModel()
|
||||
err = currentUser.GetByUserName(userName)
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
glog.Warningln("User does not exist in database registry")
|
||||
currentUser = nil
|
||||
} else {
|
||||
controller.FailCode(c, errors.ServerError, err, "服务异常!")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if currentUser == nil {
|
||||
glog.Infoln("Moving user to database, user: ", loginBody.UserName)
|
||||
spec := user.UserSpec{}
|
||||
spec.UserID = accountMap.(map[string]interface{})["accountId"].(string)
|
||||
spec.UserName = userName
|
||||
userMap := data.(map[string]interface{})["user"]
|
||||
displayName := userMap.(map[string]interface{})["cn"]
|
||||
if displayName != nil {
|
||||
spec.DisplayName = displayName.(string)
|
||||
} else {
|
||||
spec.DisplayName = userName
|
||||
}
|
||||
if userName == "admin" {
|
||||
spec.Role = 1
|
||||
} else {
|
||||
spec.Role = 0
|
||||
}
|
||||
if config.Config.CfnConfig.Enable {
|
||||
spec.Namespace = fmt.Sprintf("DEFAULT,%s", config.Config.CfnConfig.CfnWorkSpaceId)
|
||||
} else {
|
||||
spec.Namespace = "DEFAULT"
|
||||
}
|
||||
|
||||
_, err = user.CreateUser(spec)
|
||||
if err != nil {
|
||||
glog.Errorln("failed to create user, err: " + err.Error())
|
||||
controller.FailCode(c, errors.ServerError, err, "服务异常!")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
detail, err := user.GetUserByUsername(userName)
|
||||
if err != nil || detail == nil {
|
||||
glog.Errorln("failed to get user, err: " + err.Error())
|
||||
controller.FailCode(c, errors.ServerError, err, "服务异常!")
|
||||
return
|
||||
}
|
||||
|
||||
userMap := data.(map[string]interface{})["user"]
|
||||
mobile := userMap.(map[string]interface{})["mobile"]
|
||||
if mobile != nil {
|
||||
detail.Mobile = mobile.(string)
|
||||
}
|
||||
provinceId := userMap.(map[string]interface{})["provinceId"]
|
||||
if provinceId != nil {
|
||||
detail.ProvinceId = provinceId.(string)
|
||||
}
|
||||
detail.Status = userMap.(map[string]interface{})["status"].(string)
|
||||
tokenMap := data.(map[string]interface{})["token"]
|
||||
authToken := tokenMap.(map[string]interface{})["accessToken"].(string)
|
||||
|
||||
go func() {
|
||||
userModel := user.NewUserModel()
|
||||
userModel.UserID = detail.UserID
|
||||
userModel.LastLoginTime = time.Now()
|
||||
userModel.LoginFrequency = detail.LoginFrequency + 1
|
||||
_, err = userModel.UpdateLastLoginTime()
|
||||
if err != nil {
|
||||
glog.Errorln("Failed to update last_login_time", err)
|
||||
}
|
||||
}()
|
||||
|
||||
token, err := auth.Authorize(authToken, detail)
|
||||
if err != nil || token == "" {
|
||||
glog.Errorln("Failed to get token", err)
|
||||
controller.FailCode(c, errors.ServerError, err, "服务异常!")
|
||||
return
|
||||
}
|
||||
|
||||
userinfo := UserInfo{
|
||||
UserObj: detail,
|
||||
Token: token,
|
||||
}
|
||||
|
||||
controller.Success(c, userinfo)
|
||||
}
|
41
server/internal/controller/v1/logs.go
Normal file
41
server/internal/controller/v1/logs.go
Normal file
@ -0,0 +1,41 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
devc "git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/device"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/message"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// 获取设备运行日志
|
||||
func GetDeviceLogs(c *gin.Context) {
|
||||
device := &devc.AssetDeviceInfo{}
|
||||
serialNo := c.Param("serialNo")
|
||||
comType := c.Param("comType")
|
||||
fields := map[string]interface{}{}
|
||||
fields["serial_no"] = serialNo
|
||||
_, err := device.Get(fields)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
loglines := []string{}
|
||||
switch comType {
|
||||
case "agent":
|
||||
loglines, err = service.GetDeviceLogs(message.FUNC_AGENTLOG, serialNo, 100)
|
||||
break
|
||||
case "syslog":
|
||||
break
|
||||
case "telegraf":
|
||||
loglines, err = service.GetDeviceLogs(message.FUNC_TELEGRAFLOG, serialNo, 100)
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
}
|
||||
controller.Success(c, loglines)
|
||||
}
|
467
server/internal/controller/v1/metric.go
Normal file
467
server/internal/controller/v1/metric.go
Normal file
@ -0,0 +1,467 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/data"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/device"
|
||||
mc "git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/metric"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/pkg/log"
|
||||
"github.com/gin-gonic/gin"
|
||||
v1 "github.com/prometheus/client_golang/api/prometheus/v1"
|
||||
"github.com/prometheus/common/model"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type QueryBody struct {
|
||||
Rids string `json:"rids"`
|
||||
OrgId string `json:"orgId"`
|
||||
AssetType string `json:"assetType"`
|
||||
RuleNos string `json:"ruleNo"`
|
||||
Start string `json:"start"`
|
||||
End string `json:"end"`
|
||||
Step time.Duration `json:"step"`
|
||||
}
|
||||
|
||||
type Metric struct {
|
||||
RuleNo string `json:"ruleNo"`
|
||||
RuleName string `json:"ruleName"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
type Pair struct {
|
||||
Time model.Time `json:"time"`
|
||||
Value interface{} `json:"value"`
|
||||
}
|
||||
|
||||
func QueryMetric(c *gin.Context) {
|
||||
body := request.GetBody(c)
|
||||
var b QueryBody
|
||||
err := json.Unmarshal(body, &b)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数(body)是否符合要求!")
|
||||
return
|
||||
}
|
||||
|
||||
var end time.Time
|
||||
if b.End != "" {
|
||||
end, err = time.Parse(time.RFC3339, b.End)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "invalid end")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
end = time.Now()
|
||||
}
|
||||
|
||||
var start time.Time
|
||||
if b.Start != "" {
|
||||
start, err = time.Parse(time.RFC3339, b.Start)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "invalid start")
|
||||
return
|
||||
}
|
||||
} else if b.End == "" {
|
||||
start = end
|
||||
}
|
||||
|
||||
if end.Before(start) {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "invalid start and end")
|
||||
return
|
||||
}
|
||||
|
||||
if b.Step == 0 {
|
||||
duration := end.Sub(start)
|
||||
durationSeconds := duration.Seconds()
|
||||
b.Step = time.Duration(durationSeconds/6) * time.Second
|
||||
if b.Step == 0 {
|
||||
b.Step = time.Second
|
||||
}
|
||||
}
|
||||
|
||||
ruleNos := strings.Split(b.RuleNos, ",")
|
||||
if len(ruleNos) == 0 {
|
||||
controller.Success(c, nil)
|
||||
return
|
||||
}
|
||||
|
||||
rids := strings.Split(b.Rids, ",")
|
||||
if len(rids) == 0 {
|
||||
controller.Success(c, nil)
|
||||
return
|
||||
}
|
||||
|
||||
if data.V1api == nil {
|
||||
log.Info("prometheus client is nil")
|
||||
controller.Success(c, nil)
|
||||
return
|
||||
}
|
||||
|
||||
device := &device.DeviceInfo{}
|
||||
devices, err := device.GetBySerialNos(rids)
|
||||
if len(devices) == 0 {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "rids are not exist")
|
||||
return
|
||||
}
|
||||
|
||||
osType := make(map[string]string, len(devices))
|
||||
for _, info := range devices {
|
||||
osType[info.SerialNo] = info.OsType
|
||||
}
|
||||
|
||||
rule := mc.MetricsRule{}
|
||||
rules, err := rule.GetByRuleNo(ruleNos)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "数据库错误!")
|
||||
return
|
||||
}
|
||||
|
||||
if len(rules) == 0 {
|
||||
controller.Success(c, nil)
|
||||
return
|
||||
}
|
||||
|
||||
result := make(map[string][]Metric, len(rids))
|
||||
for _, rid := range rids {
|
||||
var isWindows bool
|
||||
if osType[rid] == "" || strings.ToLower(osType[rid]) == "windows" {
|
||||
isWindows = true
|
||||
} else {
|
||||
isWindows = false
|
||||
}
|
||||
result[rid] = []Metric{}
|
||||
for _, metricsRule := range rules {
|
||||
var ruleQl string
|
||||
if isWindows {
|
||||
ruleQl = metricsRule.RuleQlWindows
|
||||
} else {
|
||||
ruleQl = metricsRule.RuleQl
|
||||
}
|
||||
promQl := strings.ReplaceAll(ruleQl, "$rid", rid)
|
||||
queryRange, _, err := data.V1api.QueryRange(context.TODO(), promQl, v1.Range{
|
||||
Start: start,
|
||||
End: end,
|
||||
Step: b.Step,
|
||||
})
|
||||
if err != nil {
|
||||
log.Info("failed to query range, err: ", err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
var data interface{}
|
||||
resultType := queryRange.Type()
|
||||
switch resultType {
|
||||
case model.ValScalar:
|
||||
scalar := queryRange.(*model.Scalar)
|
||||
data = []Pair{
|
||||
{
|
||||
scalar.Timestamp,
|
||||
scalar.Value,
|
||||
},
|
||||
}
|
||||
case model.ValMatrix:
|
||||
matrix := queryRange.(model.Matrix)
|
||||
size := len(matrix)
|
||||
if size > 1 {
|
||||
temp := make(map[string][]Pair)
|
||||
for _, stream := range matrix {
|
||||
var pairs []Pair
|
||||
for _, value := range stream.Values {
|
||||
pairs = append(pairs, Pair{
|
||||
value.Timestamp,
|
||||
value.Value,
|
||||
})
|
||||
}
|
||||
key, _ := json.Marshal(stream.Metric)
|
||||
temp[string(key)] = pairs
|
||||
}
|
||||
data = temp
|
||||
} else if size > 0 {
|
||||
var pairs []Pair
|
||||
values := matrix[0].Values
|
||||
for i := range values {
|
||||
pairs = append(pairs, Pair{
|
||||
values[i].Timestamp,
|
||||
values[i].Value,
|
||||
})
|
||||
}
|
||||
data = pairs
|
||||
}
|
||||
case model.ValString:
|
||||
str := queryRange.(*model.String)
|
||||
data = []Pair{
|
||||
{
|
||||
str.Timestamp,
|
||||
str.Value,
|
||||
},
|
||||
}
|
||||
case model.ValVector:
|
||||
vector := queryRange.(model.Vector)
|
||||
size := len(vector)
|
||||
if size > 1 {
|
||||
temp := make(map[string][]Pair)
|
||||
for _, sample := range vector {
|
||||
key, _ := json.Marshal(sample.Metric.String())
|
||||
temp[string(key)] = []Pair{{
|
||||
sample.Timestamp,
|
||||
sample.Value},
|
||||
}
|
||||
}
|
||||
data = temp
|
||||
} else if size > 0 {
|
||||
data = []Pair{
|
||||
{
|
||||
vector[0].Timestamp,
|
||||
vector[0].Value,
|
||||
},
|
||||
}
|
||||
}
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
result[rid] = append(result[rid], Metric{
|
||||
metricsRule.RuleNo,
|
||||
metricsRule.RuleName,
|
||||
data,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
type ProcessMetricQueryBody struct {
|
||||
Rid string `json:"rid"`
|
||||
PName string `json:"pName"`
|
||||
Start string `json:"start"`
|
||||
End string `json:"end"`
|
||||
Step time.Duration `json:"step"`
|
||||
}
|
||||
|
||||
func QueryProcessMetric(c *gin.Context) {
|
||||
body := request.GetBody(c)
|
||||
var b ProcessMetricQueryBody
|
||||
err := json.Unmarshal(body, &b)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数(body)是否符合要求!")
|
||||
return
|
||||
}
|
||||
|
||||
if b.Rid == "" || b.PName == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数(body)是否符合要求!")
|
||||
}
|
||||
|
||||
var end time.Time
|
||||
if b.End != "" {
|
||||
end, err = time.Parse(time.RFC3339, b.End)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "invalid end")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
end = time.Now()
|
||||
}
|
||||
|
||||
var start time.Time
|
||||
if b.Start != "" {
|
||||
start, err = time.Parse(time.RFC3339, b.Start)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "invalid start")
|
||||
return
|
||||
}
|
||||
} else if b.End == "" {
|
||||
start = end
|
||||
}
|
||||
|
||||
if end.Before(start) {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "invalid start and end")
|
||||
return
|
||||
}
|
||||
|
||||
if b.Step == 0 {
|
||||
duration := end.Sub(start)
|
||||
durationSeconds := duration.Seconds()
|
||||
b.Step = time.Duration(durationSeconds/6) * time.Second
|
||||
if b.Step == 0 {
|
||||
b.Step = time.Second
|
||||
}
|
||||
}
|
||||
|
||||
d := &device.DeviceInfo{}
|
||||
r, err := d.GetBySerialNo(b.Rid)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "rid are not exist")
|
||||
return
|
||||
}
|
||||
|
||||
isWindows := strings.ToLower(r.OsType) == "windows"
|
||||
promQLs := make(map[string]string)
|
||||
if isWindows {
|
||||
promQLs["read"] = fmt.Sprintf(
|
||||
`rate(windows_process_io_bytes_total{rid="%s", process="%s", mode="read"}[5m])`, b.Rid, b.PName)
|
||||
promQLs["write"] = fmt.Sprintf(
|
||||
`rate(windows_process_io_bytes_total{rid="%s", process="%s", mode="write"}[5m])`, b.Rid, b.PName)
|
||||
promQLs["cpu"] = fmt.Sprintf(
|
||||
`sum(rate(windows_process_cpu_time_total{rid="%s", process="%s"}[5m]))`, b.Rid, b.PName)
|
||||
promQLs["memory"] = fmt.Sprintf(
|
||||
`sum(windows_process_page_file_bytes{rid="%s", process="%s"})`, b.Rid, b.PName)
|
||||
} else {
|
||||
promQLs["read"] = fmt.Sprintf(
|
||||
`rate(namedprocess_namegroup_read_bytes_total{rid="%s",groupname="%s"}[5m])`, b.Rid, b.PName)
|
||||
promQLs["write"] = fmt.Sprintf(
|
||||
`rate(namedprocess_namegroup_write_bytes_total{rid="%s",groupname="%s"}[5m])`, b.Rid, b.PName)
|
||||
promQLs["cpu"] = fmt.Sprintf(
|
||||
`sum(rate(namedprocess_namegroup_cpu_seconds_total{rid="%s",groupname="%s"}[5m]))`, b.Rid, b.PName)
|
||||
promQLs["memory"] = fmt.Sprintf(
|
||||
`sum(namedprocess_namegroup_memory_bytes{rid="%s",groupname="%s"})`, b.Rid, b.PName)
|
||||
}
|
||||
|
||||
result := make(map[string][]Pair)
|
||||
for key, promQL := range promQLs {
|
||||
queryRange, _, err := data.V1api.QueryRange(context.TODO(), promQL, v1.Range{
|
||||
Start: start,
|
||||
End: end,
|
||||
Step: b.Step,
|
||||
})
|
||||
if err != nil {
|
||||
log.Info("failed to query range, err: ", err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
var pairs []Pair
|
||||
resultType := queryRange.Type()
|
||||
switch resultType {
|
||||
case model.ValScalar:
|
||||
scalar := queryRange.(*model.Scalar)
|
||||
pairs = append(pairs, Pair{
|
||||
scalar.Timestamp,
|
||||
scalar.Value,
|
||||
})
|
||||
case model.ValMatrix:
|
||||
matrix := queryRange.(model.Matrix)
|
||||
if len(matrix) == 0 {
|
||||
continue
|
||||
}
|
||||
values := matrix[0].Values
|
||||
for i := range values {
|
||||
pairs = append(pairs, Pair{
|
||||
values[i].Timestamp,
|
||||
values[i].Value,
|
||||
})
|
||||
}
|
||||
case model.ValString:
|
||||
str := queryRange.(*model.String)
|
||||
pairs = append(pairs, Pair{
|
||||
str.Timestamp,
|
||||
str.Value,
|
||||
})
|
||||
case model.ValVector:
|
||||
vector := queryRange.(model.Vector)
|
||||
for i := range vector {
|
||||
pairs = append(pairs, Pair{
|
||||
vector[i].Timestamp,
|
||||
vector[i].Value,
|
||||
})
|
||||
}
|
||||
default:
|
||||
continue
|
||||
}
|
||||
result[key] = pairs
|
||||
}
|
||||
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
func QueryProcessListMetric(c *gin.Context) {
|
||||
rid := c.Param("rid")
|
||||
|
||||
d := &device.DeviceInfo{}
|
||||
r, err := d.GetBySerialNo(rid)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "rid are not exist")
|
||||
return
|
||||
}
|
||||
|
||||
isWindows := strings.ToLower(r.OsType) == "windows"
|
||||
promQLs := make(map[string]string)
|
||||
if isWindows {
|
||||
promQLs["pName"] = fmt.Sprintf(
|
||||
`sum(windows_process_start_time{rid="%s"}) by (process)`, rid)
|
||||
promQLs["state"] = fmt.Sprintf(
|
||||
`sum(windows_process_threads{rid="%s"}) by (process) > 0`, rid)
|
||||
promQLs["cpu"] = fmt.Sprintf(
|
||||
`sum(rate(windows_process_cpu_time_total{rid="%s"}[5m])) by (process)`, rid)
|
||||
promQLs["memory"] = fmt.Sprintf(
|
||||
`sum(windows_process_page_file_bytes{rid="%s"}) by (process)`, rid)
|
||||
promQLs["diskIO"] = fmt.Sprintf(
|
||||
`sum(rate(windows_process_io_bytes_total{rid="%s", mode="read"}[5m])) by (process)`, rid)
|
||||
} else {
|
||||
promQLs["pName"] = fmt.Sprintf(
|
||||
`namedprocess_namegroup_num_procs{rid="%s"} == 1`, rid)
|
||||
promQLs["state"] = fmt.Sprintf(
|
||||
`sum(namedprocess_namegroup_states{rid="%s", state=~"Other|Zombie"}) by (groupname) == 0`, rid)
|
||||
promQLs["cpu"] = fmt.Sprintf(
|
||||
`sum(rate(namedprocess_namegroup_cpu_seconds_total{rid="%s"}[5m])) by (groupname)`, rid)
|
||||
promQLs["memory"] = fmt.Sprintf(
|
||||
`sum(namedprocess_namegroup_memory_bytes{rid="%s"}) by (groupname)`, rid)
|
||||
promQLs["diskIO"] = fmt.Sprintf(
|
||||
`rate(namedprocess_namegroup_read_bytes_total{rid="%s"}[5m]) + rate(namedprocess_namegroup_write_bytes_total{rid="%s"}[5m])`, rid, rid)
|
||||
}
|
||||
|
||||
temp := make(map[string][]*model.Sample)
|
||||
time := time.Now()
|
||||
for key, promQL := range promQLs {
|
||||
queryRange, _, err := data.V1api.Query(context.TODO(), promQL, time)
|
||||
if err != nil {
|
||||
log.Info("failed to query range, err: ", err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
if queryRange.Type() == model.ValVector {
|
||||
temp[key] = queryRange.(model.Vector)
|
||||
}
|
||||
}
|
||||
|
||||
samples := temp["pName"]
|
||||
result := make(map[string]map[string]interface{}, len(samples))
|
||||
var processName model.LabelName
|
||||
if isWindows {
|
||||
processName = "process"
|
||||
} else {
|
||||
processName = "groupname"
|
||||
}
|
||||
for _, sample := range samples {
|
||||
|
||||
result[string(sample.Metric[processName])] = make(map[string]interface{}, 3)
|
||||
}
|
||||
|
||||
delete(temp, "pName")
|
||||
|
||||
samples = temp["state"]
|
||||
for _, sample := range samples {
|
||||
pName := string(sample.Metric[processName])
|
||||
if _, ok := result[pName]; ok {
|
||||
result[pName]["status"] = true
|
||||
}
|
||||
}
|
||||
|
||||
delete(temp, "state")
|
||||
|
||||
for key, value := range temp {
|
||||
for _, sample := range value {
|
||||
pName := string(sample.Metric[processName])
|
||||
if _, ok := result[pName]; !ok {
|
||||
continue
|
||||
}
|
||||
result[pName][key] = sample.Value
|
||||
}
|
||||
}
|
||||
|
||||
controller.Success(c, result)
|
||||
}
|
176
server/internal/controller/v1/metricrule.go
Normal file
176
server/internal/controller/v1/metricrule.go
Normal file
@ -0,0 +1,176 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
mc "git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/metric"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/validator"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// 创建指标规则
|
||||
func CreateMetricRule(c *gin.Context) {
|
||||
rule := &mc.MetricsRule{}
|
||||
err := validator.CheckPostParams(c, rule)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
queryNo := map[string]interface{}{
|
||||
"rule_no": rule.RuleNo,
|
||||
}
|
||||
r, _ := rule.Get(queryNo)
|
||||
if r.RuleNo != "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "编号重复!")
|
||||
return
|
||||
}
|
||||
|
||||
if rule.RuleKey != "" {
|
||||
queryKey := map[string]interface{}{
|
||||
"rule_key": rule.RuleKey,
|
||||
}
|
||||
rr, _ := rule.Get(queryKey)
|
||||
if rr.RuleKey != "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "KEY值重复!")
|
||||
return
|
||||
}
|
||||
}
|
||||
_, err = rule.Create()
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "数据库错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
// 编辑指标规则
|
||||
func EditMetricRule(c *gin.Context) {
|
||||
rule := &mc.MetricsRule{}
|
||||
err := validator.CheckPostParams(c, rule)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
fields := map[string]interface{}{}
|
||||
fields["id"] = rule.Id
|
||||
oldRule, err := rule.Get(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "无法查找到对象!")
|
||||
return
|
||||
}
|
||||
if rule.RuleNo != oldRule.RuleNo {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "编号不允许修改!")
|
||||
return
|
||||
}
|
||||
|
||||
if rule.RuleKey != "" {
|
||||
queryKey := map[string]interface{}{
|
||||
"rule_key": rule.RuleKey,
|
||||
}
|
||||
rr, _ := rule.Get(queryKey)
|
||||
if rr.RuleKey != "" && rr.RuleKey != oldRule.RuleKey {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "KEY值重复!")
|
||||
return
|
||||
}
|
||||
}
|
||||
updateColumns := []string{}
|
||||
_, err = rule.Update(updateColumns)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "数据库错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
// 根据编号获取规则
|
||||
func GetMetricRule(c *gin.Context) {
|
||||
rule := &mc.MetricsRule{}
|
||||
ruleNo := c.Param("ruleNo")
|
||||
fields := map[string]interface{}{}
|
||||
fields["rule_no"] = ruleNo
|
||||
mRule, err := rule.Get(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, mRule)
|
||||
}
|
||||
|
||||
// 根据扩展key获取规则
|
||||
func GetMetricRuleByKey(c *gin.Context) {
|
||||
rule := &mc.MetricsRule{}
|
||||
ruleKey := c.Param("ruleKey")
|
||||
fields := map[string]interface{}{}
|
||||
fields["rule_key"] = ruleKey
|
||||
mRule, err := rule.Get(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, mRule)
|
||||
}
|
||||
|
||||
type PageBody struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
Keyword string `json:"keyword"`
|
||||
}
|
||||
|
||||
// 根据扩展key获取规则
|
||||
func PageMetrics(c *gin.Context) {
|
||||
var pageBody PageBody
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
rule := &mc.MetricsRule{}
|
||||
fields := map[string]interface{}{}
|
||||
fields["keyword"] = pageBody.Keyword
|
||||
page := &model.Page[mc.MetricsRule]{}
|
||||
page.Covert(pageBody.PageInfo)
|
||||
err = rule.Page(page, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, page)
|
||||
}
|
||||
|
||||
// 删除指标规则
|
||||
func DeleteMetric(c *gin.Context) {
|
||||
rule := &mc.MetricsRule{}
|
||||
ruleNo := c.Param("ruleNo")
|
||||
fields := map[string]interface{}{}
|
||||
fields["rule_no"] = ruleNo
|
||||
mRule, err := rule.Get(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
mRule.Delete()
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
type DeleteBody struct {
|
||||
RuleNos []string `json:"ruleNos" binding:"required"`
|
||||
}
|
||||
|
||||
// 批量删除指标规则
|
||||
func DeleteBatchMetric(c *gin.Context) {
|
||||
var deleteBody DeleteBody
|
||||
err := c.ShouldBindJSON(&deleteBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
rule := &mc.MetricsRule{}
|
||||
_, err = rule.DeleteBatch(deleteBody.RuleNos)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "删除失败!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "删除成功!")
|
||||
}
|
91
server/internal/controller/v1/minio.go
Normal file
91
server/internal/controller/v1/minio.go
Normal file
@ -0,0 +1,91 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func init() {
|
||||
_ = os.Mkdir("/tmp", os.FileMode(0777))
|
||||
}
|
||||
|
||||
func GetPresignedUrl(c *gin.Context) {
|
||||
filename := c.Param("filename")
|
||||
if filename == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
url, err := service.GetPresignedUrl("cpn", filename, 10000)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
controller.FailCode(c, errors.ServerError, err, "minio connection fail!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, url)
|
||||
}
|
||||
|
||||
func PostPresignedUrl(c *gin.Context) {
|
||||
filename := c.Param("filename")
|
||||
if filename == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
formData, err := service.PostPresignedUrl("cpn", filename, 10000)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
controller.FailCode(c, errors.ServerError, err, "minio connection fail!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, formData)
|
||||
}
|
||||
|
||||
func PutPresignedUrl(c *gin.Context) {
|
||||
filename := c.Param("filename")
|
||||
if filename == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
data, err := service.PutPresignedUrl("cpn", filename, 10000)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
controller.FailCode(c, errors.ServerError, err, "minio connection fail!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, data)
|
||||
}
|
||||
|
||||
func UploadFile(c *gin.Context) {
|
||||
_, headers, err := c.Request.FormFile("file")
|
||||
if err != nil {
|
||||
log.Printf("Error when try to get file: %v", err)
|
||||
}
|
||||
filename := c.Request.PostForm.Get("filename")
|
||||
if filename == "" {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
//headers.Size 获取文件大小
|
||||
if headers.Size > 1024*1024*200 {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "文件大小不能超过200M")
|
||||
return
|
||||
}
|
||||
err = c.SaveUploadedFile(headers, "/tmp/"+headers.Filename)
|
||||
if err != nil {
|
||||
log.Printf("Error upload file: %v", err)
|
||||
controller.FailCode(c, errors.ServerError, err, "上传文件失败!")
|
||||
return
|
||||
}
|
||||
err = service.UploadFile("cpn", filename, "/tmp/"+headers.Filename)
|
||||
if err != nil {
|
||||
log.Printf("Error upload minio file: %v", err)
|
||||
controller.FailCode(c, errors.ServerError, err, "上传文件失败!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "")
|
||||
}
|
549
server/internal/controller/v1/schedule.go
Normal file
549
server/internal/controller/v1/schedule.go
Normal file
@ -0,0 +1,549 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/middleware"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/event"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/id"
|
||||
sc "git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/schedule"
|
||||
tk "git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/schedule"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/user"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
excel "git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/utils"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/schedule_engine"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/validator"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/pkg/log"
|
||||
"github.com/gin-gonic/gin"
|
||||
"time"
|
||||
)
|
||||
|
||||
func CreateSchedRule(c *gin.Context) {
|
||||
rule := &sc.SchedRule{}
|
||||
err := validator.CheckPostParams(c, rule)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
if ur, bl := c.Get(middleware.LoginUserKey); bl {
|
||||
if u, b := ur.(*user.User); b {
|
||||
rule.CreateBy = u.Name
|
||||
}
|
||||
}
|
||||
if _, err = rule.Create(); err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
// 编辑调度规则
|
||||
func EditSchedRule(c *gin.Context) {
|
||||
rule := &sc.SchedRule{}
|
||||
err := validator.CheckPostParams(c, rule)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
fields := map[string]interface{}{}
|
||||
fields["id"] = rule.Id
|
||||
_, err = rule.Get(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "无法查找到对象!")
|
||||
return
|
||||
}
|
||||
updateColumns := []string{}
|
||||
_, err = rule.Update(updateColumns)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "数据库错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
// 根据ID获取规则
|
||||
func GetSchedRule(c *gin.Context) {
|
||||
rule := &sc.SchedRule{}
|
||||
id := c.Param("id")
|
||||
fields := map[string]interface{}{}
|
||||
fields["id"] = id
|
||||
result, err := rule.Get(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
func StatisticSchedRule(c *gin.Context) {
|
||||
rule := &sc.SchedRule{}
|
||||
total, err := rule.Count()
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "数据库异常!")
|
||||
return
|
||||
}
|
||||
now := time.Now()
|
||||
lastYear := now.AddDate(-1, 1, 0)
|
||||
startDate := time.Date(lastYear.Year(), lastYear.Month(), 1, 0, 0, 0, 0, time.Local)
|
||||
tmp, err := rule.CountByMonth(startDate)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "数据库异常!")
|
||||
return
|
||||
}
|
||||
group := make(map[string]interface{})
|
||||
for _, item := range tmp {
|
||||
dateStr := item["date"].(string)
|
||||
group[dateStr] = item["count"]
|
||||
}
|
||||
for startDate.Before(now) {
|
||||
dateStr := startDate.Format("2006-01")
|
||||
if _, exist := group[dateStr]; !exist {
|
||||
group[dateStr] = 0
|
||||
}
|
||||
startDate = startDate.AddDate(0, 1, 0)
|
||||
}
|
||||
result := map[string]interface{}{
|
||||
"total": total,
|
||||
"group": group,
|
||||
}
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
type PageBodySchedRule struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
Keyword string `json:"keyword"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
// 分页获取规则
|
||||
func PageSchedRules(c *gin.Context) {
|
||||
var pageBody PageBodySchedRule
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
rule := &sc.SchedRule{}
|
||||
fields := map[string]interface{}{}
|
||||
fields["keyword"] = pageBody.Keyword
|
||||
if pageBody.Status != "" {
|
||||
fields["rule_status"] = pageBody.Status
|
||||
}
|
||||
page := &model.Page[sc.SchedRule]{}
|
||||
page.Covert(pageBody.PageInfo)
|
||||
err = rule.Page(page, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, page)
|
||||
}
|
||||
|
||||
type DeleteBodySchedRule struct {
|
||||
Ids []int64 `json:"ids" binding:"required"`
|
||||
}
|
||||
|
||||
// 批量删除规则
|
||||
func DeleteSchedRules(c *gin.Context) {
|
||||
var deleteBody DeleteBodySchedRule
|
||||
err := c.ShouldBindJSON(&deleteBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
rule := &sc.SchedRule{}
|
||||
_, err = rule.DeleteBatch(deleteBody.Ids)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "删除失败!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, "删除成功!")
|
||||
}
|
||||
|
||||
// 停用启用操作
|
||||
func DoSchedRule(c *gin.Context) {
|
||||
rule := &sc.SchedRule{}
|
||||
id := c.Param("id")
|
||||
option := c.Param("option")
|
||||
fields := map[string]interface{}{}
|
||||
fields["id"] = id
|
||||
result, err := rule.Get(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
if option == "0" {
|
||||
//todo 开启任务
|
||||
} else if option == "1" {
|
||||
//todo 停止任务
|
||||
} else {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
result.RuleStatus = option
|
||||
result.Update(nil)
|
||||
controller.Success(c, "执行成功!")
|
||||
}
|
||||
|
||||
type PageBodySchedTask struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
ListBodySchedTask
|
||||
}
|
||||
|
||||
type ListBodySchedTask struct {
|
||||
TaskName string `json:"taskName"`
|
||||
TaskStatus string `json:"taskStatus"`
|
||||
StartTime *time.Time `json:"startTime"`
|
||||
EndTime *time.Time `json:"endTime"`
|
||||
}
|
||||
|
||||
// 分页获取规则
|
||||
func PageSchedTasks(c *gin.Context) {
|
||||
var pageBody PageBodySchedTask
|
||||
err := c.ShouldBindJSON(&pageBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
task := &sc.SchedTask{}
|
||||
fields := map[string]interface{}{}
|
||||
fields["task_name"] = pageBody.TaskName
|
||||
if pageBody.TaskStatus != "" {
|
||||
fields["task_status"] = pageBody.TaskStatus
|
||||
}
|
||||
|
||||
if pageBody.StartTime == nil {
|
||||
fields["start_time"] = time.Now().Add(-30 * 24 * time.Hour)
|
||||
} else {
|
||||
fields["start_time"] = pageBody.StartTime
|
||||
}
|
||||
|
||||
if pageBody.EndTime == nil {
|
||||
fields["end_time"] = time.Now()
|
||||
} else {
|
||||
fields["end_time"] = pageBody.EndTime
|
||||
}
|
||||
|
||||
page := &model.Page[sc.SchedTask]{}
|
||||
page.Covert(pageBody.PageInfo)
|
||||
err = task.Page(page, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, page)
|
||||
}
|
||||
|
||||
// 分页获取规则
|
||||
func ExportSchedTasks(c *gin.Context) {
|
||||
var listBody ListBodySchedTask
|
||||
err := c.ShouldBindJSON(&listBody)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
task := &sc.SchedTask{}
|
||||
fields := map[string]interface{}{}
|
||||
fields["task_name"] = listBody.TaskName
|
||||
if listBody.TaskStatus != "" {
|
||||
fields["task_status"] = listBody.TaskStatus
|
||||
}
|
||||
fields["start_time"] = listBody.StartTime
|
||||
fields["end_time"] = listBody.EndTime
|
||||
tasks, err := task.ListAll(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "未找到记录!")
|
||||
return
|
||||
}
|
||||
rows := [][]interface{}{}
|
||||
for _, t := range tasks {
|
||||
row := []interface{}{
|
||||
t.TaskName, t.Id, t.StartTime, t.EndTime, tk.TriggerTypeMap[t.TriggerType], "", tk.TaskStatusMap[t.TaskStatus],
|
||||
}
|
||||
rows = append(rows, row)
|
||||
}
|
||||
header := []string{"任务名称", "任务编号", "开始时间", "结束时间", "触发方式", "触发事件", "状态"}
|
||||
f, err := excel.ExportExcel("调度任务", header, rows)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "生成excel文件失败!")
|
||||
return
|
||||
}
|
||||
f.SetColWidth("调度任务", "A", "A", 40)
|
||||
f.SetColWidth("调度任务", "C", "D", 15)
|
||||
f.SetColWidth("调度任务", "F", "F", 40)
|
||||
defer func() {
|
||||
if err := f.Close(); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}()
|
||||
if err := f.SaveAs("/tmp/task.xlsx"); err != nil {
|
||||
fmt.Println(err)
|
||||
controller.FailCode(c, errors.ServerError, err, "生成下载文件失败!")
|
||||
return
|
||||
}
|
||||
c.Header("Content-Type", "application/octet-stream")
|
||||
c.Header("Content-Disposition", "attachment; filename=task.xlsx")
|
||||
c.Header("Content-Transfer-Encoding", "binary")
|
||||
c.File("/tmp/task.xlsx")
|
||||
return
|
||||
}
|
||||
|
||||
// 根据ID获取调度任务
|
||||
func GetSchedTask(c *gin.Context) {
|
||||
task := &sc.SchedTask{}
|
||||
id := c.Param("id")
|
||||
fields := map[string]interface{}{}
|
||||
fields["id"] = id
|
||||
result, err := task.Get(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
// 根据EventId获取调度任务
|
||||
func GetSchedTaskByEvent(c *gin.Context) {
|
||||
task := &sc.SchedTask{}
|
||||
eventId := c.Param("eventId")
|
||||
fields := map[string]interface{}{}
|
||||
fields["event_id"] = eventId
|
||||
result, err := task.Get(fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
type TriggerTaskBody struct {
|
||||
PlanId string `json:"planId" validate:"required"`
|
||||
HandleAdvice string `json:"handleAdvice"`
|
||||
// 资源Id
|
||||
ResourceID string `json:"resourceId"`
|
||||
// 资源名称(cpCode)
|
||||
ResourceName string `json:"resourceName"`
|
||||
// 资源节点
|
||||
ResourceNode string `json:"resourceNode"`
|
||||
// 资源类型
|
||||
ResourceType string `json:"resourceType"`
|
||||
|
||||
// 方案参数
|
||||
SchemeParams string `json:"schemeParams"`
|
||||
}
|
||||
|
||||
// 手动触发调度任务
|
||||
func TriggerSchedTask_UserManual(c *gin.Context) {
|
||||
var body TriggerTaskBody
|
||||
err := c.ShouldBindJSON(&body)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
// 暂不入库
|
||||
record := event.EventRecord{
|
||||
ResourceType: body.ResourceType,
|
||||
ResourceNode: body.ResourceNode,
|
||||
ResourceName: body.ResourceName,
|
||||
ResourceId: body.ResourceID,
|
||||
Id: id.NewEventRecord(),
|
||||
}
|
||||
|
||||
task := &sc.SchedTask{}
|
||||
|
||||
t := time.Now()
|
||||
sno := fmt.Sprintf("%d-%d%d-%s", t.Year(), t.Month(), t.Day(), record.Id)
|
||||
task.Id = record.ResourceType + "-" + sno
|
||||
task.TaskName = ""
|
||||
task.EventId = record.Id
|
||||
task.StartTime = time.Now()
|
||||
task.PlanId = body.PlanId
|
||||
task.CreateTime = time.Now()
|
||||
task.HandleAdvice = body.HandleAdvice
|
||||
task.HandleTime = time.Now()
|
||||
err = schedule_engine.PlanHandle(task.PlanId, task.Id, body.SchemeParams, record)
|
||||
if err != nil {
|
||||
//log.Errorf("%v", err)
|
||||
controller.FailCode(c, errors.ServerError, err, "调度方案失败!")
|
||||
return
|
||||
}
|
||||
task.TaskStatus = sc.TASK_STATUS_ING
|
||||
task.TriggerType = sc.TRIGGER_TYPE_MANUAL
|
||||
_, err = task.Create()
|
||||
if err != nil {
|
||||
log.Errorf("生成调度任务失败:%v,事件ID:%s", err, record.Id)
|
||||
controller.FailCode(c, errors.ServerError, err, "生成调度任务失败!")
|
||||
return
|
||||
}
|
||||
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
// 手动触发调度任务
|
||||
func TriggerSchedTask(c *gin.Context) {
|
||||
eventId := c.Param("eventId")
|
||||
event := &event.EventRecord{}
|
||||
eventFields := map[string]interface{}{}
|
||||
eventFields["id"] = eventId
|
||||
record, err := event.Get(eventFields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
var body TriggerTaskBody
|
||||
err = c.ShouldBindJSON(&body)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
task := &sc.SchedTask{}
|
||||
fields := map[string]interface{}{}
|
||||
fields["event_id"] = eventId
|
||||
taskRecord, err := task.Get(fields)
|
||||
if ur, bl := c.Get(middleware.LoginUserKey); bl {
|
||||
if u, b := ur.(*user.User); b {
|
||||
task.HandleUsername = u.Name
|
||||
taskRecord.HandleUsername = u.Name
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
t := time.Now()
|
||||
sno := fmt.Sprintf("%d-%d%d-%s", t.Year(), t.Month(), t.Day(), eventId)
|
||||
task.Id = record.ResourceType + "-" + sno
|
||||
task.TaskName = ""
|
||||
task.EventId = eventId
|
||||
task.StartTime = time.Now()
|
||||
task.PlanId = body.PlanId
|
||||
task.CreateTime = time.Now()
|
||||
task.HandleAdvice = body.HandleAdvice
|
||||
task.HandleTime = time.Now()
|
||||
err = schedule_engine.PlanHandle(task.PlanId, task.Id, "", record)
|
||||
if err != nil {
|
||||
log.Errorf("%v", err)
|
||||
controller.FailCode(c, errors.ServerError, err, "调度方案失败!")
|
||||
return
|
||||
}
|
||||
task.TaskStatus = sc.TASK_STATUS_ING
|
||||
task.TriggerType = sc.TRIGGER_TYPE_MANUAL
|
||||
_, err = task.Create()
|
||||
if err != nil {
|
||||
log.Errorf("生成调度任务失败:%v,事件ID:%s", err, eventId)
|
||||
controller.FailCode(c, errors.ServerError, err, "生成调度任务失败!")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
taskRecord.TriggerType = sc.TRIGGER_TYPE_MANUAL
|
||||
taskRecord.StartTime = time.Now()
|
||||
taskRecord.EventId = eventId
|
||||
taskRecord.PlanId = body.PlanId
|
||||
taskRecord.HandleAdvice = body.HandleAdvice
|
||||
taskRecord.HandleTime = time.Now()
|
||||
err = schedule_engine.PlanHandle(taskRecord.PlanId, taskRecord.Id, "", record)
|
||||
if err != nil {
|
||||
log.Errorf("%v", err)
|
||||
controller.FailCode(c, errors.ServerError, err, "调度失败!")
|
||||
return
|
||||
}
|
||||
taskRecord.TaskStatus = sc.TASK_STATUS_ING
|
||||
_, err = taskRecord.Update(nil)
|
||||
if err != nil {
|
||||
log.Errorf("生成调度任务失败:%v,事件ID:%s", err, eventId)
|
||||
controller.FailCode(c, errors.ServerError, err, "生成调度任务失败!")
|
||||
return
|
||||
}
|
||||
}
|
||||
controller.Success(c, "")
|
||||
}
|
||||
|
||||
type TaskCallBackBody struct {
|
||||
Status string `json:"status" validate:"required"` // 1:成功,2:失败
|
||||
EndTime int64 `json:"endTime"` //秒级时间戳
|
||||
}
|
||||
|
||||
// 调度任务回调
|
||||
func TaskCallBack(c *gin.Context) {
|
||||
taskId := c.Param("taskId")
|
||||
var body TaskCallBackBody
|
||||
err := c.ShouldBindJSON(&body)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
task := &sc.SchedTask{}
|
||||
fields := map[string]interface{}{}
|
||||
fields["id"] = taskId
|
||||
taskRecord, err := task.Get(fields)
|
||||
if err != nil {
|
||||
log.Errorf("回调任务失败:%v", err)
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "未找到调度任务,请检查参数!")
|
||||
return
|
||||
}
|
||||
taskRecord.TaskStatus = body.Status
|
||||
if body.EndTime <= 0 {
|
||||
taskRecord.EndTime = time.Now()
|
||||
} else {
|
||||
taskRecord.EndTime = time.Unix(body.EndTime, 22)
|
||||
}
|
||||
_, err = taskRecord.Update(nil)
|
||||
|
||||
// todo 将事件更新至事件历史表(一删一增)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("更新回调任务失败:%v", err)
|
||||
controller.FailCode(c, errors.ServerError, err, "内部错误!")
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
evt := &event.EventRecord{}
|
||||
f := map[string]interface{}{}
|
||||
f["id"] = taskRecord.EventId
|
||||
e, err := evt.Get(f)
|
||||
if err == nil {
|
||||
eh := &event.HistoryEventRecord{
|
||||
Id: e.Id,
|
||||
EventName: e.EventName,
|
||||
EventKey: e.EventKey,
|
||||
Level: e.Level,
|
||||
ResourceId: e.ResourceId,
|
||||
ResourceName: e.ResourceName,
|
||||
ResourceType: e.ResourceType,
|
||||
ResourceNode: e.ResourceNode,
|
||||
EventTime: e.EventTime,
|
||||
EventInfo: e.EventInfo,
|
||||
OperatorUser: taskRecord.HandleUsername,
|
||||
OperatorFinishTime: taskRecord.EndTime,
|
||||
CreateTime: time.Now(),
|
||||
}
|
||||
rows, _ := eh.SaveOrUpdate()
|
||||
if rows > 0 {
|
||||
e.Delete()
|
||||
}
|
||||
}
|
||||
}()
|
||||
controller.Success(c, "回调成功")
|
||||
}
|
||||
|
||||
// 任务状态数统计
|
||||
func CountTaskStatus(c *gin.Context) {
|
||||
task := &sc.SchedTask{}
|
||||
result, err := task.CountStatusNum()
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
// 调度任务自动化率
|
||||
func AutoRatio(c *gin.Context) {
|
||||
task := &sc.SchedTask{}
|
||||
result, err := task.AutoRatio()
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "数据库异常!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, result)
|
||||
}
|
232
server/internal/controller/v1/statistic.go
Normal file
232
server/internal/controller/v1/statistic.go
Normal file
@ -0,0 +1,232 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/device"
|
||||
devc "git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/device"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GetDeviceOnlineStatistic(c *gin.Context) {
|
||||
duration := c.Query("duration")
|
||||
if len(duration) <= 1 {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
var timeDuration time.Duration
|
||||
if strings.HasSuffix(duration, "h") {
|
||||
timeDuration = time.Hour
|
||||
} else if strings.HasSuffix(duration, "m") {
|
||||
timeDuration = time.Minute
|
||||
} else {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
timeInt, err := strconv.ParseInt(duration[0:len(duration)-1], 10, 64)
|
||||
if err != nil || timeInt <= 0 {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
if timeInt > 1440 || (timeDuration == time.Hour && timeInt > 24) {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
result := make(map[string]int)
|
||||
|
||||
now := time.Now()
|
||||
todayBegin := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||||
timeInterval := time.Duration((timeInt - 1) * timeDuration.Nanoseconds())
|
||||
timeIntervalStart := todayBegin
|
||||
var timeIntervalEnd time.Time
|
||||
sql := "SELECT CASE "
|
||||
for timeIntervalStart.Before(now) {
|
||||
timeIntervalEnd = timeIntervalStart.Add(timeInterval)
|
||||
timeStartStr := timeIntervalStart.Format("200601021504")
|
||||
timeEndStr := timeIntervalEnd.Format("200601021504")
|
||||
sql += "WHEN id BETWEEN '" + timeStartStr + "' AND '" + timeEndStr + "' THEN '" + timeStartStr + "' "
|
||||
result[timeStartStr] = 0
|
||||
timeIntervalStart = timeIntervalEnd.Add(timeDuration)
|
||||
}
|
||||
|
||||
sql += "END AS time, MAX(count) AS count FROM perc_device_online_count WHERE id >= '" + todayBegin.Format("200601021504") + "' AND id <= '" + now.Format("200601021504") + "' GROUP BY time;"
|
||||
|
||||
d := device.DeviceOnlineCount{}
|
||||
tResult, err := d.Query(sql)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "服务异常!")
|
||||
return
|
||||
}
|
||||
|
||||
for _, item := range tResult {
|
||||
result[item.Time] = item.Count
|
||||
}
|
||||
|
||||
delete(result, "")
|
||||
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
func GetDeviceUsageRate(c *gin.Context) {
|
||||
d := &devc.DeviceInfo{}
|
||||
|
||||
result, err := d.GetHistoryUsageRate()
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "服务异常!")
|
||||
return
|
||||
}
|
||||
|
||||
result1, err := d.GetTodayUsageRate()
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "服务异常!")
|
||||
return
|
||||
}
|
||||
|
||||
result["today"] = result1["today"]
|
||||
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
type DeviceOperateLogCondition struct {
|
||||
PageInfo *request.PageInfo `json:"pageInfo" binding:"required"`
|
||||
StartTime *time.Time `json:"startTime"`
|
||||
EndTime *time.Time `json:"endTime"`
|
||||
Operate string `json:"operate"`
|
||||
}
|
||||
|
||||
func GetDeviceOperateLog(c *gin.Context) {
|
||||
serialNo := c.Param("serialNo")
|
||||
|
||||
var body DeviceOperateLogCondition
|
||||
err := c.ShouldBindJSON(&body)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
op := &devc.DeviceOperateLog{}
|
||||
fields := make(map[string]interface{})
|
||||
fields["serial_no"] = serialNo
|
||||
if body.StartTime != nil {
|
||||
fields["operate_time >"] = body.StartTime
|
||||
} else {
|
||||
now := time.Now()
|
||||
todayBegin := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||||
fields["operate_time >"] = todayBegin
|
||||
}
|
||||
|
||||
if body.EndTime != nil {
|
||||
fields["operate_time <"] = body.EndTime
|
||||
}
|
||||
|
||||
if len(body.Operate) > 0 {
|
||||
fields["operate"] = body.Operate
|
||||
}
|
||||
|
||||
page := &model.Page[devc.DeviceOperateLog]{
|
||||
CurrentPage: body.PageInfo.CurrentPage,
|
||||
PageSize: body.PageInfo.PageSize,
|
||||
Order: body.PageInfo.Order,
|
||||
}
|
||||
|
||||
err = op.Page(page, fields)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "服务异常!")
|
||||
return
|
||||
}
|
||||
|
||||
if page.Data == nil {
|
||||
page.Data = []devc.DeviceOperateLog{}
|
||||
}
|
||||
|
||||
controller.Success(c, page)
|
||||
}
|
||||
|
||||
func GetDeviceRunTime(c *gin.Context) {
|
||||
serialNo := c.Param("serialNo")
|
||||
duration := c.Query("duration")
|
||||
|
||||
result := make(map[string]int)
|
||||
d := &devc.DeviceRunTime{}
|
||||
now := time.Now()
|
||||
var startDate string
|
||||
if duration == "day" {
|
||||
nowStr := now.Format("20060102")
|
||||
tResult, err := d.GetRunTimeByDay(serialNo, nowStr)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "服务异常!")
|
||||
return
|
||||
}
|
||||
result[nowStr] = tResult.RunTime
|
||||
} else if duration == "month" {
|
||||
startDate = time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()).Format("20060102")
|
||||
endDate := now.Format("20060102")
|
||||
tmp, err := d.StatisticRunTimeByDuration(serialNo, startDate, endDate)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "服务异常!")
|
||||
return
|
||||
}
|
||||
|
||||
tDate := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
|
||||
for tDate.Before(now) {
|
||||
result[tDate.Format("20060102")] = 0
|
||||
tDate = tDate.Add(24 * time.Hour)
|
||||
}
|
||||
|
||||
for _, runTime := range tmp {
|
||||
result[runTime.Date] = runTime.RunTime
|
||||
}
|
||||
} else {
|
||||
controller.FailCode(c, errors.InvalidParameter, nil, "请检查参数!")
|
||||
return
|
||||
}
|
||||
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
func GetAllDeviceRunTime(c *gin.Context) {
|
||||
d := &devc.DeviceRunTime{}
|
||||
result, err := d.StatisticRunTimeByAllDevice()
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "服务异常!")
|
||||
return
|
||||
}
|
||||
controller.Success(c, result)
|
||||
}
|
||||
|
||||
func GetDeviceBootCount(c *gin.Context) {
|
||||
serialNo := c.Param("serialNo")
|
||||
|
||||
d := &devc.DeviceOperateLog{}
|
||||
now := time.Now()
|
||||
monthBegin := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
|
||||
startDate := monthBegin.Format("2006-01-02 15:04:05.999999999 -0700")
|
||||
endDate := now.Format("2006-01-02 15:04:05.999999999 -0700")
|
||||
tResult, err := d.StatisticDeviceBootCountByDuration(serialNo, startDate, endDate)
|
||||
if err != nil {
|
||||
controller.FailCode(c, errors.ServerError, err, "服务异常!")
|
||||
return
|
||||
}
|
||||
|
||||
result := make(map[string]int)
|
||||
tDate := monthBegin
|
||||
for tDate.Before(now) {
|
||||
result[tDate.Format("20060102")] = 0
|
||||
tDate = tDate.Add(24 * time.Hour)
|
||||
}
|
||||
|
||||
for _, dateCount := range tResult {
|
||||
result[dateCount.Date] = dateCount.Count
|
||||
}
|
||||
|
||||
controller.Success(c, result)
|
||||
}
|
27
server/internal/middleware/app_context.go
Normal file
27
server/internal/middleware/app_context.go
Normal file
@ -0,0 +1,27 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
const (
|
||||
CLUSTERID = "clusterId"
|
||||
NAMESPACE = "namespace"
|
||||
)
|
||||
|
||||
func AppContextHandler() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
ns := c.Request.Header.Get("namespace")
|
||||
if len(ns) != 0 {
|
||||
c.Set(NAMESPACE, ns)
|
||||
}
|
||||
|
||||
clusterId := c.Param("cluster")
|
||||
if len(clusterId) != 0 {
|
||||
c.Set(CLUSTERID, clusterId)
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
|
||||
}
|
230
server/internal/middleware/authentication.go
Normal file
230
server/internal/middleware/authentication.go
Normal file
@ -0,0 +1,230 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/config"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/user"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/auth"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/authen"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/golang/glog"
|
||||
"gorm.io/gorm"
|
||||
"io"
|
||||
"net/http"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
const (
|
||||
LoginUserKey = "login-user"
|
||||
)
|
||||
|
||||
func AuthenticationHandler() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
|
||||
match, _ := regexp.MatchString("/healthz", c.Request.RequestURI)
|
||||
if match {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
match, _ = regexp.MatchString("/run", c.Request.RequestURI)
|
||||
if match {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
match, _ = regexp.MatchString("/login", c.Request.RequestURI)
|
||||
if match {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
match, _ = regexp.MatchString("/api/v1/socket/*", c.Request.RequestURI)
|
||||
if match {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
match, _ = regexp.MatchString("/api/v1/*", c.Request.RequestURI)
|
||||
if match {
|
||||
rawToken := c.Request.Header.Get("Authorization")
|
||||
if rawToken == "" {
|
||||
glog.Warning("unauthorized access, token not specified")
|
||||
response.Resp().FailCode(c, errors.AuthorizationError, "token should be specified in header with 'Authorization' key")
|
||||
return
|
||||
}
|
||||
|
||||
//todo 临时用
|
||||
if config.Config.AppConfig.Debug {
|
||||
if rawToken == "mock token" {
|
||||
u, _ := user.GetUserByUsername("admin")
|
||||
c.Set(LoginUserKey, u)
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var username, apiToken string
|
||||
ok, bearerToken := authen.JWTAuthorizer.IsBearerToken(rawToken)
|
||||
if ok {
|
||||
loginInfo, err := auth.Validate(bearerToken)
|
||||
//marshal, _ := json.Marshal(loginInfo)
|
||||
//fmt.Print(string(marshal))
|
||||
|
||||
if err != nil {
|
||||
if authen.JWTAuthorizer.IsTokenExpired(err) {
|
||||
glog.Warning("unauthorized access, bearer token expired")
|
||||
response.Resp().FailCode(c, errors.AuthorizationError, "bearer token expired")
|
||||
return
|
||||
}
|
||||
glog.Warningf("validate bearer token failed, %s", err)
|
||||
response.Resp().FailCode(c, errors.AuthorizationError, fmt.Sprint("validate bearer token failed, %s", err))
|
||||
return
|
||||
}
|
||||
username = loginInfo.Username
|
||||
apiToken = loginInfo.Token
|
||||
} else {
|
||||
glog.Warningf("validate bearer token failed")
|
||||
response.Resp().FailCode(c, errors.AuthorizationError, "validate bearer token failed")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
u, err := user.GetUserByUsername(username)
|
||||
if err != nil {
|
||||
// 适配算网用户,支持单点登录
|
||||
if config.Config.CfnConfig.Enable {
|
||||
u, err = CheckUserLogin(c)
|
||||
if err != nil {
|
||||
glog.Errorf("unauthorized access, user not found or not login, %s", username)
|
||||
response.Resp().FailCode(c, errors.AuthorizationError, "user not found or not login")
|
||||
return
|
||||
}
|
||||
// todo?
|
||||
u.APIToken = apiToken
|
||||
} else {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
glog.Errorf("unauthorized access, user not found, %s", username)
|
||||
response.Resp().FailCode(c, errors.AuthorizationError, "user not found")
|
||||
return
|
||||
}
|
||||
glog.Errorf("get user from db failed, user %s, %s", username, err)
|
||||
response.Resp().FailCode(c, errors.ServerError, fmt.Sprintf("get user from db failed, user %s, %s", username, err))
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if apiToken != "" && apiToken != u.APIToken {
|
||||
glog.Warningf("unauthorized access, password mismatch, user %s", username)
|
||||
response.Resp().FailCode(c, errors.AuthorizationError, "password mismatch")
|
||||
return
|
||||
}
|
||||
|
||||
c.Set(LoginUserKey, u)
|
||||
c.Next()
|
||||
}
|
||||
|
||||
//match, _ = regexp.MatchString("/", c.Request.RequestURI)
|
||||
//if match {
|
||||
// c.Next()
|
||||
// return
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const AUTH_HEADER = "Authorization"
|
||||
|
||||
func CheckUserLogin(c *gin.Context) (*user.UserObj, error) {
|
||||
url := config.Config.Auth.Url
|
||||
if url == "" {
|
||||
return nil, errors.NewBusinessError(errors.ServerError, "login config is not set!")
|
||||
}
|
||||
token := c.Request.Header.Get(AUTH_HEADER)
|
||||
|
||||
var client *http.Client
|
||||
var request *http.Request
|
||||
var resp *http.Response
|
||||
client = &http.Client{Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
}}
|
||||
request, err := http.NewRequest("GET", url+config.Config.Auth.LoginInfo, nil)
|
||||
if err != nil {
|
||||
glog.Errorln("failed to create request [Get LoginInfo]!", err)
|
||||
return nil, errors.NewBusinessError(errors.ServerError, "failed to create request [Get LoginInfo]!")
|
||||
}
|
||||
request.Header.Add(AUTH_HEADER, token)
|
||||
resp, err = client.Do(request)
|
||||
if err != nil {
|
||||
glog.Errorln("failed to request [Get LoginInfo]!", err)
|
||||
return nil, errors.NewBusinessError(errors.ServerError, "failed to request [Get LoginInfo]!")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
defer client.CloseIdleConnections()
|
||||
if resp.StatusCode != 200 {
|
||||
glog.Errorln("response error [Get LoginInfo]!")
|
||||
glog.Errorln("response status code: %d, %s", resp.StatusCode, resp.Body)
|
||||
return nil, errors.NewBusinessError(errors.ServerError, "response error [Get LoginInfo]!")
|
||||
}
|
||||
|
||||
var respBody map[string]interface{}
|
||||
respStr, _ := io.ReadAll(resp.Body)
|
||||
err = json.Unmarshal(respStr, &respBody)
|
||||
if err != nil {
|
||||
glog.Errorln("failed to decode response [Get LoginInfo]!", err)
|
||||
return nil, errors.NewBusinessError(errors.ServerError, "failed to decode response [Get LoginInfo]!")
|
||||
}
|
||||
|
||||
data := respBody["data"]
|
||||
if data == nil {
|
||||
meta := respBody["meta"]
|
||||
return nil, fmt.Errorf("failed to get user info from login server! %s", meta)
|
||||
}
|
||||
|
||||
userObj := &user.UserObj{}
|
||||
userMap := data.(map[string]interface{})["user"]
|
||||
|
||||
userId := userMap.(map[string]interface{})["userId"]
|
||||
if userId != nil {
|
||||
userObj.UserID = userId.(string)
|
||||
}
|
||||
|
||||
cn := userMap.(map[string]interface{})["cn"]
|
||||
if cn != nil {
|
||||
userObj.DisplayName = cn.(string)
|
||||
}
|
||||
mobile := userMap.(map[string]interface{})["mobile"]
|
||||
if mobile != nil {
|
||||
userObj.Mobile = mobile.(string)
|
||||
}
|
||||
provinceId := userMap.(map[string]interface{})["provinceId"]
|
||||
if provinceId != nil {
|
||||
userObj.ProvinceId = provinceId.(string)
|
||||
}
|
||||
userObj.Status = userMap.(map[string]interface{})["status"].(string)
|
||||
|
||||
accountMap := data.(map[string]interface{})["account"]
|
||||
userName := accountMap.(map[string]interface{})["loginName"]
|
||||
if userName != nil {
|
||||
userObj.UserName = userName.(string)
|
||||
}
|
||||
|
||||
if userName == "admin" {
|
||||
userObj.Role = 1
|
||||
} else {
|
||||
userObj.Role = 0
|
||||
}
|
||||
|
||||
if config.Config.CfnConfig.Enable {
|
||||
userObj.Namespace = fmt.Sprintf("DEFAULT,%s", config.Config.CfnConfig.CfnWorkSpaceId)
|
||||
} else {
|
||||
userObj.Namespace = "DEFAULT"
|
||||
}
|
||||
|
||||
return userObj, nil
|
||||
}
|
49
server/internal/middleware/authorization.go
Normal file
49
server/internal/middleware/authorization.go
Normal file
@ -0,0 +1,49 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/golang/glog"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
func AuthorizationHandler() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
|
||||
match, _ := regexp.MatchString("/healthz", c.Request.RequestURI)
|
||||
if match {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
match, _ = regexp.MatchString("/run", c.Request.RequestURI)
|
||||
if match {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
match, _ = regexp.MatchString("/login", c.Request.RequestURI)
|
||||
if match {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
match, _ = regexp.MatchString("/api/v1/socket/*", c.Request.RequestURI)
|
||||
if match {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
match, _ = regexp.MatchString("/api/v1/*", c.Request.RequestURI)
|
||||
if match {
|
||||
_, exist := c.Get(LoginUserKey)
|
||||
if !exist {
|
||||
glog.Fatal("Authorization middleware should work together with Authentication middleware")
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
10
server/internal/middleware/cors.go
Normal file
10
server/internal/middleware/cors.go
Normal file
@ -0,0 +1,10 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func CorsHandler() gin.HandlerFunc {
|
||||
return cors.Default()
|
||||
}
|
53
server/internal/middleware/logger.go
Normal file
53
server/internal/middleware/logger.go
Normal file
@ -0,0 +1,53 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/config"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/pkg/log"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
"time"
|
||||
)
|
||||
|
||||
type responseWriter struct {
|
||||
gin.ResponseWriter
|
||||
body *bytes.Buffer
|
||||
}
|
||||
|
||||
func (w responseWriter) Write(b []byte) (int, error) {
|
||||
w.body.Write(b)
|
||||
return w.ResponseWriter.Write(b)
|
||||
}
|
||||
|
||||
func (w responseWriter) WriteString(s string) (int, error) {
|
||||
w.body.WriteString(s)
|
||||
return w.ResponseWriter.WriteString(s)
|
||||
}
|
||||
|
||||
// CustomLogger 接收gin框架默认的日志
|
||||
func CustomLogger() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
blw := &responseWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
|
||||
c.Writer = blw
|
||||
// 读取body数据
|
||||
//body := request.GetBody(c)
|
||||
c.Next()
|
||||
|
||||
cost := time.Since(c.GetTime("requestStartTime"))
|
||||
if config.Config.AppEnv != "production" {
|
||||
path := c.Request.URL.Path
|
||||
log.Logger.Info(path,
|
||||
zap.Int("status", c.Writer.Status()),
|
||||
zap.String("method", c.Request.Method),
|
||||
zap.String("path", path),
|
||||
zap.String("query", c.Request.URL.RawQuery),
|
||||
//zap.Any("body", string(body)),
|
||||
zap.String("ip", c.ClientIP()),
|
||||
zap.String("user-agent", c.Request.UserAgent()),
|
||||
zap.String("errors", c.Errors.ByType(gin.ErrorTypePrivate).String()),
|
||||
zap.String("cost", cost.String()),
|
||||
//zap.String("response", blw.body.String()),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
40
server/internal/middleware/recovery.go
Normal file
40
server/internal/middleware/recovery.go
Normal file
@ -0,0 +1,40 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/config"
|
||||
e "git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||||
response2 "git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/response"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/pkg/log"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CustomRecovery 自定义错误 (panic) 拦截中间件、对可能发生的错误进行拦截、统一记录
|
||||
func CustomRecovery() gin.HandlerFunc {
|
||||
DefaultErrorWriter := &PanicExceptionRecord{}
|
||||
return gin.RecoveryWithWriter(DefaultErrorWriter, func(c *gin.Context, err interface{}) {
|
||||
// 这里针对发生的panic等异常进行统一响应即
|
||||
// 这里针对发生的panic等异常进行统一响应即
|
||||
errStr := ""
|
||||
if config.Config.Debug == true {
|
||||
errStr = fmt.Sprintf("%v", err)
|
||||
}
|
||||
response2.Resp().SetHttpCode(http.StatusInternalServerError).FailCode(c, e.ServerError, errStr)
|
||||
})
|
||||
}
|
||||
|
||||
// PanicExceptionRecord panic等异常记录
|
||||
type PanicExceptionRecord struct{}
|
||||
|
||||
func (p *PanicExceptionRecord) Write(b []byte) (n int, err error) {
|
||||
s1 := "An error occurred in the server's internal code:"
|
||||
var build strings.Builder
|
||||
build.WriteString(s1)
|
||||
build.Write(b)
|
||||
errStr := build.String()
|
||||
log.Error(errStr)
|
||||
return len(errStr), errors.New(errStr)
|
||||
}
|
13
server/internal/middleware/request_cost.go
Normal file
13
server/internal/middleware/request_cost.go
Normal file
@ -0,0 +1,13 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"time"
|
||||
)
|
||||
|
||||
func RequestCostHandler() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
c.Set("requestStartTime", time.Now())
|
||||
c.Next()
|
||||
}
|
||||
}
|
93
server/internal/middleware/vue_embed.go
Normal file
93
server/internal/middleware/vue_embed.go
Normal file
@ -0,0 +1,93 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"github.com/gin-gonic/gin"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const INDEX = "index.html"
|
||||
|
||||
type ServeFileSystem interface {
|
||||
http.FileSystem
|
||||
Exists(prefix string, path string) bool
|
||||
}
|
||||
|
||||
type localFileSystem struct {
|
||||
http.FileSystem
|
||||
root string
|
||||
indexes bool
|
||||
}
|
||||
|
||||
func LocalFile(root string, indexes bool) *localFileSystem {
|
||||
return &localFileSystem{
|
||||
FileSystem: gin.Dir(root, indexes),
|
||||
root: root,
|
||||
indexes: indexes,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *localFileSystem) Exists(prefix string, filepath string) bool {
|
||||
if p := strings.TrimPrefix(filepath, prefix); len(p) < len(filepath) {
|
||||
name := path.Join(l.root, p)
|
||||
stats, err := os.Stat(name)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if stats.IsDir() {
|
||||
if !l.indexes {
|
||||
index := path.Join(name, INDEX)
|
||||
_, err := os.Stat(index)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ServeRoot(urlPrefix, root string) gin.HandlerFunc {
|
||||
return Serve(urlPrefix, LocalFile(root, false))
|
||||
}
|
||||
|
||||
// Static returns a middleware handler that serves static files in the given directory.
|
||||
func Serve(urlPrefix string, fs ServeFileSystem) gin.HandlerFunc {
|
||||
fileserver := http.FileServer(fs)
|
||||
if urlPrefix != "" {
|
||||
fileserver = http.StripPrefix(urlPrefix, fileserver)
|
||||
}
|
||||
return func(c *gin.Context) {
|
||||
if fs.Exists(urlPrefix, c.Request.URL.Path) {
|
||||
fileserver.ServeHTTP(c.Writer, c.Request)
|
||||
c.Abort()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type embedFileSystem struct {
|
||||
http.FileSystem
|
||||
}
|
||||
|
||||
func (e embedFileSystem) Exists(prefix string, path string) bool {
|
||||
_, err := e.Open(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func EmbedFolder(fsEmbed embed.FS, targetPath string) ServeFileSystem {
|
||||
fsys, err := fs.Sub(fsEmbed, targetPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return embedFileSystem{
|
||||
FileSystem: http.FS(fsys),
|
||||
}
|
||||
}
|
127
server/internal/model/agent/agent_info.go
Normal file
127
server/internal/model/agent/agent_info.go
Normal file
@ -0,0 +1,127 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/utils"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
OS_WINDOWS = "Windows"
|
||||
OS_LINUX = "Linux"
|
||||
OS_LINUX_LIST = "Ubuntu,CentOS,KylinOS"
|
||||
OS_LINUX_UBUNTU = "Ubuntu"
|
||||
OS_LINUX_CENTOS = "CentOS"
|
||||
OS_LINUX_KylinOS = "KylinOS"
|
||||
)
|
||||
|
||||
// 小助手信息
|
||||
// 表名:perc_agent_info
|
||||
type AgentInfo struct {
|
||||
Id string `gorm:"column:id;primaryKey" json:"id"` //type:string comment:主键 version:2023-9-11 14:25
|
||||
Version string `gorm:"column:version" json:"version" validate:"required"` //type:string comment:版本 version:2023-9-11 14:25
|
||||
VersionNum int64 `gorm:"column:version_num" json:"versionNum"` //type:int comment:版本排序号
|
||||
OsPlatform string `gorm:"column:os_platform" json:"osPlatform"` //type:string comment:操作系统平台;字典:Windows\Linux
|
||||
OsType string `gorm:"column:os_type" json:"osType" validate:"required"` //type:string comment:操作系统类型;字典:Windows\Ubuntu\CentOS\KylinOS version:2023-9-11 14:25
|
||||
ArchType string `gorm:"column:arch_type" json:"archType" validate:"required"` //type:string comment:芯片架构类型;字典: X86\ARM version:2023-9-11 14:25
|
||||
PackageUrl string `gorm:"column:package_url" json:"packageUrl"` //type:string comment:程序包地址;oss地址 version:2023-9-11 14:25
|
||||
BucketName string `gorm:"column:bucket_name" json:"bucketName"` //type:string comment:桶名称
|
||||
Filename string `gorm:"column:filename" json:"filename"` //type:string comment:文件名称
|
||||
CompressionType string `gorm:"column:compression_type" json:"compressionType"` //type:string comment:压缩格式
|
||||
Command string `gorm:"column:command" json:"command"` //type:string comment:启动命令
|
||||
Describe string `gorm:"column:describe" json:"describe"` //type:string comment:描述 version:2023-9-11 14:25
|
||||
CreateBy string `gorm:"column:create_by" json:"createBy"` //type:string comment:创建人
|
||||
CreateTime time.Time `gorm:"column:create_time" json:"createTime"` //type:*time.Time comment:创建时间 version:2023-9-11 14:25
|
||||
UpdateTime time.Time `gorm:"column:update_time" json:"updateTime"` //type:*time.Time comment:更新时间
|
||||
}
|
||||
|
||||
func (AgentInfo) TableName() string {
|
||||
return "perc_agent_info"
|
||||
}
|
||||
|
||||
func (a *AgentInfo) Create() (int64, error) {
|
||||
a.CreateTime = time.Now()
|
||||
a.UpdateTime = time.Now()
|
||||
a.Id = utils.NewAgentID()
|
||||
|
||||
tx := model.DB().Create(a)
|
||||
|
||||
if tx.Error != nil {
|
||||
return 0, tx.Error
|
||||
}
|
||||
return tx.RowsAffected, nil
|
||||
}
|
||||
|
||||
func (a *AgentInfo) CreateBatch(agents []AgentInfo) (int64, error) {
|
||||
for i, _ := range agents {
|
||||
agents[i].CreateTime = time.Now()
|
||||
agents[i].UpdateTime = time.Now()
|
||||
agents[i].Id = utils.NewAgentID()
|
||||
}
|
||||
tx := model.DB().CreateInBatches(agents, len(agents))
|
||||
if tx.Error != nil {
|
||||
return 0, tx.Error
|
||||
}
|
||||
return tx.RowsAffected, nil
|
||||
}
|
||||
|
||||
func (a *AgentInfo) Delete() (int64, error) {
|
||||
tx := model.DB().Delete(a)
|
||||
if tx.Error != nil {
|
||||
return 0, tx.Error
|
||||
}
|
||||
return tx.RowsAffected, nil
|
||||
}
|
||||
|
||||
func (a *AgentInfo) Update(fields []string) (int64, error) {
|
||||
a.UpdateTime = time.Now()
|
||||
tx := model.DB().Model(&a).Select(fields).Updates(a)
|
||||
if tx.Error != nil {
|
||||
return 0, tx.Error
|
||||
}
|
||||
return tx.RowsAffected, nil
|
||||
}
|
||||
|
||||
func (a *AgentInfo) Get(fields map[string]interface{}) (AgentInfo, error) {
|
||||
agent := AgentInfo{}
|
||||
tx := model.DB().Where(fields).First(&agent)
|
||||
if tx.Error != nil && tx.Error != gorm.ErrRecordNotFound {
|
||||
return agent, tx.Error
|
||||
}
|
||||
return agent, nil
|
||||
}
|
||||
|
||||
func (a *AgentInfo) HasNewVersion(fields map[string]interface{}) (bool, error) {
|
||||
cout := int64(0)
|
||||
tx := model.DB().Model(a).Where("os_type=? and arch_type=? and version_num >=?", fields["os_type"], fields["arch_type"], fields["version_num"]).Count(&cout)
|
||||
if tx.Error != nil || cout > int64(0) {
|
||||
return true, tx.Error
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// 获取最近的版本
|
||||
func (a *AgentInfo) ListLastVersion() ([]AgentInfo, error) {
|
||||
agents := []AgentInfo{}
|
||||
tx := model.DB().Raw("SELECT * FROM perc_agent_info A INNER JOIN (SELECT os_type,arch_type,MAX (version_num) AS version_num FROM perc_agent_info GROUP BY os_type,arch_type) b ON A.arch_type=b.arch_type AND A.os_type=b.os_type AND A.version_num=b.version_num").Find(&agents)
|
||||
if tx.Error != nil {
|
||||
return nil, tx.Error
|
||||
}
|
||||
return agents, nil
|
||||
}
|
||||
|
||||
func (a *AgentInfo) Page(page *model.Page[AgentInfo], fields map[string]interface{}) error {
|
||||
keyword := fields["keyword"]
|
||||
query := model.DB()
|
||||
if keyword != "" {
|
||||
keyword = fmt.Sprintf("%%%s%%", keyword)
|
||||
query = query.Where("concat(version,os_platform,os_type,arch_type,describe) like ?", keyword)
|
||||
}
|
||||
err := page.SelectPages(query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
6
server/internal/model/app_manage/data/agent_whitelist.go
Normal file
6
server/internal/model/app_manage/data/agent_whitelist.go
Normal file
@ -0,0 +1,6 @@
|
||||
package data
|
||||
|
||||
type AgentWhitelist struct {
|
||||
// 项目目录白名单、日志文件白名单
|
||||
Project []string `json:"project"`
|
||||
}
|
96
server/internal/model/app_manage/node/machine_node.go
Normal file
96
server/internal/model/app_manage/node/machine_node.go
Normal file
@ -0,0 +1,96 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/secure"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type MachineNode struct {
|
||||
model.BaseUserModifyDbModel
|
||||
Name string `gorm:"column:name" json:"name"`
|
||||
HostName string `gorm:"column:hostname" json:"hostName"`
|
||||
OsName string `gorm:"column:os_name" json:"osName"`
|
||||
OsOccupyCpu float64 `gorm:"column:os_occupy_cpu" json:"osOccupyCpu"`
|
||||
OsOccupyMemory float64 `gorm:"column:os_occupy_memory" json:"osOccupyMemory"`
|
||||
OsOccupyDisk float64 `gorm:"column:os_occupy_disk" json:"osOccupyDisk"`
|
||||
HostIpv4s string `gorm:"column:host_ipv4s" json:"hostIpv4s"`
|
||||
Status int `gorm:"column:status" json:"status,omitempty"` // 假设可以为null
|
||||
StatusMsg string `gorm:"column:status_msg" json:"statusMsg"`
|
||||
TransportMode int `gorm:"column:transport_mode" json:"transportMode,omitempty"`
|
||||
CfnAgentUrl string `gorm:"column:cfn_agent_url" json:"cfnAgentUrl"`
|
||||
CfnAgentUsername string `gorm:"column:cfn_agent_username" json:"cfnAgentUsername"`
|
||||
CfnAgentPassword string `gorm:"column:cfn_agent_password" json:"cfnAgentPassword"`
|
||||
CfnAgentProtocol string `gorm:"column:cfn_agent_protocol" json:"cfnAgentProtocol"`
|
||||
CfnAgentTimeout int `gorm:"column:cfn_agent_timeout" json:"cfnAgentTimeout,omitempty"`
|
||||
CfnAgentHttpProxy string `gorm:"column:cfn_agent_http_proxy" json:"cfnAgentHttpProxy"`
|
||||
CfnAgentHttpProxyType string `gorm:"column:cfn_agent_http_proxy_type" json:"cfnAgentHttpProxyType"`
|
||||
CfnAgentVersion string `gorm:"column:cfn_agent_version" json:"cfnAgentVersion"`
|
||||
CfnAgentUptime int64 `gorm:"column:cfn_agent_uptime" json:"cfnAgentUptime"`
|
||||
CfnAgentBuildTime int64 `gorm:"column:cfn_agent_build_time" json:"cfnAgentBuildTime"`
|
||||
CfnAgentProjectCount int `gorm:"column:cfn_agent_project_count" json:"cfnAgentProjectCount,omitempty"`
|
||||
CfnAgentScriptCount int `gorm:"column:cfn_agent_script_count" json:"cfnAgentScriptCount,omitempty"`
|
||||
JavaVersion string `gorm:"column:java_version" json:"javaVersion"`
|
||||
JvmTotalMemory int64 `gorm:"column:jvm_total_memory" json:"jvmTotalMemory,omitempty"`
|
||||
JvmFreeMemory int64 `gorm:"column:jvm_free_memory" json:"jvmFreeMemory,omitempty"`
|
||||
TemplateNode int `gorm:"column:template_node" json:"templateNode,omitempty"`
|
||||
InstallId string `gorm:"column:install_id" json:"installId"`
|
||||
TransportEncryption int `gorm:"column:transport_encryption" json:"transportEncryption,omitempty"` // 传输加密方式 0 不加密 1 BASE64 2 AES
|
||||
Group string `gorm:"column:group_name" json:"groupName"`
|
||||
}
|
||||
|
||||
func NewMachine() *MachineNode {
|
||||
n := &MachineNode{}
|
||||
n.Handler = n
|
||||
return n
|
||||
}
|
||||
|
||||
func (*MachineNode) TableName() string {
|
||||
return "sched_machine_node_info"
|
||||
}
|
||||
|
||||
func (m *MachineNode) ListGroup() ([]string, error) {
|
||||
var result []string
|
||||
tx := model.DB().Table(m.TableName()).Select("group_name").Distinct().Scan(&result)
|
||||
return result, tx.Error
|
||||
}
|
||||
|
||||
func (*MachineNode) FindResult(db *gorm.DB) (interface{}, error) {
|
||||
var result []MachineNode
|
||||
if db == nil {
|
||||
return result, nil
|
||||
}
|
||||
err := db.Find(&result).Error
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (m *MachineNode) Authorize() string {
|
||||
return secure.Sha1Encrypt(m.CfnAgentUsername + "@" + m.CfnAgentPassword)
|
||||
}
|
||||
|
||||
// 根据Name查询MachineNode是否存在
|
||||
func (m *MachineNode) ExistMachineNodeByName(name string) (bool, error) {
|
||||
var count int64
|
||||
tx := model.DB().Table(m.TableName()).Where("name = ?", name).Count(&count)
|
||||
return count > 0, tx.Error
|
||||
}
|
||||
|
||||
// 根据CfnAgentUrl查询MachineNode是否存在
|
||||
func (m *MachineNode) ExistMachineNodeByCfnAgentUrl(url string) (bool, error) {
|
||||
var count int64
|
||||
tx := model.DB().Table(m.TableName()).Where("cfn_agent_url = ?", url).Count(&count)
|
||||
return count > 0, tx.Error
|
||||
}
|
||||
|
||||
// 根据CfnAgentUrl查询MachineNode
|
||||
func (m *MachineNode) GetMachineNodeByCfnAgentUrl(url string) (*MachineNode, error) {
|
||||
var result MachineNode
|
||||
tx := model.DB().Table(m.TableName()).Where("cfn_agent_url = ?", url).First(&result)
|
||||
return &result, tx.Error
|
||||
}
|
||||
|
||||
// 更新MachineNode的CfnAgentPassword
|
||||
func (m *MachineNode) UpdateMachineNodeCfnAgentPassword(url, password string) error {
|
||||
tx := model.DB().Table(m.TableName()).Where("cfn_agent_url = ?", url).Update("cfn_agent_password", password)
|
||||
return tx.Error
|
||||
}
|
72
server/internal/model/app_manage/node/node.go
Normal file
72
server/internal/model/app_manage/node/node.go
Normal file
@ -0,0 +1,72 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Node struct {
|
||||
model.BaseMachineModel
|
||||
Url string `gorm:"column:url" json:"url"`
|
||||
LoginName string `gorm:"column:login_name" json:"loginName"`
|
||||
LoginPwd string `gorm:"column:login_pwd" json:"loginPwd"`
|
||||
Name string `gorm:"column:name" json:"name"`
|
||||
Protocol string `gorm:"column:protocol" json:"protocol"`
|
||||
OpenStatus int `gorm:"column:open_status" json:"openStatus"`
|
||||
TimeOut int `gorm:"column:timeout" json:"timeOut"`
|
||||
HttpProxy string `gorm:"column:http_proxy" json:"httpProxy"`
|
||||
HttpProxyType string `gorm:"column:http_proxy_type" json:"httpProxyType"`
|
||||
SortValue float32 `gorm:"column:sort_value" json:"sortValue"`
|
||||
MachineNodeData *MachineNode `gorm:"-" json:"machineNodeData"`
|
||||
}
|
||||
|
||||
func New() *Node {
|
||||
n := &Node{}
|
||||
n.Handler = n
|
||||
return n
|
||||
}
|
||||
|
||||
func (*Node) TableName() string {
|
||||
return "sched_node_info"
|
||||
}
|
||||
|
||||
func (n *Node) ListGroup() ([]string, error) {
|
||||
var result []string
|
||||
tx := model.DB().Table(n.TableName()).Select("\"group\"").Distinct().Scan(&result)
|
||||
return result, tx.Error
|
||||
}
|
||||
|
||||
func (n *Node) FindResult(db *gorm.DB) (interface{}, error) {
|
||||
var result []Node
|
||||
if db == nil {
|
||||
return result, nil
|
||||
}
|
||||
err := db.Find(&result).Error
|
||||
return result, err
|
||||
}
|
||||
|
||||
// 根据节点id获取节点信息
|
||||
func GetNodeById(id string) *Node {
|
||||
node := New()
|
||||
model.DB().Where("id = ?", id).First(node)
|
||||
return node
|
||||
}
|
||||
|
||||
// 根据节点id批量获取节点信息
|
||||
func GetNodeByIds(ids []string) []Node {
|
||||
var nodes []Node
|
||||
model.DB().Where("id in (?)", ids).Find(&nodes)
|
||||
return nodes
|
||||
}
|
||||
|
||||
// 根据工作空间(WorkspaceId)计算节点数量
|
||||
func CountNodeByWorkspaceId(workspaceId string) (int64, error) {
|
||||
var count int64
|
||||
tx := model.DB().Table(New().TableName()).Where("workspace_id = ?", workspaceId).Count(&count)
|
||||
return count, tx.Error
|
||||
}
|
||||
|
||||
// 根据MachineId更新Node的LoginPwd
|
||||
func UpdateNodeLoginPwdByMachineId(machineId string, loginPwd string) error {
|
||||
return model.DB().Table(New().TableName()).Where("machine_id = ?", machineId).Update("login_pwd", loginPwd).Error
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package after_opt
|
||||
|
||||
const (
|
||||
No = 0
|
||||
Restart = 1
|
||||
Order_Must_Restart = 2
|
||||
Order_Restart = 3
|
||||
)
|
@ -0,0 +1,39 @@
|
||||
package out_giving
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type OutGivingExecLog struct {
|
||||
Id string `gorm:"column:id;primary_key" json:"id"`
|
||||
LogsId string `gorm:"column:logs_id" json:"logsId"`
|
||||
}
|
||||
|
||||
func (o *OutGivingExecLog) TableName() string {
|
||||
return "sched_out_giving_instance_log"
|
||||
}
|
||||
|
||||
// 保存一条OutGivingExecLog
|
||||
func SaveOutGivingExecLog(outGivingExecLog *OutGivingExecLog) error {
|
||||
return model.DB().Create(outGivingExecLog).Error
|
||||
}
|
||||
|
||||
//// 根据Id查询OutGivingExecLog
|
||||
//func GetOutGivingExecLogById(id string) (*OutGivingExecLog, error) {
|
||||
// outGivingExecLog := new(OutGivingExecLog)
|
||||
// return outGivingExecLog, model.DB().Where("id = ?", id).First(outGivingExecLog).Error
|
||||
//}
|
||||
|
||||
// 根据Id查询OutGivingExecLog
|
||||
func GetOutGivingExecLogById(id string) (*OutGivingExecLog, error) {
|
||||
outGivingExecLog := new(OutGivingExecLog)
|
||||
if err := model.DB().Where("id = ?", id).First(outGivingExecLog).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil // 如果记录不存在,返回nil, nil
|
||||
}
|
||||
return nil, err // 其他类型的错误仍然返回
|
||||
}
|
||||
return outGivingExecLog, nil
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
package out_giving
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
// OutGivingLog 项目分发日志
|
||||
type OutGivingLog struct {
|
||||
model.BaseWorkspaceModel
|
||||
OutGivingID string `gorm:"column:out_giving_id;comment:'分发id'" json:"outGivingId"` // 分发id
|
||||
Status int `gorm:"column:status;comment:'状态'" json:"status"` // 状态
|
||||
StartTime time.Time `gorm:"column:start_time" json:"startTime"`
|
||||
EndTime time.Time `gorm:"column:end_time" json:"endTime"`
|
||||
Result string `gorm:"column:result;comment:'处理消息'" json:"result"` // 处理消息
|
||||
NodeID string `gorm:"column:node_id;comment:'节点id'" json:"nodeId"` // 节点id
|
||||
ProjectID string `gorm:"column:project_id;comment:'项目id'" json:"projectId"` // 项目id
|
||||
FileSize int64 `gorm:"column:file_size;comment:'文件大小'" json:"fileSize"` // 文件大小
|
||||
ProgressSize int64 `gorm:"column:progress_size;comment:'进度信息'" json:"progressSize"` // 进度信息
|
||||
|
||||
// 由于Go不支持泛型且GORM没有直接的表关联继承模型的方式,此处省略了直接的“parents = OutGivingModel.class”等Java特定注解的转换。
|
||||
// 在Go中,通常会通过外键或者关联查询来实现类似的关系。
|
||||
}
|
||||
|
||||
func NewOutGivingLog() *OutGivingLog {
|
||||
n := &OutGivingLog{}
|
||||
n.Handler = n
|
||||
return n
|
||||
}
|
||||
|
||||
// TableName 自定义表名
|
||||
func (o *OutGivingLog) TableName() string {
|
||||
return "sched_outgiving_log"
|
||||
}
|
||||
|
||||
func (o *OutGivingLog) FindResult(db *gorm.DB) (interface{}, error) {
|
||||
var result []OutGivingLog
|
||||
if db == nil {
|
||||
return result, nil
|
||||
}
|
||||
err := db.Find(&result).Error
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (o *OutGivingLog) Page(page *model.Page[OutGivingLog], fields map[string]interface{}) error {
|
||||
query := model.DB()
|
||||
if fields != nil {
|
||||
//query = query.Where(fields)
|
||||
for key := range fields {
|
||||
value := fields[key]
|
||||
switch value.(type) {
|
||||
case []string, []int, []int64, []interface{}:
|
||||
query = query.Where(key+" in (?)", value)
|
||||
default:
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
err := page.SelectPages(query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 根据outGivingId删除OutGivingLog
|
||||
func DeleteOutGivingLogByOutGivingId(outGivingId string) error {
|
||||
return model.DB().Table(NewOutGivingLog().TableName()).Where("out_giving_id = ?", outGivingId).Delete(&OutGivingLog{}).Error
|
||||
}
|
||||
|
||||
// 批量保存OutGivingLog
|
||||
func SaveOutGivingLog(outGivingLogs []OutGivingLog) error {
|
||||
return model.DB().Create(&outGivingLogs).Error
|
||||
}
|
||||
|
||||
// 更新OutGivingLog
|
||||
func UpdateOutGivingLog(outGivingLog *OutGivingLog) error {
|
||||
return model.DB().Model(outGivingLog).Updates(outGivingLog).Error
|
||||
}
|
||||
|
||||
func CountOutGivingLogByWorkspaceId(workspaceId string) (int64, error) {
|
||||
var result int64
|
||||
tx := model.DB().Table(NewOutGivingLog().TableName()).Where("workspace_id = ?", workspaceId).Count(&result)
|
||||
if tx.Error != nil {
|
||||
return 0, tx.Error
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// DeleteOutGivingLogByWorkspaceId
|
||||
func DeleteOutGivingLogByWorkspaceId(workspaceId string) error {
|
||||
return model.DB().Table(NewOutGivingLog().TableName()).Where("workspace_id = ?", workspaceId).Delete(&OutGivingLog{}).Error
|
||||
}
|
305
server/internal/model/app_manage/out_giving/out_giving_model.go
Normal file
305
server/internal/model/app_manage/out_giving/out_giving_model.go
Normal file
@ -0,0 +1,305 @@
|
||||
package out_giving
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/pkg/file_utils"
|
||||
"gorm.io/gorm"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// 不做任何操作
|
||||
No = 0
|
||||
// 并发重启
|
||||
Restart = 1
|
||||
// 完整顺序重启(有重启失败将结束本次)
|
||||
Order_Must_Restart = 2
|
||||
// 顺序重启(有重启失败将继续)
|
||||
Order_Restart = 3
|
||||
)
|
||||
|
||||
// OutGivingModel 分发实体
|
||||
// 单文件分发或单压缩包分发
|
||||
type OutGivingModel struct {
|
||||
model.BaseWorkspaceModel
|
||||
Group *string `gorm:"column:group" json:"group"`
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
Name string `gorm:"column:name" json:"name"`
|
||||
/**
|
||||
* 分发间隔时间
|
||||
*/
|
||||
IntervalTime int `gorm:"column:interval_time" json:"intervalTime"`
|
||||
/**
|
||||
* 节点下的项目列表
|
||||
*/
|
||||
OutGivingNodeProjectList string `gorm:"column:out_giving_node_project_list" json:"outGivingNodeProjectList"`
|
||||
/**
|
||||
* 分发后的操作
|
||||
*/
|
||||
AfterOpt int `gorm:"column:after_opt" json:"afterOpt"`
|
||||
/**
|
||||
* 是否清空旧包发布
|
||||
*/
|
||||
ClearOld bool `gorm:"column:clear_old" json:"clearOld"`
|
||||
/**
|
||||
* 是否为单独创建的分发项目
|
||||
*/
|
||||
OutGivingProject bool `gorm:"column:out_giving_project" json:"outGivingProject"`
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
Status int `gorm:"column:status" json:"status"`
|
||||
/**
|
||||
* 二级目录,LevelName
|
||||
*/
|
||||
SecondaryDirectory *string `gorm:"column:secondary_directory" json:"secondaryDirectory"`
|
||||
/**
|
||||
* 保存项目文件前先关闭
|
||||
*/
|
||||
UploadCloseFirst bool `gorm:"column:upload_close_first" json:"uploadCloseFirst"`
|
||||
/**
|
||||
* 状态消息
|
||||
*/
|
||||
StatusMsg string `gorm:"column:status_msg" json:"statusMsg"`
|
||||
/**
|
||||
* 构建发布状态通知
|
||||
*/
|
||||
Webhook string `gorm:"column:webhook" json:"webhook"`
|
||||
}
|
||||
|
||||
// TableName sets the table name for GORM
|
||||
func (*OutGivingModel) TableName() string {
|
||||
return "sched_out_giving"
|
||||
}
|
||||
|
||||
func NewOutGivingModel() *OutGivingModel {
|
||||
n := &OutGivingModel{}
|
||||
n.Handler = n
|
||||
return n
|
||||
}
|
||||
|
||||
func (o *OutGivingModel) FindResult(db *gorm.DB) (interface{}, error) {
|
||||
var result []OutGivingModel
|
||||
if db == nil {
|
||||
return result, nil
|
||||
}
|
||||
err := db.Find(&result).Error
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (o *OutGivingModel) Page(page *model.Page[OutGivingModel], fields map[string]interface{}) error {
|
||||
query := model.DB()
|
||||
if fields != nil {
|
||||
//query = query.Where(fields)
|
||||
for key := range fields {
|
||||
value := fields[key]
|
||||
switch value.(type) {
|
||||
case []string, []int, []int64, []interface{}:
|
||||
query = query.Where(key+" in (?)", value)
|
||||
default:
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
err := page.SelectPages(query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 查询所有分发模型
|
||||
func ListOutGivingModel() []OutGivingModel {
|
||||
var outGivingModel []OutGivingModel
|
||||
model.DB().Table(NewOutGivingModel().TableName()).Find(&outGivingModel)
|
||||
return outGivingModel
|
||||
}
|
||||
|
||||
// 根据Id 查询OutGivingModel
|
||||
func GetOutGivingModelById(id string) *OutGivingModel {
|
||||
var outGivingModel OutGivingModel
|
||||
model.DB().Table(NewOutGivingModel().TableName()).Where("id = ?", id).First(&outGivingModel)
|
||||
return &outGivingModel
|
||||
}
|
||||
|
||||
// 根据Id和WorkspaceId删除OutGivingModel,并返回受影响行数
|
||||
func DeleteOutGivingModelById(id string) (int64, error) {
|
||||
tx := model.DB().Table(NewOutGivingModel().TableName()).Where("id = ?", id).Delete(&OutGivingModel{})
|
||||
return tx.RowsAffected, tx.Error
|
||||
}
|
||||
|
||||
// 更新分发模型
|
||||
func UpdateOutGivingModel(outGivingModel *OutGivingModel, updateFields []string) error {
|
||||
return model.DB().Table(NewOutGivingModel().TableName()).Where("id = ?", outGivingModel.Id).Select(updateFields).Updates(outGivingModel).Error
|
||||
}
|
||||
|
||||
// ListByWorkspace 根据Workspace查询OutGivingModel
|
||||
func ListOutGivingModelByWorkspace(workspaceId string) []OutGivingModel {
|
||||
var outGivingModel []OutGivingModel
|
||||
model.DB().Table(NewOutGivingModel().TableName()).Where("workspace_id = ?", workspaceId).Find(&outGivingModel)
|
||||
return outGivingModel
|
||||
}
|
||||
|
||||
// 更新分发模型,将状态为out_giving.DONE的状态改为out_giving.ING
|
||||
func UpdateOutGivingModelStatus(oldStatus int, newStatus int) (int64, error) {
|
||||
updateSql := `UPDATE ` + NewOutGivingModel().TableName() + ` SET status=? WHERE status=?`
|
||||
tx := model.DB().Table(NewOutGivingModel().TableName()).Exec(updateSql, newStatus, oldStatus)
|
||||
return tx.RowsAffected, tx.Error
|
||||
}
|
||||
|
||||
// 指定workspaceId, nodeId,计算符合条件的项目数
|
||||
func ExistsOutGivingModel(workspaceId, nodeId string) (bool, error) {
|
||||
var result int64
|
||||
tx := model.DB().Table(NewOutGivingModel().TableName()).Where("workspace_id = ? and node_id = ?", workspaceId, nodeId).Count(&result)
|
||||
if tx.Error != nil {
|
||||
return false, tx.Error
|
||||
}
|
||||
return result > 0, nil
|
||||
}
|
||||
|
||||
func CountOutGivingModelByWorkspaceId(workspaceId string) (int64, error) {
|
||||
var result int64
|
||||
tx := model.DB().Table(NewOutGivingModel().TableName()).Where("workspace_id = ?", workspaceId).Count(&result)
|
||||
if tx.Error != nil {
|
||||
return 0, tx.Error
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
|
||||
// SetSecondaryDirectory validates and sets the secondary directory
|
||||
func (o *OutGivingModel) SetSecondaryDirectory(secondaryDirectory string) error {
|
||||
if secondaryDirectory != "" {
|
||||
err := file_utils.CheckFilePathSlip(secondaryDirectory)
|
||||
if err != nil {
|
||||
return fmt.Errorf("二级目录不能越级: %w", err)
|
||||
}
|
||||
}
|
||||
space := strings.TrimSpace(secondaryDirectory)
|
||||
o.SecondaryDirectory = &space
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetOutGivingNodeProjectList converts the list string to a slice of OutGivingNodeProject
|
||||
func (o *OutGivingModel) GetOutGivingNodeProjectList() []OutGivingNodeProject {
|
||||
return o.GetOutGivingNodeProjectListBySelect("")
|
||||
}
|
||||
|
||||
// GetOutGivingNodeProjectListBySelect filters and sorts the list
|
||||
func (o *OutGivingModel) GetOutGivingNodeProjectListBySelect(selectStr string) []OutGivingNodeProject {
|
||||
var outGivingNodeProjects []OutGivingNodeProject
|
||||
bytes := []byte(o.OutGivingNodeProjectList)
|
||||
err := json.Unmarshal(bytes, &outGivingNodeProjects)
|
||||
if err != nil {
|
||||
return outGivingNodeProjects
|
||||
}
|
||||
|
||||
if outGivingNodeProjects == nil {
|
||||
return outGivingNodeProjects
|
||||
}
|
||||
list := strings.Split(strings.TrimSpace(selectStr), ",")
|
||||
for i := range outGivingNodeProjects {
|
||||
if outGivingNodeProjects[i].SortValue != nil {
|
||||
if outGivingNodeProjects[i].SortValue == nil {
|
||||
outGivingNodeProjects[i].SortValue = &i
|
||||
}
|
||||
}
|
||||
}
|
||||
filteredProjects := filterAndSortProjects(outGivingNodeProjects, list)
|
||||
return filteredProjects
|
||||
}
|
||||
|
||||
// filterAndSortProjects filters projects based on the selection and sorts them
|
||||
func filterAndSortProjects(projects []OutGivingNodeProject, selection []string) []OutGivingNodeProject {
|
||||
if len(selection) == 0 {
|
||||
return projects
|
||||
}
|
||||
selectedProjects := projects[:0]
|
||||
for _, project := range projects {
|
||||
projectKey := fmt.Sprintf("%s@%s", project.ProjectId, project.NodeId)
|
||||
if contains(selection, projectKey) {
|
||||
selectedProjects = append(selectedProjects, project)
|
||||
}
|
||||
}
|
||||
//sortedProjects := sortProjects(selectedProjects)
|
||||
return selectedProjects
|
||||
}
|
||||
|
||||
// contains checks if the selection contains the given key
|
||||
func contains(selection []string, key string) bool {
|
||||
for _, s := range selection {
|
||||
if s == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
if s == key {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// sortProjects sorts projects by their sort value
|
||||
func sortProjects(projects []OutGivingNodeProject) []OutGivingNodeProject {
|
||||
sort.SliceStable(projects, func(i, j int) bool {
|
||||
return *projects[i].SortValue < *projects[j].SortValue
|
||||
})
|
||||
|
||||
return projects
|
||||
}
|
||||
|
||||
// SetOutGivingNodeProjectList updates the list string from a slice of OutGivingNodeProject
|
||||
func (o *OutGivingModel) SetOutGivingNodeProjectList(outGivingNodeProjects []OutGivingNodeProject) {
|
||||
if outGivingNodeProjects == nil {
|
||||
o.OutGivingNodeProjectList = ""
|
||||
} else {
|
||||
marshal, err := json.Marshal(outGivingNodeProjects)
|
||||
if err != nil {
|
||||
o.OutGivingNodeProjectList = ""
|
||||
return
|
||||
}
|
||||
o.OutGivingNodeProjectList = string(marshal)
|
||||
}
|
||||
}
|
||||
|
||||
// CheckContains checks if the model contains a project with the given node and project IDs
|
||||
// 判断是否包含某个项目id
|
||||
func (o *OutGivingModel) CheckContains(nodeId, projectId string) bool {
|
||||
nodeProjectList := o.GetOutGivingNodeProjectList()
|
||||
project := o.GetNodeProject(nodeProjectList, nodeId, projectId)
|
||||
return project != nil
|
||||
}
|
||||
|
||||
// GetNodeProject gets a project from the list with the given node and project IDs
|
||||
// 从指定数组中获取对应信息
|
||||
func (o *OutGivingModel) GetNodeProject(projects []OutGivingNodeProject, nodeId, projectId string) *OutGivingNodeProject {
|
||||
for _, project := range projects {
|
||||
if strings.EqualFold(project.NodeId, nodeId) && strings.EqualFold(project.ProjectId, projectId) {
|
||||
return &project
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDelete compares the old and new projects and returns deleted ones
|
||||
func (o *OutGivingModel) GetDelete(newProjects []OutGivingNodeProject) []OutGivingNodeProject {
|
||||
oldProjects := o.GetOutGivingNodeProjectList()
|
||||
if oldProjects == nil || len(oldProjects) == 0 {
|
||||
return nil
|
||||
}
|
||||
var deletedProjects []OutGivingNodeProject
|
||||
// 如果在newsProject中不存在,则将该节点项目添加到delete列表中
|
||||
for _, oldProject := range oldProjects {
|
||||
if o.GetNodeProject(newProjects, oldProject.NodeId, oldProject.ProjectId) != nil {
|
||||
continue
|
||||
}
|
||||
deletedProjects = append(deletedProjects, oldProject)
|
||||
}
|
||||
return deletedProjects
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package out_giving
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestOutGivingModel_GetOutGivingNodeProjectListBySelect(t *testing.T) {
|
||||
list := strings.Split("", ",")
|
||||
fmt.Print(list)
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package out_giving
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// OutGivingNodeProject 结构体扩展了BaseNodeProject,包含了排序值和是否禁用的字段
|
||||
type OutGivingNodeProject struct {
|
||||
NodeId string `json:"nodeId"`
|
||||
ProjectId string `json:"projectId"`
|
||||
SortValue *int `json:"sortValue"`
|
||||
Disabled bool `json:"disabled,omitempty"`
|
||||
}
|
||||
|
||||
// GetDisabled 返回默认禁用状态,如果Disabled为nil,则返回false
|
||||
func (o *OutGivingNodeProject) GetDisabled() bool {
|
||||
// 如果Disabled为nil,则返回false,其他情况返回Disabled的值
|
||||
if o.Disabled != true {
|
||||
return false
|
||||
}
|
||||
return o.Disabled
|
||||
}
|
||||
|
||||
func (o *OutGivingNodeProject) FindResult(db *gorm.DB) (interface{}, error) {
|
||||
var result []OutGivingNodeProject
|
||||
if db == nil {
|
||||
return result, nil
|
||||
}
|
||||
err := db.Find(&result).Error
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (o *OutGivingNodeProject) Page(page *model.Page[OutGivingNodeProject], fields map[string]interface{}) error {
|
||||
query := model.DB()
|
||||
if fields != nil {
|
||||
//query = query.Where(fields)
|
||||
for key := range fields {
|
||||
value := fields[key]
|
||||
switch value.(type) {
|
||||
case []string, []int, []int64, []interface{}:
|
||||
query = query.Where(key+" in (?)", value)
|
||||
default:
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
err := page.SelectPages(query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
23
server/internal/model/app_manage/out_giving/status/status.go
Normal file
23
server/internal/model/app_manage/out_giving/status/status.go
Normal file
@ -0,0 +1,23 @@
|
||||
package status
|
||||
|
||||
// Status 枚举表示状态
|
||||
type Status int
|
||||
|
||||
const (
|
||||
// NO 未分发
|
||||
NO = 0
|
||||
// ING 分发中
|
||||
ING = 1
|
||||
// 分发成功
|
||||
Ok = 2
|
||||
// DONE 分发结束
|
||||
DONE = 2
|
||||
// CANCEL 已取消 // 系统取消分发
|
||||
CANCEL = 3
|
||||
// FAIL 分发失败
|
||||
FAIL = 4
|
||||
// 准备分发
|
||||
Prepare = 5
|
||||
// 手动取消分发
|
||||
ArtificialCancel = 6
|
||||
)
|
160
server/internal/model/app_manage/project_info/project_info.go
Normal file
160
server/internal/model/app_manage/project_info/project_info.go
Normal file
@ -0,0 +1,160 @@
|
||||
package project_info
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"github.com/araujo88/lambda-go/pkg/core"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type ProjectInfo struct {
|
||||
model.BaseWorkspaceModel
|
||||
ProjectId string `gorm:"column:project_id" json:"projectId"`
|
||||
NodeId string `gorm:"column:node_id" json:"nodeId"`
|
||||
Name string `gorm:"column:name" json:"name"`
|
||||
Lib string `gorm:"column:lib" json:"lib"`
|
||||
WhitelistDirectory string `gorm:"column:whitelist_directory" json:"whitelistDirectory"`
|
||||
LogPath string `gorm:"column:log_path" json:"logPath"`
|
||||
Jvm string `gorm:"column:jvm" json:"jvm"`
|
||||
Args string `gorm:"column:args" json:"args"`
|
||||
Token string `gorm:"column:token" json:"token"`
|
||||
RunMode string `gorm:"column:run_mode" json:"runMode"`
|
||||
OutGivingProject bool `gorm:"column:out_giving_project" json:"outGivingProject"`
|
||||
//SortValue string `gorm:"column:sort_value" json:"sortValue"`
|
||||
TriggerToken string `gorm:"column:trigger_token" json:"triggerToken"`
|
||||
Group *string `gorm:"column:group" json:"group"`
|
||||
DslContent string `gorm:"column:dsl_content" json:"dslContent"`
|
||||
DslEnv string `gorm:"column:dsl_env" json:"dslEnv"`
|
||||
AutoStart bool `gorm:"column:auto_start" json:"autoStart"`
|
||||
NodeName string `gorm:"column:node_name" json:"nodeName"`
|
||||
WorkspaceName string `gorm:"column:workspace_name" json:"workspaceName"`
|
||||
}
|
||||
|
||||
func New() *ProjectInfo {
|
||||
n := &ProjectInfo{}
|
||||
n.Handler = n
|
||||
return n
|
||||
}
|
||||
|
||||
func (*ProjectInfo) TableName() string {
|
||||
return "sched_project_info"
|
||||
}
|
||||
|
||||
// 删除所有项目
|
||||
func ClearAll() (int64, error) {
|
||||
return model.DB().Where("1 = 1").Delete(&ProjectInfo{}).RowsAffected, nil
|
||||
}
|
||||
|
||||
// 根据Id删除项目
|
||||
func DeleteProjectById(id string) (int64, error) {
|
||||
return model.DB().Where("id = ?", id).Delete(&ProjectInfo{}).RowsAffected, nil
|
||||
}
|
||||
|
||||
// 根据Id查询项目
|
||||
func GetProjectById(id string) (ProjectInfo, error) {
|
||||
var project ProjectInfo
|
||||
err := model.DB().Where("id = ?", id).First(&project).Error
|
||||
return project, err
|
||||
}
|
||||
|
||||
// 根据Id批量查询项目
|
||||
func GetProjectByIds(ids []string) []ProjectInfo {
|
||||
var projects []ProjectInfo
|
||||
model.DB().Where("id in (?)", ids).Find(&projects)
|
||||
return projects
|
||||
}
|
||||
|
||||
// 根据nodeId和workspace_id删除项目
|
||||
func DeleteProjectByNodeIdAndWorkspaceId(nodeId, workspaceId string) (int64, error) {
|
||||
return model.DB().Where("node_id = ? and workspace_id = ?", nodeId, workspaceId).Delete(&ProjectInfo{}).RowsAffected, nil
|
||||
}
|
||||
|
||||
// 根据nodeId删除项目
|
||||
func DeleteProjectByNodeId(nodeId string) (int64, error) {
|
||||
return model.DB().Where("node_id = ?", nodeId).Delete(&ProjectInfo{}).RowsAffected, nil
|
||||
}
|
||||
|
||||
// 根据nodeId查询项目
|
||||
func GetProjectByNodeId(nodeId string) ([]ProjectInfo, error) {
|
||||
var result []ProjectInfo
|
||||
err := model.DB().Table(New().TableName()).Table(New().TableName()).Where("node_id = ?", nodeId).Find(&result).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 指定workspaceId, nodeId,计算符合条件的项目数
|
||||
func Exists_1(workspaceId, nodeId string) (bool, error) {
|
||||
var result int64
|
||||
tx := model.DB().Table(New().TableName()).Where("workspace_id = ? and node_id = ?", workspaceId, nodeId).Count(&result)
|
||||
if tx.Error != nil {
|
||||
return false, tx.Error
|
||||
}
|
||||
return result > 0, nil
|
||||
|
||||
}
|
||||
|
||||
// 指定workspaceId, nodeId, projectId,计算符合条件的项目数
|
||||
func Exists(workspaceId, nodeId, projectId string) (bool, error) {
|
||||
var result int64
|
||||
tx := model.DB().Table(New().TableName()).Where("workspace_id = ? and node_id = ? and project_id = ?", workspaceId, nodeId, projectId).Count(&result)
|
||||
if tx.Error != nil {
|
||||
return false, tx.Error
|
||||
}
|
||||
return result > 0, nil
|
||||
}
|
||||
|
||||
// 指定Id,计算符合条件的项目数
|
||||
func ExistsById(id string) (bool, error) {
|
||||
var result int64
|
||||
tx := model.DB().Table(New().TableName()).Where("id = ?", id).Count(&result)
|
||||
if tx.Error != nil {
|
||||
return false, tx.Error
|
||||
}
|
||||
return result > 0, nil
|
||||
}
|
||||
|
||||
func (p *ProjectInfo) ListGroup() ([]string, error) {
|
||||
var result []sql.NullString
|
||||
tx := model.DB().Table(p.TableName()).Select("\"group\"").Distinct().Scan(&result)
|
||||
if len(result) > 0 {
|
||||
us := core.Map(result, func(s sql.NullString) string {
|
||||
if s.Valid {
|
||||
return s.String
|
||||
}
|
||||
return ""
|
||||
})
|
||||
return us, tx.Error
|
||||
}
|
||||
return []string{}, tx.Error
|
||||
}
|
||||
|
||||
func (p *ProjectInfo) CreateOrUpdate() (err error) {
|
||||
_, err = p.Create(p)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
_, err = p.Update(p, nil)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *ProjectInfo) FindResult(db *gorm.DB) (interface{}, error) {
|
||||
var result []ProjectInfo
|
||||
if db == nil {
|
||||
return result, nil
|
||||
}
|
||||
err := db.Find(&result).Error
|
||||
return result, err
|
||||
}
|
||||
|
||||
// 根据工作空间(WorkspaceId)计算项目数量
|
||||
func CountProjectByWorkspaceId(workspaceId string) (int64, error) {
|
||||
var result int64
|
||||
tx := model.DB().Table(New().TableName()).Where("workspace_id = ?", workspaceId).Count(&result)
|
||||
if tx.Error != nil {
|
||||
return 0, tx.Error
|
||||
}
|
||||
return result, nil
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
package script_info
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// 脚本模版实体 对应NodeScriptCacheModel
|
||||
type NodeScriptCacheModel struct {
|
||||
model.BaseWorkspaceModel
|
||||
ScriptId string `gorm:"column:script_id" json:"scriptId"`
|
||||
Name string `gorm:"column:name" json:"name"`
|
||||
LastRunUser string `gorm:"column:last_run_user" json:"lastRunUser"`
|
||||
AutoExecCron string `gorm:"column:auto_exec_cron" json:"autoExecCron"`
|
||||
DefArgs string `gorm:"column:def_args" json:"defArgs"`
|
||||
Description string `gorm:"column:description" json:"description"`
|
||||
ScriptType string `gorm:"column:script_type" json:"scriptType"`
|
||||
TriggerToken string `gorm:"column:trigger_token" json:"trigger_token"`
|
||||
NodeId string `gorm:"column:node_id" json:"nodeId"`
|
||||
NodeName string `gorm:"column:node_name" json:"nodeName"`
|
||||
WorkspaceName string `gorm:"column:workspace_name" json:"workspaceName"`
|
||||
}
|
||||
|
||||
func NewNodeScriptCacheModel() *NodeScriptCacheModel {
|
||||
n := &NodeScriptCacheModel{}
|
||||
n.Handler = n
|
||||
return n
|
||||
}
|
||||
|
||||
func (*NodeScriptCacheModel) TableName() string {
|
||||
return "sched_script_info"
|
||||
}
|
||||
|
||||
func (s *NodeScriptCacheModel) ListGroup() ([]string, error) {
|
||||
var result []string
|
||||
tx := model.DB().Table(s.TableName()).Select("\"group\"").Distinct().Scan(&result)
|
||||
return result, tx.Error
|
||||
}
|
||||
|
||||
func (s *NodeScriptCacheModel) CreateOrUpdate() (err error) {
|
||||
_, err = s.Create(s)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
_, err = s.Update(s, nil)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 根据Id删除脚本
|
||||
func DeleteNodeScriptById(id string) (int64, error) {
|
||||
tx := model.DB().Table(NewNodeScriptCacheModel().TableName()).Where("id = ?", id).Delete(&NodeScriptCacheModel{})
|
||||
return tx.RowsAffected, tx.Error
|
||||
}
|
||||
|
||||
// 根据nodeId删除脚本
|
||||
func DeleteNodeScriptByNodeId(nodeId string) (int64, error) {
|
||||
tx := model.DB().Table(NewNodeScriptCacheModel().TableName()).Where("node_id = ?", nodeId).Delete(&NodeScriptCacheModel{})
|
||||
return tx.RowsAffected, tx.Error
|
||||
}
|
||||
|
||||
// 根据nodeId查询脚本
|
||||
func GetNodeScriptByNodeId(nodeId string) ([]NodeScriptCacheModel, error) {
|
||||
var result []NodeScriptCacheModel
|
||||
tx := model.DB().Table(NewNodeScriptCacheModel().TableName()).Where("node_id = ?", nodeId).Find(&result)
|
||||
return result, tx.Error
|
||||
}
|
||||
|
||||
// 根据Id查询脚本
|
||||
func GetNodeScriptById(id string) (NodeScriptCacheModel, error) {
|
||||
var result NodeScriptCacheModel
|
||||
tx := model.DB().Table(NewNodeScriptCacheModel().TableName()).Where("id = ?", id).First(&result)
|
||||
return result, tx.Error
|
||||
}
|
||||
|
||||
// 根据IdworkspaceId删除脚本
|
||||
func DeleteNodeScriptByIdAndWorkspaceId(id, workspaceId string) (int64, error) {
|
||||
tx := model.DB().Table(NewNodeScriptCacheModel().TableName()).Where("id = ? and workspace_id = ?", id, workspaceId).Delete(&NodeScriptCacheModel{})
|
||||
return tx.RowsAffected, tx.Error
|
||||
}
|
||||
|
||||
// 根据NodeId和workspaceId删除脚本
|
||||
func DeleteNodeScriptByNodeIdAndWorkspaceId(nodeId, workspaceId string) (int64, error) {
|
||||
tx := model.DB().Table(NewNodeScriptCacheModel().TableName()).Where("node_id = ? and workspace_id = ?", nodeId, workspaceId).Delete(&NodeScriptCacheModel{})
|
||||
return tx.RowsAffected, tx.Error
|
||||
}
|
||||
|
||||
// 删除所有脚本
|
||||
func DeleteAllNodeScript() (int64, error) {
|
||||
tx := model.DB().Table(NewNodeScriptCacheModel().TableName()).Where("1 = 1").Delete(&NodeScriptCacheModel{})
|
||||
return tx.RowsAffected, tx.Error
|
||||
}
|
||||
|
||||
// 批量保存脚本
|
||||
func SaveNodeScript(scripts []NodeScriptCacheModel) (int64, error) {
|
||||
tx := model.DB().Table(NewNodeScriptCacheModel().TableName()).CreateInBatches(scripts, 100)
|
||||
return tx.RowsAffected, tx.Error
|
||||
}
|
||||
|
||||
func (s *NodeScriptCacheModel) FindResult(db *gorm.DB) (interface{}, error) {
|
||||
var result []NodeScriptCacheModel
|
||||
if db == nil {
|
||||
return result, nil
|
||||
}
|
||||
err := db.Find(&result).Error
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *NodeScriptCacheModel) HasScriptNode() ([]string, error) {
|
||||
var nodeIds = make([]string, 0)
|
||||
tx := model.DB().Table(s.TableName()).Select("node_id").Distinct().Scan(&nodeIds)
|
||||
if tx.Error != nil {
|
||||
return nodeIds, tx.Error
|
||||
}
|
||||
return nodeIds, nil
|
||||
}
|
||||
|
||||
// 指定workspaceId, nodeId,计算符合条件的项目数
|
||||
func ExistsNodeScriptCacheModel(workspaceId, nodeId string) (bool, error) {
|
||||
var result int64
|
||||
tx := model.DB().Table(NewNodeScriptCacheModel().TableName()).Where("workspace_id = ? and node_id = ?", workspaceId, nodeId).Count(&result)
|
||||
if tx.Error != nil {
|
||||
return false, tx.Error
|
||||
}
|
||||
return result > 0, nil
|
||||
|
||||
}
|
||||
|
||||
func CountNodeScriptByWorkspaceId(workspaceId string) (int64, error) {
|
||||
var result int64
|
||||
tx := model.DB().Table(NewNodeScriptCacheModel().TableName()).Where("workspace_id = ?", workspaceId).Count(&result)
|
||||
if tx.Error != nil {
|
||||
return 0, tx.Error
|
||||
}
|
||||
return result, nil
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
package script_info
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/secure"
|
||||
"gorm.io/gorm"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// NodeScriptExecuteLogCacheModel 结构体
|
||||
type NodeScriptExecuteLogCacheModel struct {
|
||||
model.BaseNodeModel // 继承自 BaseNodeModel
|
||||
|
||||
// 使用 GORM 标签映射字段到数据库列
|
||||
Name string `gorm:"-" json:"name"` // 不会映射到数据库,因为有PropIgnore注解
|
||||
ScriptId string `gorm:"column:script_id" json:"scriptId"`
|
||||
ScriptName string `gorm:"column:script_name" json:"scriptName"`
|
||||
|
||||
// 触发类型 {0,手动,1 自动触发}
|
||||
TriggerExecType int `gorm:"column:trigger_exec_type" json:"triggerExecType"`
|
||||
}
|
||||
|
||||
// 实现 fullId 方法
|
||||
func (n *NodeScriptExecuteLogCacheModel) fullId() string {
|
||||
encrypt := secure.Sha1Encrypt(n.WorkspaceId + n.NodeId + n.ScriptId)
|
||||
return encrypt
|
||||
}
|
||||
|
||||
// SetName 方法
|
||||
func (n *NodeScriptExecuteLogCacheModel) SetName(name string) {
|
||||
n.Name = name
|
||||
n.ScriptName = name
|
||||
}
|
||||
|
||||
// SetScriptName 方法
|
||||
func (n *NodeScriptExecuteLogCacheModel) SetScriptName(scriptName string) {
|
||||
n.ScriptName = scriptName
|
||||
n.Name = scriptName
|
||||
}
|
||||
|
||||
func NewNodeScriptExecuteLogCacheModel() *NodeScriptExecuteLogCacheModel {
|
||||
n := &NodeScriptExecuteLogCacheModel{}
|
||||
n.Handler = n
|
||||
return n
|
||||
}
|
||||
|
||||
func (*NodeScriptExecuteLogCacheModel) TableName() string {
|
||||
return "sched_script_execute_log"
|
||||
}
|
||||
|
||||
func (n *NodeScriptExecuteLogCacheModel) FindResult(db *gorm.DB) (interface{}, error) {
|
||||
var result []NodeScriptExecuteLogCacheModel
|
||||
if db == nil {
|
||||
return result, nil
|
||||
}
|
||||
err := db.Find(&result).Error
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Page 可以使用类似 {"age >": 30} 这样的字段映射来过滤年龄大于30的结果
|
||||
func (n *NodeScriptExecuteLogCacheModel) Page(page *model.Page[NodeScriptExecuteLogCacheModel], fields map[string]interface{}) error {
|
||||
query := model.DB()
|
||||
if fields != nil {
|
||||
for key := range fields {
|
||||
value := fields[key]
|
||||
switch value.(type) {
|
||||
case []string, []int, []int64, []interface{}:
|
||||
query = query.Where(key+" in (?)", value)
|
||||
default:
|
||||
// 支持模糊查询
|
||||
if strings.Contains(key, "%") {
|
||||
kk := strings.ReplaceAll(key, "%", "")
|
||||
query = query.Where(kk+" like ?", "%"+value.(string)+"%")
|
||||
continue
|
||||
}
|
||||
|
||||
// 检查字段是否包含操作符
|
||||
if strings.Contains(key, ">") || strings.Contains(key, "<") {
|
||||
// 分割字段名和操作符
|
||||
parts := strings.Split(key, " ")
|
||||
if len(parts) == 2 {
|
||||
field := parts[0]
|
||||
op := parts[1]
|
||||
switch op {
|
||||
case ">":
|
||||
query = query.Where(field+" > ?", value)
|
||||
case "<":
|
||||
query = query.Where(field+" < ?", value)
|
||||
default:
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
} else {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
} else {
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
err := page.SelectPages(query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 根据ids批量删除NodeScriptExecuteLogCacheModel
|
||||
func DeleteNodeScriptExecuteLogByIds(ids []string) (int64, error) {
|
||||
return model.DB().Where("id in (?)", ids).Delete(&NodeScriptExecuteLogCacheModel{}).RowsAffected, nil
|
||||
}
|
||||
|
||||
// 根据Id和 []workspace 数组获取脚本
|
||||
func GetNodeScriptExecuteLogByIdAndWorkspaceIds(id string, workspaceIds []string) (NodeScriptExecuteLogCacheModel, error) {
|
||||
var script NodeScriptExecuteLogCacheModel
|
||||
err := model.DB().Where("id = ? and workspace_id in (?)", id, workspaceIds).First(&script).Error
|
||||
return script, err
|
||||
}
|
||||
|
||||
// 根据Id workspaceId删除脚本
|
||||
func DeleteNodeScriptExecuteLogByIdAndWorkspaceIds(id string, workspaceIds []string) (int64, error) {
|
||||
var script NodeScriptExecuteLogCacheModel
|
||||
tx := model.DB().Where("id = ? and workspace_id in (?)", id, workspaceIds).Delete(&script)
|
||||
if tx.Error != nil {
|
||||
return 0, tx.Error
|
||||
}
|
||||
return tx.RowsAffected, nil
|
||||
}
|
||||
|
||||
// 根据NodeId workspaceId删除脚本
|
||||
func DeleteNodeScriptExecuteLogByNodeIdAndWorkspaceIds(nodeId string, workspaceIds []string) (int64, error) {
|
||||
var script NodeScriptExecuteLogCacheModel
|
||||
tx := model.DB().Where("node_id = ? and workspace_id in (?)", nodeId, workspaceIds).Delete(&script)
|
||||
if tx.Error != nil {
|
||||
return 0, tx.Error
|
||||
}
|
||||
return tx.RowsAffected, nil
|
||||
}
|
||||
|
||||
func CountNodeScriptExecuteLogByWorkspaceId(workspaceId string) (int64, error) {
|
||||
var result int64
|
||||
tx := model.DB().Table(NewNodeScriptExecuteLogCacheModel().TableName()).Where("workspace_id = ?", workspaceId).Count(&result)
|
||||
if tx.Error != nil {
|
||||
return 0, tx.Error
|
||||
}
|
||||
return result, nil
|
||||
}
|
@ -0,0 +1,154 @@
|
||||
package script_info
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/command_utils"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/utils"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/utils/file_utils"
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// ScriptModel represents the script template model in the database.
|
||||
type ScriptModel struct {
|
||||
model.BaseWorkspaceModel
|
||||
|
||||
Name string `gorm:"column:name" json:"name"`
|
||||
LastRunUser string `gorm:"column:last_run_user" json:"lastRunUser"`
|
||||
AutoExecCron string `gorm:"column:auto_exec_cron" json:"autoExecCron"`
|
||||
DefArgs string `gorm:"column:def_args" json:"defArgs"`
|
||||
Description string `gorm:"column:description" json:"description"`
|
||||
|
||||
Context string `gorm:"column:context" json:"context"`
|
||||
NodeIds string `gorm:"column:node_ids" json:"nodeIds"`
|
||||
TriggerToken string `gorm:"column:trigger_token" json:"triggerToken"`
|
||||
}
|
||||
|
||||
func NewScriptModel() *ScriptModel {
|
||||
n := &ScriptModel{}
|
||||
n.Handler = n
|
||||
return n
|
||||
}
|
||||
|
||||
func (*ScriptModel) TableName() string {
|
||||
return "sched_server_script_info"
|
||||
}
|
||||
|
||||
func (s *ScriptModel) FindResult(db *gorm.DB) (interface{}, error) {
|
||||
var result []ScriptModel
|
||||
if db == nil {
|
||||
return result, nil
|
||||
}
|
||||
err := db.Find(&result).Error
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *ScriptModel) Page(page *model.Page[ScriptModel], fields map[string]interface{}) error {
|
||||
query := model.DB()
|
||||
if fields != nil {
|
||||
for key := range fields {
|
||||
value := fields[key]
|
||||
switch value.(type) {
|
||||
case []string, []int, []int64, []interface{}:
|
||||
query = query.Where(key+" in (?)", value)
|
||||
default:
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
err := page.SelectPages(query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 根据查询条件获取单个脚本(First),如果没有则返回空
|
||||
func GetServerScriptModel(fields map[string]interface{}) (ScriptModel, error) {
|
||||
var script ScriptModel
|
||||
err := model.DB().Where(fields).First(&script).Error
|
||||
return script, err
|
||||
}
|
||||
|
||||
// 根据Id和获取脚本
|
||||
func GetServerScriptModelById(id string) (ScriptModel, error) {
|
||||
var script ScriptModel
|
||||
err := model.DB().Where("id = ?", id).First(&script).Error
|
||||
return script, err
|
||||
}
|
||||
|
||||
// 根据Id和 []workspace 数组获取脚本
|
||||
func GetServerScriptModelByIdAndWorkspaceIds(id string, workspaceIds []string) (ScriptModel, error) {
|
||||
var script ScriptModel
|
||||
err := model.DB().Where("id = ? and workspace_id in (?)", id, workspaceIds).First(&script).Error
|
||||
return script, err
|
||||
}
|
||||
|
||||
// 根据Id和 []workspace 数组删除脚本
|
||||
func DeleteServerScriptByIdAndWorkspaceIds(id string, workspaceIds []string) (int64, error) {
|
||||
var script ScriptModel
|
||||
tx := model.DB().Where("id = ? and workspace_id in (?)", id, workspaceIds).Delete(&script)
|
||||
if tx.Error != nil {
|
||||
return 0, tx.Error
|
||||
}
|
||||
return tx.RowsAffected, nil
|
||||
}
|
||||
|
||||
// 根据Id更新脚本
|
||||
func UpdateServerScriptById(id string, fields map[string]interface{}) (int64, error) {
|
||||
tx := model.DB().Model(&ScriptModel{}).Where("id = ?", id).Updates(fields)
|
||||
if tx.Error != nil {
|
||||
return 0, tx.Error
|
||||
}
|
||||
return tx.RowsAffected, nil
|
||||
}
|
||||
|
||||
func CountScriptByWorkspaceId(workspaceId string) (int64, error) {
|
||||
var result int64
|
||||
tx := model.DB().Table(NewScriptModel().TableName()).Where("workspace_id = ?", workspaceId).Count(&result)
|
||||
if tx.Error != nil {
|
||||
return 0, tx.Error
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
/***********************************************/
|
||||
|
||||
// ScriptPath generates the script's path based on its ID.
|
||||
func (s *ScriptModel) ScriptPath() (string, error) {
|
||||
// Implement your logic to get the script path based on your application's setup.
|
||||
// JpomApplication and other dependencies would need to be replaced with Go equivalents.
|
||||
if s.Id == "" {
|
||||
return "", fmt.Errorf("id 为空")
|
||||
}
|
||||
path, err := utils.GetDataPath()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("获取数据目录失败: %v", err)
|
||||
}
|
||||
scriptPath := filepath.Join(path, "script", s.Id)
|
||||
// Return a hypothetical path for demonstration purposes.
|
||||
return scriptPath, nil
|
||||
}
|
||||
|
||||
// LogFilePath generates the log file's path given the script ID and execution ID.
|
||||
func (s *ScriptModel) LogFilePath(executeId string) (string, error) {
|
||||
scriptFolderPath, err := s.ScriptPath()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
scriptLogFilePath := filepath.Join(scriptFolderPath, "log", executeId) + ".log"
|
||||
return scriptLogFilePath, nil
|
||||
}
|
||||
|
||||
func (s *ScriptModel) ScriptFile() (string, error) {
|
||||
dataPath, _ := utils.GetDataPath()
|
||||
fileName := fmt.Sprintf("%s.%s", uuid.New().String(), command_utils.SUFFIX)
|
||||
scriptFile := filepath.Join(dataPath, "script_run_cache", fileName)
|
||||
err := file_utils.WriteScript(s.Context, scriptFile)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return scriptFile, nil
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package server_white_list
|
||||
|
||||
import "path/filepath"
|
||||
|
||||
type ServerWhitelist struct {
|
||||
OutGiving string `json:"outGiving"`
|
||||
//AllowRemoteDownloadHost []string `json:"allowRemoteDownloadHost"`
|
||||
//StaticDir []string `json:"staticDir"`
|
||||
}
|
||||
|
||||
func GetId(workspaceId string) string {
|
||||
return "OUTGIVING_WHITELIST-" + workspaceId
|
||||
}
|
||||
|
||||
// CheckPath 用于判断给定路径是否在白名单列表中
|
||||
func CheckPath(list []string, path string) bool {
|
||||
if list == nil || len(list) == 0 {
|
||||
return false
|
||||
}
|
||||
if path == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
normalizedPath := filepath.Clean(path)
|
||||
|
||||
for _, item := range list {
|
||||
normalizedItem := filepath.Clean(item)
|
||||
if normalizedPath == normalizedItem {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package system_parameters
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
)
|
||||
|
||||
type SystemParameters struct {
|
||||
model.BaseUserModifyDbModel
|
||||
Value string `gorm:"column:value" json:"value"`
|
||||
Description string `gorm:"column:description" json:"description"`
|
||||
}
|
||||
|
||||
func (*SystemParameters) TableName() string {
|
||||
return "sched_system_parameters"
|
||||
}
|
||||
|
||||
func (w *SystemParameters) Page(page *model.Page[SystemParameters], fields map[string]interface{}) error {
|
||||
query := model.DB()
|
||||
if fields != nil {
|
||||
//query = query.Where(fields)
|
||||
for key := range fields {
|
||||
value := fields[key]
|
||||
switch value.(type) {
|
||||
case []string, []int, []int64, []interface{}:
|
||||
query = query.Where(key+" in (?)", value)
|
||||
default:
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
err := page.SelectPages(query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
71
server/internal/model/app_manage/workspace/workspace.go
Normal file
71
server/internal/model/app_manage/workspace/workspace.go
Normal file
@ -0,0 +1,71 @@
|
||||
package workspace
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"github.com/araujo88/lambda-go/pkg/core"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Workspace struct {
|
||||
model.BaseUserModifyDbModel
|
||||
Name string `gorm:"column:name" json:"name"` //type:string comment:名称 version:2024-02-12 14:22
|
||||
Description string `gorm:"column:description" json:"description"` //type:string comment:描述 version:2024-02-12 14:22
|
||||
Group *string `gorm:"column:group" json:"group"` //type:string comment:分组 version:2024-02-12 14:22
|
||||
}
|
||||
|
||||
func New() *Workspace {
|
||||
w := &Workspace{}
|
||||
w.Handler = w
|
||||
return w
|
||||
}
|
||||
|
||||
// 说明:
|
||||
func (*Workspace) TableName() string {
|
||||
return "sched_workspace"
|
||||
}
|
||||
|
||||
func (w *Workspace) ListGroup() ([]string, error) {
|
||||
var result []sql.NullString
|
||||
tx := model.DB().Table(w.TableName()).Select("\"group\"").Distinct().Scan(&result)
|
||||
if len(result) > 0 {
|
||||
us := core.Map(result, func(s sql.NullString) string {
|
||||
if s.Valid {
|
||||
return s.String
|
||||
}
|
||||
return ""
|
||||
})
|
||||
return us, tx.Error
|
||||
}
|
||||
return []string{}, tx.Error
|
||||
}
|
||||
|
||||
func (w *Workspace) FindResult(db *gorm.DB) (interface{}, error) {
|
||||
var result []Workspace
|
||||
if db == nil {
|
||||
return result, nil
|
||||
}
|
||||
err := db.Find(&result).Error
|
||||
return result, err
|
||||
}
|
||||
|
||||
// 根据Id判断是否存在
|
||||
func (w *Workspace) ExistById(id string) (bool, error) {
|
||||
var count int64
|
||||
err := model.DB().Table(w.TableName()).Where("id = ?", id).Count(&count).Error
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
// 根据Id获取环境变量
|
||||
func GetWorkspaceById(id string) (*Workspace, error) {
|
||||
var workspace Workspace
|
||||
err := model.DB().Table(workspace.TableName()).Where("id = ?", id).First(&workspace).Error
|
||||
return &workspace, err
|
||||
}
|
||||
|
||||
// 根据Id列表获取环境变量
|
||||
func GetWorkspaceByIds(ids []string) ([]Workspace, error) {
|
||||
var workspaces []Workspace
|
||||
err := model.DB().Table(New().TableName()).Where("id in (?)", ids).Find(&workspaces).Error
|
||||
return workspaces, err
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package workspace_env
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type WorkspaceEnvVar struct {
|
||||
model.BaseWorkspaceModel
|
||||
Name string `gorm:"column:name" json:"name"`
|
||||
Description string `gorm:"column:description" json:"description"`
|
||||
Value string `gorm:"column:value" json:"value"`
|
||||
NodeIds string `gorm:"column:node_ids" json:"nodeIds"`
|
||||
Privacy int `gorm:"column:privacy" json:"privacy"`
|
||||
TriggerToken string `gorm:"column:trigger_token" json:"triggerToken"`
|
||||
}
|
||||
|
||||
func New() *WorkspaceEnvVar {
|
||||
w := &WorkspaceEnvVar{}
|
||||
w.Handler = w
|
||||
return w
|
||||
}
|
||||
|
||||
func (*WorkspaceEnvVar) TableName() string {
|
||||
return "sched_workspace_env_var"
|
||||
}
|
||||
|
||||
func (w *WorkspaceEnvVar) FindResult(db *gorm.DB) (interface{}, error) {
|
||||
var result []WorkspaceEnvVar
|
||||
if db == nil {
|
||||
return result, nil
|
||||
}
|
||||
err := db.Find(&result).Error
|
||||
return result, err
|
||||
}
|
||||
|
||||
// 根据工作空间(WorkspaceId)计算环境变量数量
|
||||
func CountWorkspaceEnvVarByWorkspaceId(workspaceId string) (int64, error) {
|
||||
var result int64
|
||||
tx := model.DB().Table(New().TableName()).Where("workspace_id = ?", workspaceId).Count(&result)
|
||||
if tx.Error != nil {
|
||||
return 0, tx.Error
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 根据工作空间(WorkspaceId)删除环境变量
|
||||
func DeleteWorkspaceEnvVarByWorkspaceId(workspaceId string) (int64, error) {
|
||||
tx := model.DB().Table(New().TableName()).Where("workspace_id = ?", workspaceId).Delete(nil)
|
||||
if tx.Error != nil {
|
||||
return 0, tx.Error
|
||||
}
|
||||
return tx.RowsAffected, nil
|
||||
}
|
342
server/internal/model/base.go
Normal file
342
server/internal/model/base.go
Normal file
@ -0,0 +1,342 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"errors"
|
||||
c "git.inspur.com/sbg-jszt/cfn/cfn-schedule/config"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/data"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/schema"
|
||||
"gorm.io/plugin/soft_delete"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type BaseIdModel struct {
|
||||
Handler ResultHandler `gorm:"-" json:"-"`
|
||||
Id string `gorm:"column:id;not null;primarykey" json:"id"`
|
||||
}
|
||||
|
||||
type ResultHandler interface {
|
||||
FindResult(*gorm.DB) (interface{}, error)
|
||||
}
|
||||
|
||||
func (b *BaseIdModel) Create(t schema.Tabler) (int64, error) {
|
||||
b.GenerateId()
|
||||
tx := DB().Table(t.TableName()).Create(t)
|
||||
if tx.Error != nil {
|
||||
return 0, tx.Error
|
||||
}
|
||||
return tx.RowsAffected, nil
|
||||
}
|
||||
|
||||
func (b *BaseIdModel) Update(t schema.Tabler, column []string) (int64, error) {
|
||||
if b.Id == "" {
|
||||
return 0, errors.New("id cannot be null")
|
||||
}
|
||||
db := DB().Table(t.TableName())
|
||||
if column != nil && len(column) > 0 {
|
||||
db = db.Select(column)
|
||||
}
|
||||
tx := db.Updates(t)
|
||||
return tx.RowsAffected, tx.Error
|
||||
}
|
||||
|
||||
func (b *BaseIdModel) GetById(t schema.Tabler) error {
|
||||
if b.Id == "" {
|
||||
return errors.New("id cannot be null")
|
||||
}
|
||||
tx := DB().Table(t.TableName()).Take(t)
|
||||
return tx.Error
|
||||
}
|
||||
|
||||
func (b *BaseIdModel) Delete(t schema.Tabler) (int64, error) {
|
||||
if b.Id == "" {
|
||||
return 0, errors.New("id cannot be null")
|
||||
}
|
||||
tx := DB().Table(t.TableName()).Delete(t)
|
||||
return tx.RowsAffected, tx.Error
|
||||
}
|
||||
|
||||
func (b *BaseIdModel) GetAll(t schema.Tabler, fields map[string]interface{}, notFields map[string]interface{}) (interface{}, error) {
|
||||
query := DB().Table(t.TableName())
|
||||
if fields != nil {
|
||||
for key := range fields {
|
||||
value := fields[key]
|
||||
switch value.(type) {
|
||||
case []string, []int, []int64, []interface{}:
|
||||
query = query.Where(key+" in (?)", value)
|
||||
default:
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
if notFields != nil {
|
||||
for key := range notFields {
|
||||
value := notFields[key]
|
||||
if items, ok := value.([]interface{}); ok {
|
||||
if len(items) > 0 {
|
||||
query = query.Where(key+" not in (?)", items)
|
||||
} else {
|
||||
query = query.Where(key+" <> ?", items[0])
|
||||
}
|
||||
} else {
|
||||
query = query.Where(key+" <> ?", value)
|
||||
}
|
||||
}
|
||||
//query = query.Where(fields)
|
||||
}
|
||||
return b.Handler.FindResult(query)
|
||||
}
|
||||
|
||||
// IN db.Where("name in (?)", []string{"jinzhu", "jinzhu 2"}).Find(&users)
|
||||
func (b *BaseIdModel) Page(t schema.Tabler, page *PageConfig, fields map[string]interface{}) (interface{}, error) {
|
||||
query := DB()
|
||||
if fields != nil {
|
||||
//query = query.Where(fields)
|
||||
for key := range fields {
|
||||
value := fields[key]
|
||||
switch value.(type) {
|
||||
case []string, []int, []int64, []interface{}:
|
||||
query = query.Where(key+" in (?)", value)
|
||||
default:
|
||||
query = query.Where(key+" = ?", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
return b.Handler.FindResult(page.SelectPages(t, query))
|
||||
}
|
||||
|
||||
func (b *BaseIdModel) GenerateId() {
|
||||
if b.Id == "" {
|
||||
id, _ := uuid.NewUUID()
|
||||
b.Id = strings.ReplaceAll(id.String(), "-", "")
|
||||
}
|
||||
}
|
||||
|
||||
type BaseDbModel struct {
|
||||
BaseIdModel
|
||||
CreateTimeMillis int64 `gorm:"column:create_time_millis" json:"createTimeMillis"` //type:timestamptz comment:数据创建时间 version:2024-02-12 14:22
|
||||
ModifyTimeMillis int64 `gorm:"column:modify_time_millis" json:"modifyTimeMillis"` //type:timestamptz comment:数据修改时间 version:2024-02-12 14:22
|
||||
}
|
||||
|
||||
func (b *BaseDbModel) Create(t schema.Tabler) (int64, error) {
|
||||
b.GenerateTime()
|
||||
return b.BaseIdModel.Create(t)
|
||||
}
|
||||
|
||||
func (b *BaseDbModel) Update(t schema.Tabler, column []string) (int64, error) {
|
||||
b.GenerateModifyTime()
|
||||
return b.BaseIdModel.Update(t, column)
|
||||
}
|
||||
|
||||
func (b *BaseDbModel) GenerateTime() {
|
||||
t := time.Now().UnixMilli()
|
||||
b.CreateTimeMillis = t
|
||||
b.ModifyTimeMillis = t
|
||||
}
|
||||
|
||||
func (b *BaseDbModel) GenerateModifyTime() {
|
||||
b.ModifyTimeMillis = time.Now().UnixMilli()
|
||||
}
|
||||
|
||||
type BaseUserModifyDbModel struct {
|
||||
BaseDbModel
|
||||
CreateUser string `gorm:"column:create_user" json:"createUser"`
|
||||
ModifyUser string `gorm:"column:modify_user" json:"modifyUser"`
|
||||
}
|
||||
|
||||
func (b *BaseUserModifyDbModel) SetUserName(userName string) {
|
||||
b.CreateUser = userName
|
||||
b.ModifyUser = userName
|
||||
}
|
||||
|
||||
func (b *BaseUserModifyDbModel) SetModifyUserName(userName string) {
|
||||
b.ModifyUser = userName
|
||||
}
|
||||
|
||||
type BaseWorkspaceModel struct {
|
||||
BaseUserModifyDbModel
|
||||
WorkspaceId string `gorm:"column:workspace_id" json:"workspaceId"`
|
||||
}
|
||||
|
||||
func (b *BaseWorkspaceModel) CountByWorkspaceId(t schema.Tabler) (int64, error) {
|
||||
if b.WorkspaceId == "" {
|
||||
return 0, errors.New("id cannot be null")
|
||||
}
|
||||
var count int64
|
||||
tx := DB().Table(t.TableName()).Where("workspace_id = ?", b.WorkspaceId).Count(&count)
|
||||
return count, tx.Error
|
||||
}
|
||||
|
||||
func (b *BaseWorkspaceModel) Global() bool {
|
||||
return strings.EqualFold(b.WorkspaceId, "GLOBAL")
|
||||
}
|
||||
|
||||
type BaseNodeModel struct {
|
||||
BaseWorkspaceModel
|
||||
NodeId string `gorm:"column:node_id" json:"nodeId"`
|
||||
NodeName string `gorm:"column:node_name" json:"nodeName"`
|
||||
WorkspaceName string `gorm:"column:workspace_name" json:"workspaceName"`
|
||||
}
|
||||
|
||||
type BaseGroupModel struct {
|
||||
BaseWorkspaceModel
|
||||
Group string `gorm:"column:group" json:"group"`
|
||||
}
|
||||
|
||||
type BaseMachineModel struct {
|
||||
BaseGroupModel
|
||||
MachineId string `gorm:"column:machine_id" json:"machineId"`
|
||||
}
|
||||
|
||||
type BaseModel struct {
|
||||
ID string `gorm:"column:id;not null;primarykey" json:"id"`
|
||||
CreateTime time.Time `gorm:"column:create_time;type:timestamp;<-:create" json:"createTime"`
|
||||
UpdateTime time.Time `gorm:"column:update_time;type:timestamp" json:"updateTime"`
|
||||
CreatorID string `gorm:"column:creator_id;type:varchar(64);not null;<-:create" json:"creatorID"`
|
||||
Modifier string `gorm:"column:modifier;type:varchar(64);not null;" json:"modifier"`
|
||||
}
|
||||
|
||||
func (model *BaseModel) DB() *gorm.DB {
|
||||
return DB()
|
||||
}
|
||||
|
||||
type ContainsDeleteBaseModel struct {
|
||||
BaseModel
|
||||
DeletedAt soft_delete.DeletedAt `gorm:"column:deleted_at;type:int(11) unsigned;not null;default:0;index" json:"-"`
|
||||
}
|
||||
|
||||
func DB() *gorm.DB {
|
||||
if c.Config.DatabaseConfig.Type == "sqlite" {
|
||||
return data.SqliteDB
|
||||
} else {
|
||||
return data.PostgreSqlDB["data"]
|
||||
}
|
||||
}
|
||||
|
||||
//func DBAuth() *gorm.DB {
|
||||
// return data.PostgreSqlDB["auth"]
|
||||
//}
|
||||
|
||||
type Page[T any] struct {
|
||||
CurrentPage int64 `json:"currentPage"`
|
||||
PageSize int64 `json:"pageSize"`
|
||||
Total int64 `json:"total"`
|
||||
Pages int64 `json:"pages"`
|
||||
Order string `json:"order"` //db.Order("name DESC")
|
||||
Data []T `json:"data"`
|
||||
}
|
||||
|
||||
func (page *Page[T]) SelectPages(query *gorm.DB) (e error) {
|
||||
var model T
|
||||
query.Model(&model).Count(&page.Total)
|
||||
if page.Total == 0 {
|
||||
page.Data = []T{}
|
||||
return
|
||||
}
|
||||
e = query.Model(&model).Scopes(Paginate(page)).Find(&page.Data).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (page *Page[T]) ScanPages(query *gorm.DB) (e error) {
|
||||
var model T
|
||||
query.Model(&model).Count(&page.Total)
|
||||
if page.Total == 0 {
|
||||
page.Data = []T{}
|
||||
return
|
||||
}
|
||||
e = query.Model(&model).Scopes(Paginate(page)).Scan(&page.Data).Error
|
||||
return
|
||||
}
|
||||
|
||||
func Paginate[T any](page *Page[T]) func(db *gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
if page.CurrentPage <= 0 {
|
||||
page.CurrentPage = 1
|
||||
}
|
||||
switch {
|
||||
case page.PageSize > 1000:
|
||||
page.PageSize = 1000 // 限制一下分页大小
|
||||
case page.PageSize <= 0:
|
||||
page.PageSize = 10
|
||||
}
|
||||
page.Pages = page.Total / page.PageSize
|
||||
if page.Total%page.PageSize != 0 {
|
||||
page.Pages++
|
||||
}
|
||||
size := page.PageSize
|
||||
offset := int((page.CurrentPage - 1) * size)
|
||||
return db.Order(page.Order).Offset(offset).Limit(int(size))
|
||||
}
|
||||
}
|
||||
|
||||
func (page *Page[T]) Covert(pageInfo *request.PageInfo) {
|
||||
if pageInfo.CurrentPage <= 0 {
|
||||
pageInfo.CurrentPage = 1
|
||||
}
|
||||
switch {
|
||||
case pageInfo.PageSize > 1000:
|
||||
pageInfo.PageSize = 1000 // 限制一下分页大小
|
||||
case pageInfo.PageSize <= 0:
|
||||
pageInfo.PageSize = 10
|
||||
}
|
||||
page.CurrentPage = pageInfo.CurrentPage
|
||||
page.PageSize = pageInfo.PageSize
|
||||
page.Order = pageInfo.Order
|
||||
}
|
||||
|
||||
// PageConfig 需要配套实现FindResult,Data需要回填。推荐使用Page[T any]
|
||||
type PageConfig struct {
|
||||
CurrentPage int64 `json:"currentPage"`
|
||||
PageSize int64 `json:"pageSize"`
|
||||
Total int64 `json:"total"`
|
||||
Pages int64 `json:"pages"`
|
||||
Order string `json:"order"` //db.Order("name DESC")
|
||||
Data any `json:"data"` // 需要回填,不好用
|
||||
}
|
||||
|
||||
func (page *PageConfig) SelectPages(t schema.Tabler, query *gorm.DB) *gorm.DB {
|
||||
query.Table(t.TableName()).Count(&page.Total)
|
||||
if page.Total == 0 {
|
||||
return nil
|
||||
}
|
||||
return query.Table(t.TableName()).Scopes(PaginateConfig(page))
|
||||
}
|
||||
|
||||
func PaginateConfig(page *PageConfig) func(db *gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
if page.CurrentPage <= 0 {
|
||||
page.CurrentPage = 1
|
||||
}
|
||||
switch {
|
||||
case page.PageSize > 1000:
|
||||
page.PageSize = 1000 // 限制一下分页大小
|
||||
case page.PageSize <= 0:
|
||||
page.PageSize = 10
|
||||
}
|
||||
page.Pages = page.Total / page.PageSize
|
||||
if page.Total%page.PageSize != 0 {
|
||||
page.Pages++
|
||||
}
|
||||
size := page.PageSize
|
||||
offset := int((page.CurrentPage - 1) * size)
|
||||
return db.Order(page.Order).Offset(offset).Limit(int(size))
|
||||
}
|
||||
}
|
||||
|
||||
func (page *PageConfig) Covert(pageInfo *request.PageInfo) {
|
||||
if pageInfo.CurrentPage <= 0 {
|
||||
pageInfo.CurrentPage = 1
|
||||
}
|
||||
switch {
|
||||
case pageInfo.PageSize > 1000:
|
||||
pageInfo.PageSize = 1000 // 限制一下分页大小
|
||||
case pageInfo.PageSize <= 0:
|
||||
pageInfo.PageSize = 10
|
||||
}
|
||||
page.CurrentPage = pageInfo.CurrentPage
|
||||
page.PageSize = pageInfo.PageSize
|
||||
page.Order = pageInfo.Order
|
||||
}
|
304
server/internal/model/common/dataselect.go
Normal file
304
server/internal/model/common/dataselect.go
Normal file
@ -0,0 +1,304 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/common/sql"
|
||||
. "github.com/ahmetb/go-linq"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
FilterTypeLikeSuffix = "__like"
|
||||
FilterTypeEqualSuffix = "__eq"
|
||||
FilterTypeNotEqualSuffix = "__neq"
|
||||
FilterTypeInSuffix = "__in"
|
||||
)
|
||||
|
||||
const (
|
||||
FilterTypeLike = 0
|
||||
FilterTypeEqual = 1
|
||||
FilterTypeNotEqual = 2
|
||||
FilterTypeIn = 3
|
||||
)
|
||||
|
||||
type FilterType int
|
||||
|
||||
// PaginationQuery defines
|
||||
type PaginationQuery struct {
|
||||
From int
|
||||
Size int
|
||||
}
|
||||
|
||||
// NoPagination is the option for no pigination, currently a very large page
|
||||
var NoPagination = NewPaginationQuery(-1, -1)
|
||||
|
||||
// DefaultPagination is the default options for pagination
|
||||
var DefaultPagination = NewPaginationQuery(0, 10)
|
||||
|
||||
// NewPaginationQuery creates a new PaginationQuery
|
||||
func NewPaginationQuery(from, size int) *PaginationQuery {
|
||||
return &PaginationQuery{
|
||||
From: from,
|
||||
Size: size,
|
||||
}
|
||||
}
|
||||
|
||||
// IsValid checks if a PaginationQuery is valid
|
||||
func (pq *PaginationQuery) IsValid() bool {
|
||||
if pq == nil {
|
||||
return false
|
||||
}
|
||||
if pq.From == -1 && pq.Size == -1 {
|
||||
return true
|
||||
}
|
||||
return pq.From >= 0 && pq.Size > 0
|
||||
}
|
||||
|
||||
func (pq *PaginationQuery) String() string {
|
||||
if pq == nil {
|
||||
return ""
|
||||
}
|
||||
if pq.From == -1 || pq.Size == -1 {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf(" LIMIT %d OFFSET %d ", pq.Size, pq.From)
|
||||
}
|
||||
|
||||
// SortQuery holds options for sort functionality of data select.
|
||||
type SortQuery struct {
|
||||
SortByList []SortBy
|
||||
}
|
||||
|
||||
// SortBy holds the name of the property that should be sorted and whether order should be ascending or descending.
|
||||
type SortBy struct {
|
||||
Property string
|
||||
Ascending bool
|
||||
}
|
||||
|
||||
// NoSort is as option for no sort.
|
||||
var NoSort = &SortQuery{
|
||||
SortByList: []SortBy{},
|
||||
}
|
||||
|
||||
// NewSortQuery takes raw sort options list and returns SortQuery object. For example:
|
||||
// ["a", "parameter1", "d", "parameter2"] - means that the data should be sorted by
|
||||
// parameter1 (ascending) and later - for results that return equal under parameter 1 sort - by parameter2 (descending)
|
||||
func NewSortQuery(sortByListRaw []string) *SortQuery {
|
||||
if sortByListRaw == nil || len(sortByListRaw)%2 == 1 {
|
||||
return &SortQuery{SortByList: []SortBy{}}
|
||||
}
|
||||
sortByList := []SortBy{}
|
||||
for i := 0; i+1 < len(sortByListRaw); i += 2 {
|
||||
// parse order option
|
||||
var ascending bool
|
||||
orderOption := sortByListRaw[i]
|
||||
if orderOption == "a" {
|
||||
ascending = true
|
||||
} else if orderOption == "d" {
|
||||
ascending = false
|
||||
} else {
|
||||
// Invalid order option. Only ascending (a), descending (d) options are supported
|
||||
return &SortQuery{SortByList: []SortBy{}}
|
||||
}
|
||||
|
||||
// parse property name
|
||||
propertyName := sortByListRaw[i+1]
|
||||
sortBy := SortBy{
|
||||
Property: propertyName,
|
||||
Ascending: ascending,
|
||||
}
|
||||
// Add to the sort options.
|
||||
sortByList = append(sortByList, sortBy)
|
||||
}
|
||||
return &SortQuery{
|
||||
SortByList: sortByList,
|
||||
}
|
||||
}
|
||||
|
||||
func (sq *SortQuery) String() string {
|
||||
if sq == nil {
|
||||
return ""
|
||||
}
|
||||
if len(sq.SortByList) == 0 {
|
||||
return ""
|
||||
}
|
||||
res := fmt.Sprintf(" ORDER BY %s ", sq.SortByList[0].Property)
|
||||
if sq.SortByList[0].Ascending == false {
|
||||
res += "desc "
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// FilterQuery holds options for filter functionality of data select.
|
||||
// currently it only supports string match
|
||||
type FilterQuery struct {
|
||||
FilterByList []FilterBy
|
||||
Extend string
|
||||
}
|
||||
|
||||
// FilterBy holds the name of the property that should be .
|
||||
type FilterBy struct {
|
||||
Property string
|
||||
Type FilterType
|
||||
Value string
|
||||
values []string
|
||||
}
|
||||
|
||||
// NoFilter is as option for no filter.
|
||||
var NoFilter = &FilterQuery{
|
||||
FilterByList: []FilterBy{},
|
||||
}
|
||||
|
||||
// NewFilterQuery takes raw filter options list and returns FilterQuery object. For example:
|
||||
// ["user_name", "test"] - means that the data should be filtered by
|
||||
// user_name (%test%), means user_name contains 'test'
|
||||
func NewFilterQuery(filterByListRaw []string) *FilterQuery {
|
||||
if filterByListRaw == nil || len(filterByListRaw)%2 == 1 {
|
||||
return &FilterQuery{FilterByList: []FilterBy{}}
|
||||
}
|
||||
filterByList := parseFilter(filterByListRaw)
|
||||
return &FilterQuery{
|
||||
FilterByList: filterByList,
|
||||
}
|
||||
}
|
||||
|
||||
func (fq *FilterQuery) Add(filterByListRaw []string) {
|
||||
filterByList := parseFilter(filterByListRaw)
|
||||
fq.FilterByList = append(fq.FilterByList, filterByList...)
|
||||
}
|
||||
func parseFilter(filterByListRaw []string) []FilterBy {
|
||||
filterByList := []FilterBy{}
|
||||
for i := 0; i+1 < len(filterByListRaw); i += 2 {
|
||||
// parse property name and value
|
||||
propertyName := filterByListRaw[i]
|
||||
propertyValue := filterByListRaw[i+1]
|
||||
propertyValueArray := strings.Split(propertyValue, " ")
|
||||
filterBy := FilterBy{
|
||||
Property: propertyName,
|
||||
Type: FilterTypeLike,
|
||||
Value: strings.Join(propertyValueArray, ","),
|
||||
}
|
||||
if strings.HasSuffix(propertyName, FilterTypeEqualSuffix) {
|
||||
filterBy.Type = FilterTypeEqual
|
||||
filterBy.Property = strings.TrimSuffix(filterBy.Property, FilterTypeEqualSuffix)
|
||||
} else if strings.HasSuffix(propertyName, FilterTypeNotEqualSuffix) {
|
||||
filterBy.Type = FilterTypeNotEqual
|
||||
filterBy.Property = strings.TrimSuffix(filterBy.Property, FilterTypeNotEqualSuffix)
|
||||
} else if strings.HasSuffix(propertyName, FilterTypeInSuffix) {
|
||||
filterBy.Type = FilterTypeIn
|
||||
filterBy.Property = strings.TrimSuffix(filterBy.Property, FilterTypeInSuffix)
|
||||
} else {
|
||||
filterBy.Property = strings.TrimSuffix(filterBy.Property, FilterTypeLikeSuffix)
|
||||
}
|
||||
|
||||
// Add to the sort options.
|
||||
filterByList = append(filterByList, filterBy)
|
||||
}
|
||||
|
||||
return filterByList
|
||||
}
|
||||
func (fq *FilterQuery) String() string {
|
||||
if fq == nil || len(fq.FilterByList) == 0 {
|
||||
return fmt.Sprintf(" '1' = '1' %s ", fq.Extend)
|
||||
}
|
||||
|
||||
type index struct {
|
||||
property string
|
||||
operator FilterType
|
||||
}
|
||||
|
||||
indexed := make(map[index][]*FilterBy)
|
||||
From(fq.FilterByList).
|
||||
GroupByT(
|
||||
func(fb FilterBy) index { return index{property: fb.Property, operator: fb.Type} },
|
||||
func(fb FilterBy) *FilterBy { return &fb }).
|
||||
ToMapByT(&indexed,
|
||||
func(g Group) index { return g.Key.(index) },
|
||||
func(g Group) []*FilterBy {
|
||||
var fbs []*FilterBy
|
||||
From(g.Group).ToSlice(&fbs)
|
||||
return fbs
|
||||
})
|
||||
var list []*FilterBy
|
||||
From(indexed).SelectT(func(kv KeyValue) *FilterBy {
|
||||
k := kv.Key.(index)
|
||||
v := kv.Value.([]*FilterBy)
|
||||
var values []string
|
||||
From(v).SelectT(func(fb *FilterBy) string { return fb.Value }).ToSlice(&values)
|
||||
return &FilterBy{
|
||||
Property: k.property,
|
||||
Type: k.operator,
|
||||
values: values,
|
||||
}
|
||||
}).ToSlice(&list)
|
||||
|
||||
var items []string
|
||||
for _, filterBy := range list {
|
||||
var constraints []string
|
||||
if filterBy.Type == FilterTypeEqual {
|
||||
From(filterBy.values).SelectT(func(v string) string {
|
||||
return fmt.Sprintf(" %s='%s' ", filterBy.Property, sql.EscapeStringBackslash(v))
|
||||
}).ToSlice(&constraints)
|
||||
items = append(items, fmt.Sprintf(" (%s) ", strings.Join(constraints, " or ")))
|
||||
} else if filterBy.Type == FilterTypeNotEqual {
|
||||
From(filterBy.values).SelectT(func(v string) string {
|
||||
return fmt.Sprintf(" %s!='%s' ", filterBy.Property, sql.EscapeStringBackslash(v))
|
||||
}).ToSlice(&constraints)
|
||||
items = append(items, strings.Join(constraints, " and "))
|
||||
} else if filterBy.Type == FilterTypeIn {
|
||||
From(filterBy.values).SelectT(func(v string) string {
|
||||
return fmt.Sprintf("%s", strings.Replace(sql.EscapeStringBackslash(v), ",", "','", -1))
|
||||
}).ToSlice(&constraints)
|
||||
items = append(items, fmt.Sprintf(` (%s in ('%s')) `, filterBy.Property, strings.Join(constraints, ",")))
|
||||
} else {
|
||||
From(filterBy.values).SelectT(func(v string) string {
|
||||
if v == "%" {
|
||||
v = "\\%"
|
||||
}
|
||||
return fmt.Sprintf(" %s like '%%%s%%' ", filterBy.Property, sql.EscapeUnderlineInLikeStatement(v))
|
||||
}).ToSlice(&constraints)
|
||||
items = append(items, fmt.Sprintf(" (%s) ", strings.Join(constraints, " or ")))
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s %s", strings.Join(items, "and"), fq.Extend)
|
||||
}
|
||||
|
||||
// DataSelectQuery currently included only Pagination and Sort options.
|
||||
type DataSelectQuery struct {
|
||||
PaginationQuery *PaginationQuery
|
||||
SortQuery *SortQuery
|
||||
FilterQuery *FilterQuery
|
||||
}
|
||||
|
||||
// NoDataSelect fetches all items with no sort.
|
||||
var NoDataSelect = NewDataSelectQuery(NoPagination, NoSort, NoFilter)
|
||||
|
||||
// DefaultDataSelect fetches first 10 items from page 1 with no sort.
|
||||
var DefaultDataSelect = NewDataSelectQuery(DefaultPagination, NoSort, NoFilter)
|
||||
|
||||
// NewDataSelectQuery creates DataSelectQuery object from simpler data select queries.
|
||||
func NewDataSelectQuery(paginationQuery *PaginationQuery, sortQuery *SortQuery, filterQuery *FilterQuery) *DataSelectQuery {
|
||||
dataselect := &DataSelectQuery{
|
||||
PaginationQuery: &PaginationQuery{From: 0, Size: 10},
|
||||
SortQuery: &SortQuery{SortByList: []SortBy{}},
|
||||
FilterQuery: &FilterQuery{FilterByList: []FilterBy{}},
|
||||
}
|
||||
if paginationQuery != nil {
|
||||
pq := *paginationQuery
|
||||
dataselect.PaginationQuery = &pq
|
||||
}
|
||||
if sortQuery != nil && len(sortQuery.SortByList) > 0 {
|
||||
dataselect.SortQuery.SortByList = append(dataselect.SortQuery.SortByList, sortQuery.SortByList...)
|
||||
}
|
||||
if filterQuery != nil && len(filterQuery.FilterByList) > 0 {
|
||||
dataselect.FilterQuery.FilterByList = append(dataselect.FilterQuery.FilterByList, filterQuery.FilterByList...)
|
||||
}
|
||||
if filterQuery != nil {
|
||||
dataselect.FilterQuery.Extend = filterQuery.Extend
|
||||
if len(filterQuery.FilterByList) > 0 {
|
||||
dataselect.FilterQuery.FilterByList = append(dataselect.FilterQuery.FilterByList, filterQuery.FilterByList...)
|
||||
}
|
||||
}
|
||||
return dataselect
|
||||
}
|
138
server/internal/model/common/dataselect_test.go
Normal file
138
server/internal/model/common/dataselect_test.go
Normal file
@ -0,0 +1,138 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewPaginationQuery(t *testing.T) {
|
||||
resource := []struct {
|
||||
label string
|
||||
from int
|
||||
size int
|
||||
}{
|
||||
{
|
||||
"normal",
|
||||
1,
|
||||
10,
|
||||
},
|
||||
{
|
||||
"normal",
|
||||
0,
|
||||
10,
|
||||
},
|
||||
{
|
||||
"sizeError",
|
||||
0,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"fromError",
|
||||
-1,
|
||||
1,
|
||||
},
|
||||
{
|
||||
"doubleError",
|
||||
-1,
|
||||
-1,
|
||||
},
|
||||
}
|
||||
for _, item := range resource {
|
||||
pgq := NewPaginationQuery(item.from, item.size)
|
||||
|
||||
flag := pgq.IsValid()
|
||||
if !flag && item.label == "normal" {
|
||||
t.Error(errors.New("IsValid error"))
|
||||
}
|
||||
|
||||
str := pgq.String()
|
||||
if str == "" && item.label == "normal" {
|
||||
t.Error(errors.New("string error"))
|
||||
}
|
||||
}
|
||||
|
||||
if !NoPagination.IsValid() {
|
||||
t.Error(errors.New("IsValid error"))
|
||||
}
|
||||
if NoPagination.String() != "" {
|
||||
t.Error(errors.New("string error"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewSortQuery(t *testing.T) {
|
||||
resource := []string{"a", "param1", "d", "param2", "d", "param3"}
|
||||
fake1 := []string{}
|
||||
fake2 := []string{"a"}
|
||||
fake3 := []string{"a", "p1", "b", "p2"}
|
||||
|
||||
sq := NewSortQuery(resource)
|
||||
if sq.String() == "" {
|
||||
t.Error(errors.New("string error"))
|
||||
}
|
||||
|
||||
fakeSq1 := NewSortQuery(fake1)
|
||||
if fakeSq1.String() != "" {
|
||||
t.Error(errors.New("string error"))
|
||||
}
|
||||
|
||||
fakeSq2 := NewSortQuery(fake2)
|
||||
if fakeSq2.String() != "" {
|
||||
t.Error(errors.New("string error"))
|
||||
}
|
||||
|
||||
fakeSq3 := NewSortQuery(fake3)
|
||||
if fakeSq3.String() != "" {
|
||||
t.Error(errors.New("string error"))
|
||||
}
|
||||
|
||||
if NoSort.String() != "" {
|
||||
t.Error(errors.New("string error"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewFilterQuery(t *testing.T) {
|
||||
resource := []string{"type", "param"}
|
||||
fake1 := []string{}
|
||||
fake2 := []string{"type"}
|
||||
fake3 := []string{"_neqtype", "param"}
|
||||
fake4 := []string{"_eqtype", "param"}
|
||||
|
||||
fq := NewFilterQuery(resource)
|
||||
if fq.String() == " '1' = '1' " {
|
||||
t.Error(errors.New("string error"))
|
||||
}
|
||||
|
||||
fqFake1 := NewFilterQuery(fake1)
|
||||
if fqFake1.String() != " '1' = '1' " {
|
||||
t.Error(errors.New("string error"))
|
||||
}
|
||||
|
||||
fqFake2 := NewFilterQuery(fake2)
|
||||
if fqFake2.String() != " '1' = '1' " {
|
||||
t.Error(errors.New("string error"))
|
||||
}
|
||||
|
||||
fqFake3 := NewFilterQuery(fake3)
|
||||
if fqFake3.String() == " '1' = '1' " {
|
||||
t.Error(errors.New("string error"))
|
||||
}
|
||||
|
||||
fqFake4 := NewFilterQuery(fake4)
|
||||
if fqFake4.String() == " '1' = '1' " {
|
||||
t.Error(errors.New("string error"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewDataSelectQuery(t *testing.T) {
|
||||
resource1 := []string{"type", "param"}
|
||||
resource2 := []string{"a", "param"}
|
||||
|
||||
pgq := NewPaginationQuery(0, 10)
|
||||
sq := NewSortQuery(resource2)
|
||||
fq := NewFilterQuery(resource1)
|
||||
|
||||
NewDataSelectQuery(nil, nil, nil)
|
||||
NewDataSelectQuery(pgq, nil, nil)
|
||||
NewDataSelectQuery(pgq, sq, nil)
|
||||
NewDataSelectQuery(pgq, sq, fq)
|
||||
}
|
71
server/internal/model/common/sql/escape.go
Normal file
71
server/internal/model/common/sql/escape.go
Normal file
@ -0,0 +1,71 @@
|
||||
package sql
|
||||
|
||||
// EscapeStringBackslash escapes special characters.
|
||||
func EscapeStringBackslash(v string) string {
|
||||
buf := make([]byte, len(v)*2, len(v)*2)
|
||||
pos := 0
|
||||
|
||||
for i := 0; i < len(v); i++ {
|
||||
c := v[i]
|
||||
switch c {
|
||||
case '\x00':
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = '0'
|
||||
pos += 2
|
||||
case '\n':
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = 'n'
|
||||
pos += 2
|
||||
case '\r':
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = 'r'
|
||||
pos += 2
|
||||
case '\x1a':
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = 'Z'
|
||||
pos += 2
|
||||
case '\'':
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = '\''
|
||||
pos += 2
|
||||
case '"':
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = '"'
|
||||
pos += 2
|
||||
case '\\':
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = '\\'
|
||||
pos += 2
|
||||
default:
|
||||
buf[pos] = c
|
||||
pos++
|
||||
}
|
||||
}
|
||||
|
||||
return string(buf[:pos])
|
||||
}
|
||||
|
||||
func EscapeSliceForInjection(src []string) []string {
|
||||
out := make([]string, 0, len(src))
|
||||
for i := range src {
|
||||
out = append(out, EscapeStringBackslash(src[i]))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func EscapeUnderlineInLikeStatement(v string) string {
|
||||
v = EscapeStringBackslash(v)
|
||||
buf := make([]byte, len(v)*2, len(v)*2)
|
||||
pos := 0
|
||||
for i := 0; i < len(v); i++ {
|
||||
if v[i] == '_' {
|
||||
buf[pos] = '\\'
|
||||
buf[pos+1] = '_'
|
||||
pos += 2
|
||||
} else {
|
||||
buf[pos] = v[i]
|
||||
pos++
|
||||
}
|
||||
}
|
||||
return string(buf[:pos])
|
||||
}
|
59
server/internal/model/device/device_health_record.go
Normal file
59
server/internal/model/device/device_health_record.go
Normal file
@ -0,0 +1,59 @@
|
||||
package device
|
||||
|
||||
import (
|
||||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 设备健康检测记录。
|
||||
// 表名:perc_device_health_record
|
||||
type DeviceHealthRecord struct {
|
||||
Id int64 `gorm:"column:id;primaryKey" json:"id"` //type:*int comment:主键 version:2023-9-11 14:28
|
||||
SerialNo string `gorm:"column:serial_no" json:"serialNo" validate:"required"` //type:string comment:序列号 version:2023-9-11 14:28
|
||||
BatchNo string `gorm:"column:batch_no" json:"batchNo" validate:"required"` //type:string comment:检测批次号 version:2023-9-11 14:28
|
||||
ItemName string `gorm:"column:item_name" json:"itemName" validate:"required"` //type:string comment:检测项 version:2023-9-11 14:28
|
||||
ItemScore string `gorm:"column:item_score" json:"itemScore"` //type:string comment:检测得分 version:2023-9-11 14:28
|
||||
ItemResult string `gorm:"column:item_result" json:"itemResult"` //type:string comment:检测结果 version:2023-9-11 14:28
|
||||
CheckTime time.Time `gorm:"column:check_time" json:"checkTime" validate:"required"` //type:*time.Time comment:检测时间 version:2023-9-11 14:28
|
||||
}
|
||||
|
||||
func (DeviceHealthRecord) TableName() string {
|
||||
return "perc_device_health_record"
|
||||
}
|
||||
|
||||
func (d *DeviceHealthRecord) Create() (int64, error) {
|
||||
d.CheckTime = time.Now()
|
||||
tx := model.DB().Create(d)
|
||||
if tx.Error != nil {
|
||||
return 0, tx.Error
|
||||
}
|
||||
return tx.RowsAffected, nil
|
||||
}
|
||||
|
||||
func (d *DeviceHealthRecord) Delete() (int64, error) {
|
||||
tx := model.DB().Delete(d)
|
||||
if tx.Error != nil {
|
||||
return 0, tx.Error
|
||||
}
|
||||
return tx.RowsAffected, nil
|
||||
}
|
||||
|
||||
func (d *DeviceHealthRecord) Get(fields map[string]interface{}) (DeviceHealthRecord, error) {
|
||||
device := DeviceHealthRecord{}
|
||||
tx := model.DB().Where(fields).First(&device)
|
||||
if tx.Error != nil {
|
||||
return device, tx.Error
|
||||
}
|
||||
return device, nil
|
||||
}
|
||||
|
||||
func (d *DeviceHealthRecord) List(limit int, offset int, fields map[string]interface{}) ([]DeviceHealthRecord, int64, error) {
|
||||
devices := []DeviceHealthRecord{}
|
||||
tx := model.DB().Limit(limit).Offset(offset).Where(fields).Find(&devices)
|
||||
if tx.Error != nil {
|
||||
return nil, 0, tx.Error
|
||||
}
|
||||
var total int64
|
||||
model.DB().Model(DeviceHealthRecord{}).Where(fields).Count(&total)
|
||||
return devices, total, nil
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user