add sheduling agent

Change-Id: I89f35fb3984044c57f10727432755012542f9fd8
This commit is contained in:
liuhaijun 2023-11-08 18:52:44 +08:00 committed by Qihui Zhao
parent 8f126a978f
commit 3f5f28d785
372 changed files with 46807 additions and 0 deletions

36
agent/Dockerfile Normal file
View File

@ -0,0 +1,36 @@
# Dockerfile for cicd
FROM harbor.inspur.local/system/alpine:3.17.2-yq
MAINTAINER yinchongbing yinchongbing@inspur.com
WORKDIR /app
ADD cmd/ /app/
ADD config/config.yaml /app/config/
ADD deploy/docker/run.sh /app/run.sh
ENV APP_ENV local
ENV APP_DEBUG true
ENV APP_LANGUAGE zh_CN
ENV SERVER_HOST 0.0.0.0
ENV SERVER_PORT 8899
ENV POSTGRES_DATA_ENABLE false
ENV POSTGRES_DATA_HOST postgres
ENV POSTGRES_DATA_PORT 5432
ENV POSTGRES_DATA_DATABASE postgres
ENV POSTGRES_DATA_USERNAME postgres
ENV POSTGRES_DATA_PASSWORD Mypostgres!23
ENV POSTGRES_AUTH_ENABLE false
ENV POSTGRES_AUTH_HOST postgres
ENV POSTGRES_AUTH_PORT 5432
ENV POSTGRES_AUTH_DATABASE auth
ENV POSTGRES_AUTH_USERNAME postgres
ENV POSTGRES_AUTH_PASSWORD Mypostgres!23
ENV LOG_LEVEL 4
ENV REDIS_EBABLE false
ENV REDIS_HOST redis
ENV REDIS_PORT 6379
ENV REDIS_DATABASE 0
ENV REDIS_PASSWORD ""
RUN chmod +x run.sh && chmod +x cfn-schedule-agent
EXPOSE $SERVER_PORT
CMD ["./run.sh"]

151
agent/README.md Normal file
View File

@ -0,0 +1,151 @@
# 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
CGO_ENABLED=0禁用CGO
GOOS=linux编译后的操作系统是Linux
GOARCH=amd64编译后的CPU架构是amd64
-a强制编译所有package
-installsuffix cgo指定额外的后缀
-o cfn-schedule-agent将编译后的程序存储为cfn-schedule-agent
.:编译当前路径下所有代码
## linux平台上编译命令
### linux
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -installsuffix cgo -o cfn-schedule-agent .
### windows
CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build -a -installsuffix cgo -o cfn-schedule-agent .
## windows平台上编译命令
### linux
set GOOS=linux
set GOARCH=amd64
set CGO_ENABLED=0
go env -w GOARCH=amd64
go env -w GOOS=linux
go env -w CGO_ENABLED=0
go build -a -installsuffix cgo -o cfn-schedule-agent .
### windows
set GOOS=windows
set GOARCH=amd64
set CGO_ENABLED=0
go env -w GOARCH=amd64
go env -w GOOS=windows
go env -w CGO_ENABLED=0
go build -a -installsuffix cgo -o cfn-schedule-agent .
# 运行时请配置指定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文件

53
agent/boot/boot.go Normal file
View File

@ -0,0 +1,53 @@
package boot
import (
"flag"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config/agent"
"os"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/data"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/validator"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/log"
processManager "git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/process-manager"
)
var (
configPath string
printVersion bool
Run string
ProcessUnitDir string
AssetConfigDir string
)
func init() {
flag.StringVar(&Run, "r", "http", "执行命令默认运行http服务")
flag.StringVar(&configPath, "c", "", "请输入配置文件绝对路径")
flag.StringVar(&ProcessUnitDir, "process-unit-dir", "", "纳管进程配置文件目录绝对路径")
flag.StringVar(&AssetConfigDir, "asset-config-dir", "", "资产配置文件目录绝对路径")
flag.BoolVar(&printVersion, "version", false, "查看版本")
flag.Parse()
if printVersion {
// 打印版本号
println(version)
os.Exit(0)
}
// 1、初始化配置
config.InitConfig(configPath)
agent.InitAgentConfig(AssetConfigDir)
// 2、初始化zap日志
log.InitLogger()
// 3、初始化数据库
data.InitData()
// 4、初始化验证器
validator.InitValidatorTrans("zh")
// 5、启动进程管理程序
go processManager.Start(ProcessUnitDir)
}

4
agent/boot/version.go Normal file
View File

@ -0,0 +1,4 @@
package boot
// version is the current gin-layout version.
const version = "0.2.3"

BIN
agent/cfn-schedule-agent Normal file

Binary file not shown.

2
agent/cmd/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

View File

@ -0,0 +1,63 @@
package agent
import (
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config/bin_path"
"gopkg.in/yaml.v3"
"io/fs"
"os"
)
type AgentConfig struct {
RID string `yaml:"rid" mapstructure:"rid"`
Token string `yaml:"token" mapstructure:"token"`
//AgentVersion string `yaml:"agent_version" mapstructure:"agent_version"`
Role string `yaml:"role" mapstructure:"role"`
NetInterface string `yaml:"net_interface" mapstructure:"net_interface"`
ScheduleServer string `yaml:"schedule_server" mapstructure:"schedule_server"`
Enterprise string `yaml:"enterprise" mapstructure:"enterprise"`
Type string `yaml:"type"` // 0:应用一体机 1:调度一体机 2:纳管一体机
}
var Agent = &AgentConfig{}
func InitAgentConfig(assetConfigDir string) {
if assetConfigDir != "" {
bin_path.ASSETCONFIGDIR = assetConfigDir
}
file, err := os.ReadFile(bin_path.ASSETCONFIGDIR + "/agent.yaml")
if err != nil {
panic("Failed to read configuration file:" + err.Error())
}
var config = &AgentConfig{}
yaml.Unmarshal(file, config)
Agent = config
//放入环境变量
os.Setenv("CFN_SCHEDULE_AGENT_RID", config.RID)
os.Setenv("CFN_TELEGRAF_LOG_FILE", bin_path.TELEGRAFLOG)
// 如果 path 路径不存在,会有 err然后通过 IsNotExist 判定文件路径是否存在,如果 true 则不存在,注意用 os.ModePerm 这样文件是可以写入的
if _, err := os.Stat(bin_path.TELEGRAFLOG); os.IsNotExist(err) {
// mkdir 创建目录mkdirAll 可创建多层级目录
os.MkdirAll(bin_path.TELEGRAFLOG, os.ModePerm)
}
}
func LoadAgentInfo(config AgentConfig) {
// 更新内存
Agent = &config
go func() {
out, _ := yaml.Marshal(config)
err := os.WriteFile(bin_path.ASSETCONFIGDIR+"/agent.yaml", out, fs.ModePerm)
if err != nil {
panic("Failed to write configuration file:" + err.Error())
}
}()
}

View File

@ -0,0 +1,7 @@
rid: "DZ210900214"
token: "afsdfasfasdccc "
role: "Cache" # 枚举Cache or Normal
net_interface: "eth0" # 示例eth0 for linux 以太网 4 for windows
schedule_server: "localhost"
enterprise: "SDLC"
type: 1 # 1:应用一体机 2:调度一体机 3:纳管一体机

26
agent/config/app.go Normal file
View File

@ -0,0 +1,26 @@
package config
import (
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/convert"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/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
}

View File

@ -0,0 +1,28 @@
package bin_path
import (
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/utils"
"path/filepath"
)
var (
BINDIR = "/root/cfn-schedule-agent/bin"
UPGRADEDIR = "/root/cfn-schedule-agent/upgrade"
ASSETCONFIGDIR = ""
AGENTLOG = ""
AGENTUPGRADELOG = ""
TELEGRAFLOG = ""
UPGRADEPLAN = ""
)
func init() {
BINDIR, _ = utils.GetCurrentPath()
UPGRADEDIR = filepath.Join(BINDIR, "../upgrade")
AGENTUPGRADELOG = filepath.Join(UPGRADEDIR, "/upgrade.log")
TELEGRAFLOG = filepath.Join(BINDIR, "/data-collector/telegraf/log/", "telegraf.log")
AGENTLOG = filepath.Join(BINDIR, "/logs/", config.Config.Logger.Filename)
UPGRADEPLAN = filepath.Join(UPGRADEDIR, "/upgradeplan")
}

View File

@ -0,0 +1,5 @@
package bin_path
func init() {
ASSETCONFIGDIR = "/etc/cfn-schedule-agent"
}

View File

@ -0,0 +1,5 @@
package bin_path
func init() {
ASSETCONFIGDIR = "C:\\cfn-schedule-agent"
}

111
agent/config/config.go Normal file
View File

@ -0,0 +1,111 @@
package config
import (
"os"
"path/filepath"
"sync"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/utils"
"github.com/spf13/viper"
)
// Conf 配置项主结构体
// mapstructure(配置文件属性名称无法与类属性名称直接对应)
type Conf struct {
AppConfig `yaml:"app" mapstructure:"app"`
Server ServerConfig `yaml:"server" mapstructure:"server"`
PostgreSql PostgreSqlConfigMap `yaml:"postgres" mapstructure:"postgres"`
Redis RedisConfig `yaml:"redis" mapstructure:"redis"`
Nats NatsConfig `yaml:"nats_config" mapstructure:"nats_config"`
//Minio MinioConfig `yaml:"minio" mapstructure:"minio"`
Logger LoggerConfig `yaml:"logger" mapstructure:"logger"`
Schedule ScheduleServer `yaml:"schedule" mapstructure:"schedule"`
AgentVersion string `yaml:"agent_version" mapstructure:"agent_version"`
ZombieCleaner bool `yaml:"zombie_cleaner" mapstructure:"zombie_cleaner"`
}
var Config = &Conf{
AppConfig: App,
Server: Server,
PostgreSql: PostgreSql,
Redis: Redis,
Nats: Nats,
//Minio: Minio,
Logger: Logger,
Schedule: Schedule,
}
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 == "" {
runDirectory, _ := utils.GetCurrentPath()
yamlConfig = filepath.Join(runDirectory, "/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
}

60
agent/config/config.yaml Normal file
View File

@ -0,0 +1,60 @@
app:
app_env: ${APP_ENV||local}
debug: ${APP_DEBUG||true}
language: ${APP_LANGUAGE||zh_CN}
# base_path: ""
server:
host: ${SERVER_HOST||0.0.0.0}
port: ${SERVER_PORT||8898}
agent_version: ${AGENT_VERSION||v1.0.0}
zombie_cleaner: ${POSTGRES_DATA_ENABLE||true}
schedule:
port: ${SCHEDULE_PORT||9090}
heart_beat: 30
protocol: http
auth:
type: none
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}
logger:
default_division: ${LOGGER_DEFAULT_DIVISION||time}
file_name: ${LOGGER_FILE_NAME||cfn-schedule-agent.sys.log}
division_time:
max_age: ${LOGGER_DIVISION_TIME_MAX_AGE||15}
rotation_time: ${LOGGER_DIVISION_TIME_ROTATION_TIME||24}
division_size:
max_size: ${LOGGER_DIVISION_SIZE_MAX_SIZE||20}
max_backups: ${LOGGER_DIVISION_SIZE_MAX_BACKUPS||15}
max_age: ${LOGGER_DIVISION_SIZE_MAX_AGE||15}
compress: ${LOGGER_DIVISION_SIZE_COMPRESS||false}

35
agent/config/logger.go Normal file
View 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
agent/config/minio.go Normal file
View 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",
}

20
agent/config/nats.go Normal file
View File

@ -0,0 +1,20 @@
package config
type NatsConfig struct {
Url string `ini:"url" yaml:"url"`
User string `ini:"user" yaml:"user"`
Password string `ini:"password" yaml:"password"`
//ToAgentUnicastSubject string `ini:"to_agent_unicast_subject" yaml:"to_agent_unicast_subject"`
//ToAgentBroadcastSubject string `ini:"to_agent_broadcast_subject" yaml:"to_agent_broadcast_subject"`
//ToScheduleSubject string `ini:"to_schedule_subject" yaml:"to_schedule_subject"`
}
var Nats = NatsConfig{
Url: "nats://192.168.12.110:30529",
User: "admin",
Password: "T0pS3cr3tFGThjjds56",
//ToAgentUnicastSubject: "cfn_to_agent_unicast_{rid}",
//ToAgentBroadcastSubject: "cfn_to_agent_broadcast",
//ToScheduleSubject: "cfn_to_schedulecfn_to_schedule",
}

40
agent/config/postgres.go Normal file
View File

@ -0,0 +1,40 @@
package config
type PostgreSqlConfig struct {
Enable bool `ini:"enable" yaml:"enable"`
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": {
Enable: false,
Host: "127.0.0.1",
Username: "root",
Password: "root1234",
Port: 3306,
Database: "test",
TablePrefix: "",
LogLevel: 4,
PrintSql: false,
},
"auth": {
Enable: false,
Host: "127.0.0.1",
Username: "root",
Password: "root1234",
Port: 3306,
Database: "test",
TablePrefix: "",
LogLevel: 4,
PrintSql: false,
},
}

17
agent/config/redis.go Normal file
View 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,
}

View File

@ -0,0 +1,42 @@
package config
// 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"
)
// Auth provides authentication data for external services
type Auth struct {
CAFile string `yaml:"ca_file" mapstructure:"ca_file"`
InsecureSkipVerify bool `yaml:"insecure_skip_verify" mapstructure:"insecure_skip_verify"`
Password string `yaml:"password" mapstructure:"password"`
Token string `yaml:"token" mapstructure:"token"`
Type string `yaml:"type" mapstructure:"type"`
Username string `yaml:"username" mapstructure:"username"`
}
func (a *Auth) Obfuscate() {
a.Token = "xxx"
a.Password = "xxx"
a.Username = "xxx"
a.CAFile = "xxx"
}
type ScheduleServer struct {
Port int `yaml:"port,omitempty" mapstructure:"port"`
Protocol string `yaml:"protocol,omitempty" mapstructure:"protocol"` // http https socket websocket
Auth Auth `yaml:"auth,omitempty" mapstructure:"auth"`
HeartBeat int64 `ini:"heart_beat" yaml:"heart_beat" mapstructure:"heart_beat"`
}
var Schedule = ScheduleServer{
Port: 1234,
Protocol: "http",
Auth: Auth{
Type: AuthTypeNone,
},
HeartBeat: 30,
}

12
agent/config/server.go Normal file
View File

@ -0,0 +1,12 @@
package config
// ServerConfig 定义项目配置
type ServerConfig struct {
Host string `ini:"host" yaml:"host" mapstructure:"host"`
Port uint16 `ini:"port" yaml:"port" mapstructure:"port"`
}
var Server = ServerConfig{
Host: "127.0.0.1",
Port: 9999,
}

19
agent/data/data.go Normal file
View File

@ -0,0 +1,19 @@
package data
import (
c "git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config"
"sync"
)
var once sync.Once
func InitData() {
once.Do(func() {
initPostgres()
if c.Config.Redis.Enable {
// 初始化 redis
initRedis()
}
})
}

73
agent/data/postgres.go Normal file
View File

@ -0,0 +1,73 @@
package data
import (
"fmt"
c "git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/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.PostgreSql
if c.Config.PostgreSql != nil && len(postgreSqlConfigMap) > 0 {
for name, postgreSqlConfig := range postgreSqlConfigMap {
if !postgreSqlConfig.Enable {
continue
}
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",
postgreSqlConfig.Host,
postgreSqlConfig.Port,
postgreSqlConfig.Username,
postgreSqlConfig.Database,
postgreSqlConfig.Password,
)
PostgreSqlDB[name], err = gorm.Open(postgres.Open(dsn), configs)
if err != nil {
panic("postgres connection failed" + err.Error())
}
}
}
}

23
agent/data/redis.go Normal file
View File

@ -0,0 +1,23 @@
package data
import (
"context"
c "git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/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())
}
}

View File

@ -0,0 +1,44 @@
#!/bin/sh
# 从环境变量获取值,来更改配置文件
NAME=$APP_ENV yq -i '.app.app_env=env(NAME)' config/config.yaml
NAME=$APP_DEBUG yq -i '.app.debug=env(NAME)' config/config.yaml
NAME=$APP_LANGUAGE yq -i '.app.language=env(NAME)' config/config.yaml
NAME=$SERVER_HOST yq -i '.server.host=env(NAME)' config/config.yaml
NAME=$SERVER_PORT yq -i '.server.port=env(NAME)' config/config.yaml
NAME=$SCHEDULE_PORT yq -i '.schedule.port=env(NAME)' config/config.yaml
if [ $POSTGRES_DATA_ENABLE = true ] ;then
NAME=$POSTGRES_DATA_ENABLE yq -i '.postgres.data.enable=env(NAME)' config/config.yaml
NAME=$POSTGRES_DATA_HOST yq -i '.postgres.data.host=env(NAME)' config/config.yaml
NAME=$POSTGRES_DATA_PORT yq -i '.postgres.data.port=env(NAME)' config/config.yaml
NAME=$POSTGRES_DATA_DATABASE yq -i '.postgres.data.database=env(NAME)' config/config.yaml
NAME=$POSTGRES_DATA_USERNAME yq -i '.postgres.data.username=env(NAME)' config/config.yaml
NAME=$LOG_LEVEL yq -i '.postgres.data.log_level=env(NAME)' config/config.yaml
if [ -n "$POSTGRES_DATA_PASSWORD" ] ;then
NAME=$POSTGRES_DATA_PASSWORD yq -i '.postgres.data.password=env(NAME)' config/config.yaml
fi
fi
if [ $POSTGRES_AUTH_ENABLE = true ] ;then
NAME=$POSTGRES_AUTH_ENABLE yq -i '.postgres.auth.enable=env(NAME)' config/config.yaml
NAME=$POSTGRES_AUTH_HOST yq -i '.postgres.auth.host=env(NAME)' config/config.yaml
NAME=$POSTGRES_AUTH_PORT yq -i '.postgres.auth.port=env(NAME)' config/config.yaml
NAME=$POSTGRES_AUTH_DATABASE yq -i '.postgres.auth.database=env(NAME)' config/config.yaml
NAME=$POSTGRES_AUTH_USERNAME yq -i '.postgres.auth.username=env(NAME)' config/config.yaml
NAME=$LOG_LEVEL yq -i '.postgres.auth.log_level=env(NAME)' config/config.yaml
if [ -n "$POSTGRES_AUTH_PASSWORD" ] ;then
NAME=$POSTGRES_AUTH_PASSWORD yq -i '.postgres.auth.password=env(NAME)' config/config.yaml
fi
fi
if [ $REDIS_EBABLE = true ] ;then
NAME=$REDIS_EBABLE yq -i '.redis.enable=env(NAME)' config/config.yaml
NAME=$REDIS_HOST yq -i '.redis.host=env(NAME)' config/config.yaml
NAME=$REDIS_PORT yq -i '.redis.port=env(NAME)' config/config.yaml
NAME=$REDIS_DATABASE yq -i '.redis.database=env(NAME)' config/config.yaml
if [ -n "$REDIS_PASSWORD" ] ;then
NAME=$REDIS_PASSWORD yq -i '.redis.password=env(NAME)' config/config.yaml
fi
fi
./cfn-schedule-agent -c config/config.yaml

162
agent/go.mod Normal file
View File

@ -0,0 +1,162 @@
module git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent
go 1.20
require (
github.com/StackExchange/wmi v1.2.1
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/docker/docker v24.0.6+incompatible
github.com/elastic/go-windows v1.0.1
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/golang/glog v1.1.0
github.com/guoyk93/rg v1.0.1
github.com/influxdata/telegraf v1.28.2
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
github.com/natefinch/lumberjack v2.0.0+incompatible
github.com/nats-io/nats.go v1.30.2
github.com/prometheus-community/pro-bing v0.3.0
github.com/prometheus/procfs v0.12.0
github.com/robfig/cron/v3 v3.0.1
github.com/spf13/viper v1.17.0
github.com/stretchr/testify v1.8.4
go.uber.org/zap v1.24.0
golang.org/x/crypto v0.14.0
golang.org/x/net v0.17.0
golang.org/x/sys v0.14.0
golang.org/x/text v0.13.0
gopkg.in/yaml.v3 v3.0.1
gorm.io/driver/postgres v1.5.2
gorm.io/gorm v1.25.0
gorm.io/plugin/soft_delete v1.1.0
howett.net/plist v1.0.0
)
require (
cloud.google.com/go/compute v1.23.0 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect
github.com/awnumar/memcall v0.1.2 // indirect
github.com/awnumar/memguard v0.22.3 // indirect
github.com/aws/aws-sdk-go-v2 v1.21.0 // indirect
github.com/aws/aws-sdk-go-v2/config v1.18.42 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.13.40 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.43 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.14.1 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.22.0 // indirect
github.com/aws/smithy-go v1.14.2 // indirect
github.com/benbjohnson/clock v1.3.3 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blues/jsonata-go v1.5.4 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/compose-spec/compose-go v1.16.0 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/distribution/reference v0.5.0 // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v5 v5.0.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/cel-go v0.14.1-0.20230424164844-d39523c445fc // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/google/uuid v1.4.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/influxdata/toml v0.0.0-20190415235208-270119a8ce65 // 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.3.1 // 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/klauspost/compress v1.17.0 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/lestrrat-go/strftime v1.0.6 // indirect
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-sqlite3 v1.14.16 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/minio/highwayhash v1.0.2 // indirect
github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/naoina/go-stringutil v0.1.0 // indirect
github.com/nats-io/jwt/v2 v2.4.1 // indirect
github.com/nats-io/nats-server/v2 v2.9.9 // indirect
github.com/nats-io/nkeys v0.4.5 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/onsi/gomega v1.27.6 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc4 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c // indirect
github.com/prometheus/client_golang v1.16.0 // indirect
github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/prometheus v0.46.0 // indirect
github.com/sagikazarmark/locafero v0.3.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/shirou/gopsutil/v3 v3.23.8 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/sirupsen/logrus v1.9.3 // 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/stoewer/go-strcase v1.2.0 // indirect
github.com/stretchr/objx v0.5.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/ugorji/go/codec v1.2.7 // indirect
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/oauth2 v0.12.0 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.13.0 // indirect
google.golang.org/api v0.143.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 // indirect
google.golang.org/grpc v1.58.2 // indirect
google.golang.org/protobuf v1.31.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
gotest.tools/v3 v3.5.1 // indirect
)

907
agent/go.sum Normal file
View File

@ -0,0 +1,907 @@
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/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY=
cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
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=
collectd.org v0.5.0 h1:y4uFSAuOmeVhG3GCRa3/oH+ysePfO/+eGJNfd0Qa3d8=
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
github.com/antchfx/jsonquery v1.3.3 h1:zjZpbnZhYng3uOAbIfdNq81A9mMEeuDJeYIpeKpZ4es=
github.com/antchfx/xmlquery v1.3.17 h1:d0qWjPp/D+vtRw7ivCwT5ApH/3CkQU8JOeo3245PpTk=
github.com/antchfx/xpath v1.2.5-0.20230505064641-588960cceeac h1:Et7H7mEPWuivbFEXi3dWa8hobnvF380TS2mq7JmgjEI=
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18=
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/awnumar/memcall v0.1.2 h1:7gOfDTL+BJ6nnbtAp9+HQzUFjtP1hEseRQq8eP055QY=
github.com/awnumar/memcall v0.1.2/go.mod h1:S911igBPR9CThzd/hYQQmTc9SWNu3ZHIlCGaWsWsoJo=
github.com/awnumar/memguard v0.22.3 h1:b4sgUXtbUjhrGELPbuC62wU+BsPQy+8lkWed9Z+pj0Y=
github.com/awnumar/memguard v0.22.3/go.mod h1:mmGunnffnLHlxE5rRgQc3j+uwPZ27eYb61ccr8Clz2Y=
github.com/aws/aws-sdk-go-v2 v1.21.0 h1:gMT0IW+03wtYJhRqTVYn0wLzwdnK9sRMcxmtfGzRdJc=
github.com/aws/aws-sdk-go-v2 v1.21.0/go.mod h1:/RfNgGmRxI+iFOB1OeJUyxiU+9s88k3pfHvDagGEp0M=
github.com/aws/aws-sdk-go-v2/config v1.18.42 h1:28jHROB27xZwU0CB88giDSjz7M1Sba3olb5JBGwina8=
github.com/aws/aws-sdk-go-v2/config v1.18.42/go.mod h1:4AZM3nMMxwlG+eZlxvBKqwVbkDLlnN2a4UGTL6HjaZI=
github.com/aws/aws-sdk-go-v2/credentials v1.13.40 h1:s8yOkDh+5b1jUDhMBtngF6zKWLDs84chUk2Vk0c38Og=
github.com/aws/aws-sdk-go-v2/credentials v1.13.40/go.mod h1:VtEHVAAqDWASwdOqj/1huyT6uHbs5s8FUHfDQdky/Rs=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 h1:uDZJF1hu0EVT/4bogChk8DyjSF6fof6uL/0Y26Ma7Fg=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11/go.mod h1:TEPP4tENqBGO99KwVpV9MlOX4NSrSLP8u3KRy2CDwA8=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 h1:22dGT7PneFMx4+b3pz7lMTRyN8ZKH7M2cW4GP9yUS2g=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41/go.mod h1:CrObHAuPneJBlfEJ5T3szXOUkLEThaGfvnhTf33buas=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 h1:SijA0mgjV8E+8G45ltVHs0fvKpTj8xmZJ3VwhGKtUSI=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35/go.mod h1:SJC1nEVVva1g3pHAIdCp7QsRIkMmLAgoDquQ9Rr8kYw=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.43 h1:g+qlObJH4Kn4n21g69DjspU0hKTjWtq7naZ9OLCv0ew=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.43/go.mod h1:rzfdUlfA+jdgLDmPKjd3Chq9V7LVLYo1Nz++Wb91aRo=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 h1:CdzPW9kKitgIiLV1+MHobfR5Xg25iYnyzWZhyQuSlDI=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35/go.mod h1:QGF2Rs33W5MaN9gYdEQOBBFPLwTZkEhRwI33f7KIG0o=
github.com/aws/aws-sdk-go-v2/service/sso v1.14.1 h1:YkNzx1RLS0F5qdf9v1Q8Cuv9NXCL2TkosOxhzlUPV64=
github.com/aws/aws-sdk-go-v2/service/sso v1.14.1/go.mod h1:fIAwKQKBFu90pBxx07BFOMJLpRUGu8VOzLJakeY+0K4=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.1 h1:8lKOidPkmSmfUtiTgtdXWgaKItCZ/g75/jEk6Ql6GsA=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.1/go.mod h1:yygr8ACQRY2PrEcy3xsUI357stq2AxnFM6DIsR9lij4=
github.com/aws/aws-sdk-go-v2/service/sts v1.22.0 h1:s4bioTgjSFRwOoyEFzAVCmFmoowBgjTR8gkrF/sQ4wk=
github.com/aws/aws-sdk-go-v2/service/sts v1.22.0/go.mod h1:VC7JDqsqiwXukYEDjoHh9U0fOJtNWh04FPQz4ct4GGU=
github.com/aws/smithy-go v1.14.2 h1:MJU9hqBGbvWZdApzpvoF2WAIJDbtjK2NDJSiJP7HblQ=
github.com/aws/smithy-go v1.14.2/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/benbjohnson/clock v1.3.3 h1:g+rSsSaAzhHJYcIQE78hJ3AhyjjtQvleKDjlhdBnIhc=
github.com/benbjohnson/clock v1.3.3/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/blues/jsonata-go v1.5.4 h1:XCsXaVVMrt4lcpKeJw6mNJHqQpWU751cnHdCFUq3xd8=
github.com/blues/jsonata-go v1.5.4/go.mod h1:uns2jymDrnI7y+UFYCqsRTEiAH22GyHnNXrkupAVFWI=
github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
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/cloudevents/sdk-go/v2 v2.14.0 h1:Nrob4FwVgi5L4tV9lhjzZcjYqFVyJzsA56CwPaPfv6s=
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/compose-spec/compose-go v1.16.0 h1:HYk4uYWXgArHh6NG+WE4yGYayOXw+hjqJ+eJxpjWWjk=
github.com/compose-spec/compose-go v1.16.0/go.mod h1:3yngGBGfls6FHGQsg4B1z6gz8ej9SOvmAJtxCwgbcnc=
github.com/containerd/containerd v1.7.3 h1:cKwYKkP1eTj54bP3wCdXXBymmKRQMrWjkLSWZZJDa8o=
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E=
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/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v24.0.6+incompatible h1:hceabKCtUgDqPu+qm0NgsaXf28Ljf4/pWFL7xjWWDgE=
github.com/docker/docker v24.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0=
github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss=
github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE=
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/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/fxamacker/cbor v1.5.1 h1:XjQWBgdmQyqimslUh5r4tUGmoqzHmBFQOImkWGi2awg=
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-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-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ=
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
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/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE=
github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE=
github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ=
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/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/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.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
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/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
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/cel-go v0.14.1-0.20230424164844-d39523c445fc h1:jd+stC3Fqf9kaqgCLOdm4Da/AN3txPTlmLB6tStXAcU=
github.com/google/cel-go v0.14.1-0.20230424164844-d39523c445fc/go.mod h1:YzWEoI07MC/a/wj9in8GeVatqfypkldgBlwXh9bCwqY=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
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.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
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/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
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/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ=
github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
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/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/guoyk93/rg v1.0.1 h1:Rnca+1JYfuGqPRMIQkuxAoZhhmrPpMFyS5XwLz0U0ds=
github.com/guoyk93/rg v1.0.1/go.mod h1:tLaoLk8bo/PQld1xGvJvAfCl3K0Nckzh0gsnykFoQYg=
github.com/hashicorp/consul/api v1.25.1 h1:CqrdhYzc8XZuPnhIYZWH45toM0LB9ZeYr/gvpLVI3PE=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
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/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
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/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY=
github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
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/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/influxdata/line-protocol/v2 v2.2.1 h1:EAPkqJ9Km4uAxtMRgUubJyqAr6zgWM0dznKMLRauQRE=
github.com/influxdata/telegraf v1.28.2 h1:psX+oyjo9Ay9Pb/CEDxW9bWoxIWfL3GnzeFYvFJO1Y0=
github.com/influxdata/telegraf v1.28.2/go.mod h1:X3UcHLZQDVu8Y5GO4rOY1pr7TrwPLuW5OBf2RGBFjTE=
github.com/influxdata/toml v0.0.0-20190415235208-270119a8ce65 h1:vvyMtD5LTJc1W9sQKjDkAWdcg0478CszSdzlHtiAXCY=
github.com/influxdata/toml v0.0.0-20190415235208-270119a8ce65/go.mod h1:zApaNFpP/bTpQItGZNNUMISDMDAnTXu9UqJ4yT3ocz8=
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.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU=
github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8=
github.com/jeremywohl/flatten/v2 v2.0.0-20211013061545-07e4a09fb8e4 h1:eA9wi6ZzpIRobvXkn/S2Lyw1hr2pc71zxzOPl7Xjs4w=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
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/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4=
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
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/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
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/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/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
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/linkedin/goavro/v2 v2.12.0 h1:rIQQSj8jdAUlKQh6DttK8wCRv4t4QO09g1C4aBWXslg=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c h1:VtwQ41oftZwlMnOEbMWQtSEUgU64U4s+GHk7hZK+jtY=
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
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.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/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.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/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/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 h1:BpfhmLKZf+SjVanKKhCgf3bg+511DmU9eDQTen7LLbY=
github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo=
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
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/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks=
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
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/jwt/v2 v2.4.1 h1:Y35W1dgbbz2SQUYDPCaclXcuqleVmpbRa7646Jf2EX4=
github.com/nats-io/jwt/v2 v2.4.1/go.mod h1:24BeQtRwxRV8ruvC4CojXlx/WQ/VjuwlYiH+vu/+ibI=
github.com/nats-io/nats-server/v2 v2.9.9 h1:bmj0RhvHOc8+z5/RuhI38GqPwtkFAHQuU3e99FVA/TI=
github.com/nats-io/nats-server/v2 v2.9.9/go.mod h1:AB6hAnGZDlYfqb7CTAm66ZKMZy9DpfierY1/PbpvI2g=
github.com/nats-io/nats.go v1.30.2 h1:aloM0TGpPorZKQhbAkdCzYDj+ZmsJDyeo3Gkbr72NuY=
github.com/nats-io/nats.go v1.30.2/go.mod h1:dcfhUgmQNN4GJEfIb2f9R7Fow+gzBF4emzDHrVBd5qM=
github.com/nats-io/nkeys v0.4.5 h1:Zdz2BUlFm4fJlierwvGK+yl20IAKUm7eV6AAZXEhkPk=
github.com/nats-io/nkeys v0.4.5/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64=
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/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0=
github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/GDEs=
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/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c h1:NRoLoZvkBTKvR5gQLgA3e0hqjkY9u1wm+iOL45VN/qI=
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus-community/pro-bing v0.3.0 h1:SFT6gHqXwbItEDJhTkzPWVqU6CLEtqEfNAPp47RUON4=
github.com/prometheus-community/pro-bing v0.3.0/go.mod h1:p9dLb9zdmv+eLxWfCT6jESWuDrS+YzpPkQBgysQF8a0=
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
github.com/prometheus/client_model v0.4.0/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.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/prometheus/prometheus v0.46.0 h1:9JSdXnsuT6YsbODEhSQMwxNkGwPExfmzqG73vCMk/Kw=
github.com/prometheus/prometheus v0.46.0/go.mod h1:10L5IJE5CEsjee1FnOcVswYXlPIscDWWt3IJ2UDYrz4=
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.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
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/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE=
github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
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/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/srebhan/cborquery v0.0.0-20230626165538-38be85b82316 h1:HVv8JjpX24FuI59aET1uInn0ItuEiyj8CZMuR9Uw+lE=
github.com/srebhan/protobufquery v0.0.0-20230803132024-ae4c0d878e55 h1:ksmbrLbJAm+8yxB7fJ245usD0b1v9JHBJrWF+WqGyjs=
github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
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 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
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.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
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/testcontainers/testcontainers-go v0.22.0 h1:hOK4NzNu82VZcKEB1aP9LO1xYssVFMvlfeuDW9JMmV0=
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
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/vjeantet/grok v1.0.1 h1:2rhIR7J4gThTgcZ1m2JY4TrJZNgjn985U28kT2wQrJ4=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk=
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
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-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
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-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.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
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-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.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-20201110031124-69a78807bb2b/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.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
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.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/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-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-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-20201204225414-ed752295db88/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-20220715151400-c0bba94af5f8/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.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.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.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.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
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.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
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 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/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-20210106214847-113979e3529a/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.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
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/api v0.143.0 h1:o8cekTkqhywkbZT6p1UHJPZ9+9uuCAJs/KYomxZB8fA=
google.golang.org/api v0.143.0/go.mod h1:FoX9DO9hT7DLNn97OuoZAGSDuNAXdJRuGK98rSUgurk=
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 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb h1:lK0oleSc7IQsUxO3U5TjL9DWlsxpEBemh+zpB7IqhWI=
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 h1:N3bU/SQDCDyD6R528GJ/PwW9KjYcJA3dgyH+MovAkIM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA=
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/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I=
google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
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.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
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/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
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/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 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/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 h1:BYfdVuZB5He/u9dt4qDpZqiqDJ6KhPqs5QUqsr/Eeuc=
gorm.io/driver/sqlite v1.1.3/go.mod h1:AKDgRWk8lcSQSw+9kxCJnX/yySj8G3rdwYlU57cB45c=
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.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=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
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=
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw=
k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ=
k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY=
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ=
k8s.io/utils v0.0.0-20230711102312-30195339c3c7 h1:ZgnF1KZsYxWIifwSNZFZgNtWE89WI5yiP5WwlfDoIyc=
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=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=

View File

@ -0,0 +1,30 @@
package command
import (
"fmt"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/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")
}

View File

@ -0,0 +1,7 @@
package command
import "fmt"
func demo() {
fmt.Println("hello console!")
}

View File

@ -0,0 +1,54 @@
package controller
import (
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/pkg/errors"
r "git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/pkg/response"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/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.Error("异常: %s", 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())
}

View File

@ -0,0 +1,69 @@
package v1
import (
"encoding/json"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config/agent"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/controller"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/pkg/errors"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/pkg/request"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/service/component"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/service/load_resource_info"
"github.com/gin-gonic/gin"
"io"
)
func AssetInformationEntry(c *gin.Context) {
body := request.GetBody(c)
var rinfo = agent.AgentConfig{}
err := json.Unmarshal(body, &rinfo)
if err != nil {
controller.FailCode(c, errors.ServerError, err, "更新资产信息失败!")
return
}
agent.Agent = &rinfo
load_resource_info.LoadAgentInfo(rinfo)
controller.Success(c, "配置初始化完成")
}
func GetComponentInfo(c *gin.Context) {
info, err := component.GetComInfo()
if err != nil {
controller.FailCode(c, errors.ServerError, err, "获取组件详情失败!")
return
}
controller.Success(c, info)
}
func UpdateTelegrafConfig(c *gin.Context) {
_, fileHeader, err := c.Request.FormFile("telegraf-config")
if err != nil {
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数(body)是否符合要求!")
return
}
src, err := fileHeader.Open()
if err != nil {
controller.FailCode(c, errors.InvalidParameter, err, "请检查参数(body)是否符合要求!")
return
}
defer src.Close()
var out []byte
out, _ = io.ReadAll(src)
component.UpdateTelegrafConfig(out)
if err != nil {
controller.FailCode(c, errors.ServerError, err, "请检查参数(body)是否符合要求!")
return
}
controller.Success(c, "完成配置文件更新!")
}
func RecoverConfig(c *gin.Context) {
component.RecoverConfig()
controller.Success(c, "完成配置文件恢复!")
}

View File

@ -0,0 +1,16 @@
package v1
import (
"fmt"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/controller"
"github.com/gin-gonic/gin"
)
func HelloWorld(c *gin.Context) {
str, ok := c.GetQuery("name")
if !ok {
str = "gin-layout"
}
controller.Success(c, fmt.Sprintf("hello %s", str))
}

View File

@ -0,0 +1,21 @@
package v1
import (
"fmt"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/nats_service/definition"
"github.com/gin-gonic/gin"
"net/http"
"path/filepath"
)
func DownloadAgent(c *gin.Context) {
filename := c.Query("filename")
c.Writer.WriteHeader(http.StatusOK)
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
c.Header("Content-Type", "application/octet-stream")
versionedAgent := filepath.Join(definition.RunDirectory, "../upgrade", filename)
c.File(versionedAgent)
}

View File

@ -0,0 +1,54 @@
package v1
import (
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/controller"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/pkg/errors"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/service/log_service"
"github.com/gin-gonic/gin"
"strconv"
)
func GetAgentLog(c *gin.Context) {
lineNum := c.Query("lines")
lineUnit, err2 := strconv.ParseUint(lineNum, 10, 64)
if err2 != nil {
lineUnit = 100
}
info, err := log_service.GetAgentLog(lineUnit)
if err != nil {
controller.FailCode(c, errors.ServerError, err, "读取日志失败!")
return
}
controller.Success(c, info)
}
func GetAgentUpgradeLog(c *gin.Context) {
lineNum := c.Query("lines")
lineUnit, err2 := strconv.ParseUint(lineNum, 10, 64)
if err2 != nil {
lineUnit = 100
}
info, err := log_service.GetAgentUpgradeLog(lineUnit)
if err != nil {
controller.FailCode(c, errors.ServerError, err, "读取日志失败!")
return
}
controller.Success(c, info)
}
func GetTelegrafLog(c *gin.Context) {
lineNum := c.Query("lines")
lineUnit, err2 := strconv.ParseUint(lineNum, 10, 64)
if err2 != nil {
lineUnit = 100
}
info, err := log_service.GetTelegrafLog(lineUnit)
if err != nil {
controller.FailCode(c, errors.ServerError, err, "读取日志失败!")
return
}
controller.Success(c, info)
}

View File

@ -0,0 +1,13 @@
package v1
import (
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/controller"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/utils"
"github.com/gin-gonic/gin"
"os"
)
func Shutdown(c *gin.Context) {
utils.ChUserSig <- os.Interrupt
controller.Success(c, "关闭命令已发送!")
}

View 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()
}
}

View File

@ -0,0 +1,81 @@
package middleware
import (
"fmt"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/pkg/authen"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/pkg/errors"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/pkg/response"
"github.com/gin-gonic/gin"
"github.com/golang/glog"
"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
}
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
}
var username, encrypted string
ok, bearerToken := authen.JWTAuthorizer.IsBearerToken(rawToken)
if ok {
loginInfo, err := authen.JWTAuthorizer.ValidateToken(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
encrypted = loginInfo.Encrypted
} else {
glog.Warningf("validate bearer token failed")
response.Resp().FailCode(c, errors.AuthorizationError, "validate bearer token failed")
return
}
//u, err := user.FindOneByName(username, model.DBAuth())
//if err != nil {
// 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 encrypted != "" && encrypted != u.EncryptedPassword {
// glog.Warningf("unauthorized access, password mismatch, user %s", username)
// response.Resp().FailCode(c, errors.AuthorizationError, "password mismatch")
// return
//}
//c.Set(LoginUserKey, u)
c.Set(LoginUserKey, username+":"+encrypted)
c.Next()
}
}

View File

@ -0,0 +1,26 @@
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
}
_, exist := c.Get(LoginUserKey)
if !exist {
glog.Fatal("Authorization middleware should work together with Authentication middleware")
c.Next()
return
}
c.Next()
}
}

View 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()
}

View File

@ -0,0 +1,53 @@
package middleware
import (
"bytes"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/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()),
)
}
}
}

View File

@ -0,0 +1,40 @@
package middleware
import (
"errors"
"fmt"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config"
e "git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/pkg/errors"
response2 "git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/pkg/response"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/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)
}

View 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()
}
}

View File

@ -0,0 +1,40 @@
package model
import (
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/data"
"gorm.io/gorm"
"gorm.io/plugin/soft_delete"
"time"
)
type PageData struct {
TotalCount int64
PageSize int
PageNumber int
Data interface{}
}
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 {
return data.PostgreSqlDB["data"]
}
func DBAuth() *gorm.DB {
return data.PostgreSqlDB["auth"]
}

View File

@ -0,0 +1,30 @@
package component
import "time"
// 组件详情
type Component struct {
COMName string `json:"comName"` // 组件名称枚举Telegraf、ProcessExporter
COMPort int64 `json:"comPort"` // 组件端口
COMType string `json:"comType"` // 组件类型,中文描述既可
COMVersion string `json:"comVersion"` // 组件版本
Config Config `json:"config"` // 组件配置(传json字符串),每个组件的信息不同
LastStarttime time.Time `json:"lastStarttime"` // 最近运行时间, 2023-08-16 00:00:00
Status string `json:"status"` // 组件状态0:离线1:在线2:故障
}
// Config 组件配置(传json字符串),每个组件的信息不同
//
// # Telegraf配置
//
// ProcessExporter配置
type Config struct {
Metrics []string `json:"metrics,omitempty"`
MetricServer []MetricServer `json:"metricServer,omitempty"` // 指标服务器名称
Tags map[string]string `json:"tags,omitempty"` // 标签map[string]string类型
}
type MetricServer struct {
Address string `json:"address"` // 指标服务器地址
Name string `json:"name"` // 指标服务器名称
}

View File

@ -0,0 +1,28 @@
package heartbeat
import "time"
// 1.返回应用一体机开机后运行时间和开始时间
// 2.返回CPU、内存、网卡等配置信息、型号信息、操作系统信息硬盘信息等
// HeartBeat 一体机-心跳检测信息
type HeartBeat struct {
SerialNo string `json:"serialNo"` // 序列号
AgentVersion string `json:"agentVersion"` // 小助手版本
IPAddress string `json:"ipAddress"` // ip地址多个逗号分割
MACAddress string `json:"macAddress"` // mac地址
Architecture string `json:"archType"` // architecture
KernelVersion string `json:"kernelVersion"` // kernel_version
OS string `json:"osInfo"` // os
OSType string `json:"osType"` // os
LastStarttime time.Time `json:"lastStarttime"` // 最近开机时间, 2023-08-16 00:00:00 - 2023-08-16 23:59:59
COMInfo []COMInfo `json:"comInfo"` // 组件信息
}
type COMInfo struct {
LastStarttime time.Time `json:"lastStarttime"` // 最近运行时间, 2023-08-16 00:00:00
Name string `json:"name"` // 组件名称
Status string `json:"status"` // 组件状态0:离线1:在线2:故障
}

View File

@ -0,0 +1,7 @@
package heartbeat
type HeartbeatResponse struct {
ID int `gorm:"column:user_id"`
Name string `gorm:"column:login_name"`
EncryptedPassword string `gorm:"column:login_pass"`
}

View File

@ -0,0 +1,29 @@
package nats_msg_model
import "encoding/json"
func UnmarshalLocalUpgradeCMD(data []byte) (LocalUpgradeCMD, error) {
var r LocalUpgradeCMD
err := json.Unmarshal(data, &r)
return r, err
}
func (r *LocalUpgradeCMD) Marshal() ([]byte, error) {
return json.Marshal(r)
}
type LocalUpgradeCMD struct {
AgentId string `json:"agentId"` // 需要关联升级记录
// 备用
DownUrl string `json:"downUrl"`
Filename string `json:"filename"`
Version string `json:"version"`
Command string `json:"command"`
CompressionType string `json:"compressionType"` // tar.gz or zip
IP string `json:"ip"`
Port uint16 `json:"port"`
OsType string `json:"osType"` // 字典Windows\Ubuntu\CentOS\KylinOS
ArchType string `json:"archType"` // 字典: X86\ARM
//DeviceType string `json:"deviceType"` // 设备类型;0:为全部1应用一体机2调度一体机3纳管一体机
}

View File

@ -0,0 +1,20 @@
package nats_msg_model
import "encoding/json"
func UnmarshalMsgModel(data []byte) (MsgModel, error) {
var r MsgModel
err := json.Unmarshal(data, &r)
return r, err
}
func (r *MsgModel) Marshal() ([]byte, error) {
return json.Marshal(r)
}
type MsgModel struct {
Body []byte `json:"body"` // 函数入参与函数配套。JSON
Func string `json:"func"` // 功能名称一般代表一个函数接口。命名规范为cfn.{agent or schedule}.{包名}.函数名例如cfn.agent.component.GetComInfo
Rid string `json:"rid"` // 资产ID列表可选。可用于部分广播
Version string `json:"version"` // 函数版本
}

View File

@ -0,0 +1,25 @@
package nats_msg_model
import "encoding/json"
func UnmarshalUpgradeCMD(data []byte) (UpgradeCMD, error) {
var r UpgradeCMD
err := json.Unmarshal(data, &r)
return r, err
}
func (r *UpgradeCMD) Marshal() ([]byte, error) {
return json.Marshal(r)
}
type UpgradeCMD struct {
AgentId string `json:"agentId"`
DownUrl string `json:"downUrl"`
BucketName string `json:"bucketName"`
Filename string `json:"filename"`
CompressionType string `json:"compressionType"`
Command string `json:"command"`
Version string `json:"version"`
OsType string `json:"osType"` //字典Windows\Ubuntu\CentOS\KylinOS
ArchType string `json:"archType"` //字典: X86\ARM
}

View File

@ -0,0 +1,25 @@
package nats_msg_model
import "encoding/json"
func UnmarshalUpgradePlan(data []byte) (UpgradePlan, error) {
var r UpgradePlan
err := json.Unmarshal(data, &r)
return r, err
}
func (r *UpgradePlan) Marshal() ([]byte, error) {
return json.Marshal(r)
}
type UpgradePlan struct {
UpgradeTime string `json:"upgradeTime" yaml:"upgradeTime"` //指定升级时间;指定时间升级时有值
UpgradeRule string `json:"upgradeRule" yaml:"upgradeRule"` //升级策略;0:立刻升级1:指定时间升级
DeviceType string `json:"deviceType" yaml:"deviceType"` //设备类型;0:为全部1应用一体机2调度一体机3纳管一体机
Status string `json:"status" yaml:"status"` //字典create创建此条升级规则delete删除升级规则
AgentId string `json:"agentId" yaml:"agentId"` // 关联升级记录,反馈升级结果时用
Option string `json:"option" yaml:"option"` // reboot|upgrade|rollback # 动作
Version string `json:"version" yaml:"version"`
CurrentVerson string `json:"currentVerson" yaml:"currentVerson"`
RID string `json:"rid" yaml:"rid" mapstructure:"rid"`
}

View File

@ -0,0 +1,74 @@
package nats_msg_model
import (
"encoding/json"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config/agent"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/service/heartbeat_service"
"time"
)
func UnmarshalUpgradeResult(data []byte) (UpgradeResult, error) {
var r UpgradeResult
err := json.Unmarshal(data, &r)
return r, err
}
func (r *UpgradeResult) Marshal() ([]byte, error) {
return json.Marshal(r)
}
// 设备升级记录
type UpgradeResult struct {
SerialNo string `json:"serialNo"` // 序列号
AgentID string `json:"agentId"` // 小助手版本ID
AgentVersion string `json:"agentVersion"` // 升级版本
OldVersion string `json:"oldVersion"` // 旧版本
UpgradeTime string `json:"upgradeTime"` // 升级时间2016-06-30T16:09:51.692226358+08:00
UpgradeResult string `json:"upgradeResult"` // 升级结果
UpgradeStatus string `json:"upgradeStatus"` // 状态0:失败1:成功
Option string `json:"option"`
}
func NewUpgradeResult(upgradeCMD UpgradeCMD, upgradeResult, UpgradeStatus string) *UpgradeResult {
result := UpgradeResult{
SerialNo: agent.Agent.RID,
AgentID: upgradeCMD.AgentId,
AgentVersion: upgradeCMD.Version,
OldVersion: heartbeat_service.AgentState.AgentVersion,
UpgradeTime: time.Now().String(),
UpgradeStatus: UpgradeStatus,
UpgradeResult: upgradeResult,
Option: "upgrade",
}
return &result
}
func NewLocalUpgradeResult(upgradeCMD LocalUpgradeCMD, upgradeResult, UpgradeStatus string) *UpgradeResult {
result := UpgradeResult{
SerialNo: agent.Agent.RID,
AgentID: upgradeCMD.AgentId,
AgentVersion: upgradeCMD.Version,
OldVersion: heartbeat_service.AgentState.AgentVersion,
UpgradeTime: time.Now().String(),
UpgradeStatus: UpgradeStatus,
UpgradeResult: upgradeResult,
Option: "upgrade",
}
return &result
}
func NewUpgradePlanResult(upgradePlan UpgradePlan, upgradeResult, UpgradeStatus string) *UpgradeResult {
result := UpgradeResult{
SerialNo: agent.Agent.RID,
AgentID: upgradePlan.AgentId,
AgentVersion: upgradePlan.Version,
OldVersion: heartbeat_service.AgentState.AgentVersion,
UpgradeTime: time.Now().String(),
UpgradeStatus: UpgradeStatus,
UpgradeResult: upgradeResult,
Option: "upgrade",
}
return &result
}

View File

@ -0,0 +1,30 @@
package user
import "gorm.io/gorm"
type User struct {
ID int `gorm:"column:user_id"`
Name string `gorm:"column:login_name"`
EncryptedPassword string `gorm:"column:login_pass"`
}
func (User) TableName() string {
return "sys_account"
}
func (m User) GetUserID() int {
return m.ID
}
func (m User) GetUserName() string {
return m.Name
}
func FindOneByName(name string, db *gorm.DB) (user *User, err error) {
var u User
if err = db.Where("login_name = ?", name).First(&u).Error; err != nil {
return
}
user = &u
return
}

View File

@ -0,0 +1,76 @@
package cfn_to_agent_broadcast
import (
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config/agent"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/model/nats_msg_model"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/nats_service/definition"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/nats_service/handle"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/log"
natsClient "git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/nats-client"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/utils"
"github.com/nats-io/nats.go"
"time"
)
var (
Role = agent.Agent.Role
)
// 小助手升级包下载命令接收接口
// 升级计划下发
func Start() {
log.Infof("启动nats订阅服务: 升级助手命令广播")
// Connect Options.
opts := []nats.Option{nats.Name("Agent CMD Subscriber")}
opts = setupConnOptions(opts)
opts = append(opts, nats.UserInfo(natsClient.NatsConfig.User, natsClient.NatsConfig.Password))
// Connect to NATS
nc, err := nats.Connect(natsClient.NatsConfig.Url, opts...)
if err != nil {
log.Error(err)
}
nc.Subscribe(definition.ToAgentBroadcastSubject, func(msg *nats.Msg) {
model, err := nats_msg_model.UnmarshalMsgModel(msg.Data)
if err != nil {
log.Errorf("解析消息体失败:%s", err)
}
log.Infof("接收到广播命令消息, Func:%s", model.Func)
log.Infof("接收到广播命令消息, Body:%s", model.Body)
log.Infof("接收到广播命令消息, Version:%s", model.Version)
log.Infof("接收到广播命令消息, Rid:%s", model.Rid)
go handle.HandleMsg(msg, model)
})
nc.Flush()
if err := nc.LastError(); err != nil {
log.Error(err)
}
// holdon
<-utils.StopNats
}
func setupConnOptions(opts []nats.Option) []nats.Option {
totalWait := 10 * time.Minute
reconnectDelay := time.Second
opts = append(opts, nats.ReconnectWait(reconnectDelay))
opts = append(opts, nats.MaxReconnects(int(totalWait/reconnectDelay)))
opts = append(opts, nats.DisconnectErrHandler(func(nc *nats.Conn, err error) {
log.Infof("Disconnected due to:%s, will attempt reconnects for %.0fm", err, totalWait.Minutes())
}))
opts = append(opts, nats.ReconnectHandler(func(nc *nats.Conn) {
log.Infof("Reconnected [%s]", nc.ConnectedUrl())
}))
opts = append(opts, nats.ClosedHandler(func(nc *nats.Conn) {
log.Errorf("Exiting: %v", nc.LastError())
}))
return opts
}

View File

@ -0,0 +1,67 @@
package cfn_to_agent_broadcast_private_enterprise
import (
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/model/nats_msg_model"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/nats_service/definition"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/nats_service/handle"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/log"
natsClient "git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/nats-client"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/utils"
"github.com/nats-io/nats.go"
"time"
)
func Start() {
log.Infof("启动nats订阅服务: 企业私有广播")
// Connect Options.
opts := []nats.Option{nats.Name("Enterprise Private Broadcast Subscriber")}
opts = setupConnOptions(opts)
opts = append(opts, nats.UserInfo(natsClient.NatsConfig.User, natsClient.NatsConfig.Password))
// Connect to NATS
nc, err := nats.Connect(natsClient.NatsConfig.Url, opts...)
if err != nil {
log.Error(err)
}
nc.Subscribe(definition.ToAgentBroadcastPrivateEnterpriseSubject, func(msg *nats.Msg) {
model, err := nats_msg_model.UnmarshalMsgModel(msg.Data)
if err != nil {
log.Errorf("解析消息体失败:%s", err)
}
log.Infof("接收到企业内私有广播命令消息, Func:%s", model.Func)
log.Infof("接收到企业内私有广播命令消息, Body:%s", model.Body)
log.Infof("接收到企业内私有广播命令消息, Version:%s", model.Version)
log.Infof("接收到企业内私有广播命令消息, Rid:%s", model.Rid)
go handle.HandleMsg(msg, model)
})
nc.Flush()
if err := nc.LastError(); err != nil {
log.Error(err)
}
// holdon
<-utils.StopNats
}
func setupConnOptions(opts []nats.Option) []nats.Option {
totalWait := 10 * time.Minute
reconnectDelay := time.Second
opts = append(opts, nats.ReconnectWait(reconnectDelay))
opts = append(opts, nats.MaxReconnects(int(totalWait/reconnectDelay)))
opts = append(opts, nats.DisconnectErrHandler(func(nc *nats.Conn, err error) {
log.Infof("Disconnected due to:%s, will attempt reconnects for %.0fm", err, totalWait.Minutes())
}))
opts = append(opts, nats.ReconnectHandler(func(nc *nats.Conn) {
log.Infof("Reconnected [%s]", nc.ConnectedUrl())
}))
opts = append(opts, nats.ClosedHandler(func(nc *nats.Conn) {
log.Errorf("Exiting: %v", nc.LastError())
}))
return opts
}

View File

@ -0,0 +1,67 @@
package cfn_to_agent_broadcast_public_enterprice
import (
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/model/nats_msg_model"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/nats_service/definition"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/nats_service/handle"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/log"
natsClient "git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/nats-client"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/utils"
"github.com/nats-io/nats.go"
"time"
)
func Start() {
log.Infof("启动nats订阅服务: 企业公共广播")
// Connect Options.
opts := []nats.Option{nats.Name("Enterprise Public Broadcast Subscriber")}
opts = setupConnOptions(opts)
opts = append(opts, nats.UserInfo(natsClient.NatsConfig.User, natsClient.NatsConfig.Password))
// Connect to NATS
nc, err := nats.Connect(natsClient.NatsConfig.Url, opts...)
if err != nil {
log.Error(err)
}
nc.Subscribe(definition.ToAgentBroadcastPublicEnterpriseSubject, func(msg *nats.Msg) {
model, err := nats_msg_model.UnmarshalMsgModel(msg.Data)
if err != nil {
log.Errorf("解析消息体失败:%s", err)
}
log.Infof("接收到企业公共广播命令消息, Func:%s", model.Func)
log.Infof("接收到企业公共广播命令消息, Body:%s", model.Body)
log.Infof("接收到企业公共广播命令消息, Version:%s", model.Version)
log.Infof("接收到企业公共广播命令消息, Rid:%s", model.Rid)
go handle.HandleMsg(msg, model)
})
nc.Flush()
if err := nc.LastError(); err != nil {
log.Error(err)
}
// holdon
<-utils.StopNats
}
func setupConnOptions(opts []nats.Option) []nats.Option {
totalWait := 10 * time.Minute
reconnectDelay := time.Second
opts = append(opts, nats.ReconnectWait(reconnectDelay))
opts = append(opts, nats.MaxReconnects(int(totalWait/reconnectDelay)))
opts = append(opts, nats.DisconnectErrHandler(func(nc *nats.Conn, err error) {
log.Infof("Disconnected due to:%s, will attempt reconnects for %.0fm", err, totalWait.Minutes())
}))
opts = append(opts, nats.ReconnectHandler(func(nc *nats.Conn) {
log.Infof("Reconnected [%s]", nc.ConnectedUrl())
}))
opts = append(opts, nats.ClosedHandler(func(nc *nats.Conn) {
log.Errorf("Exiting: %v", nc.LastError())
}))
return opts
}

View File

@ -0,0 +1,73 @@
package cfn_to_agent_unicast
import (
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/model/nats_msg_model"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/nats_service/definition"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/nats_service/handle"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/log"
natsClient "git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/nats-client"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/utils"
"github.com/nats-io/nats.go"
"time"
)
// 系统(小助手)日志查询服务
// 组件详情服务(包含配置内容)
// 更新telegraf配置文件
// 单个升级(包含升级包地址、升级配置)
func Start() {
log.Infof("启动nats订阅服务: 单播命令")
// Connect Options.
opts := []nats.Option{nats.Name("Agent Unicast Subscriber")}
opts = setupConnOptions(opts)
opts = append(opts, nats.UserInfo(natsClient.NatsConfig.User, natsClient.NatsConfig.Password))
// Connect to NATS
nc, err := nats.Connect(natsClient.NatsConfig.Url, opts...)
if err != nil {
log.Errorf("连接nats失败%s", err)
}
nc.Subscribe(definition.ToAgentUnicastSubject, func(msg *nats.Msg) {
model, err := nats_msg_model.UnmarshalMsgModel(msg.Data)
if err != nil {
log.Errorf("解析消息体失败:%s", err)
}
log.Infof("接收到单播命令消息, Func:%s", model.Func)
log.Infof("接收到单播命令消息, Body:%s", model.Body)
log.Infof("接收到单播命令消息, Version:%s", model.Version)
log.Infof("接收到单播命令消息, Rid:%s", model.Rid)
go handle.HandleMsg(msg, model)
})
nc.Flush()
if err := nc.LastError(); err != nil {
log.Error(err)
}
// holdon
<-utils.StopNats
}
func setupConnOptions(opts []nats.Option) []nats.Option {
totalWait := 10 * time.Minute
reconnectDelay := time.Second
opts = append(opts, nats.ReconnectWait(reconnectDelay))
opts = append(opts, nats.MaxReconnects(int(totalWait/reconnectDelay)))
opts = append(opts, nats.DisconnectErrHandler(func(nc *nats.Conn, err error) {
log.Infof("Disconnected due to:%s, will attempt reconnects for %.0fm", err, totalWait.Minutes())
}))
opts = append(opts, nats.ReconnectHandler(func(nc *nats.Conn) {
log.Infof("Reconnected [%s]", nc.ConnectedUrl())
}))
opts = append(opts, nats.ClosedHandler(func(nc *nats.Conn) {
log.Errorf("Exiting: %v", nc.LastError())
}))
return opts
}

View File

@ -0,0 +1,98 @@
package asset_info
import (
"encoding/json"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config/agent"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/model/nats_msg_model"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/nats_service/definition"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/service/heartbeat_service"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/service/load_resource_info"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/log"
nats_client "git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/nats-client"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/utils/randomutils"
"time"
)
func Strat() {
InitAssertInfoScheduler()
}
func InitAssertInfoScheduler() {
log.Infof("启动资产上报服务")
randomNumber := randomutils.GetRandomNumber(-3600, 3600)
// 每天执行一次
ticker := time.NewTicker((60*60*24 + time.Duration(randomNumber)) * time.Second) // 创建一个定时器
go func() {
for {
select {
case <-ticker.C:
updataAssertInfoMq()
doAssertInfoMQ()
}
}
}()
go func() {
updataAssertInfoMq()
// 开机后先上传一次(复用心跳)
doAssertInfoMQ()
}()
}
func updataAssertInfoMq() {
rid := nats_msg_model.MsgModel{
Func: definition.GETCOMPANY,
Body: []byte(agent.Agent.RID),
Version: "v1",
Rid: agent.Agent.RID,
}
marshal, _ := rid.Marshal()
msg, err := nats_client.Request(definition.ToScheduleQueueSubject, marshal)
if err != nil {
log.Errorf("获取资产信息失败(企业、资产类型):%s", err)
return
}
if msg == nil || msg.Data == nil {
log.Errorf("获取资产信息为空!")
return
}
var resp = definition.Response{}
err = json.Unmarshal(msg.Data, &resp)
if resp.Code == 200 {
var rinfo = agent.AgentConfig{}
err = json.Unmarshal(resp.Data, &rinfo)
agent.Agent.Enterprise = rinfo.Enterprise
agent.Agent.Type = rinfo.Type
load_resource_info.LoadAgentInfo(*agent.Agent)
} else {
log.Infof("资产信息获取失败:%s", resp.Msg)
return
}
}
// 1.返回应用一体机开机后运行时间和开始时间
// 2.返回CPU、内存、网卡等配置信息、型号信息、操作系统信息硬盘信息等
func doAssertInfoMQ() {
bytes, err := json.Marshal(heartbeat_service.AgentState)
if err != nil {
log.Infof("上报心跳信息序列化失败:%s", err)
return
}
msg := nats_msg_model.MsgModel{
Func: definition.ASSETINFO,
Body: bytes,
Version: "v1",
Rid: agent.Agent.RID,
}
marshal, _ := msg.Marshal()
log.Infof("上报资产信息")
nats_client.Publish(definition.ToScheduleSubject, marshal)
}

View File

@ -0,0 +1,237 @@
package asset_info
import (
"fmt"
"net"
"strings"
"syscall"
"time"
"unsafe"
"github.com/StackExchange/wmi"
)
var (
advapi = syscall.NewLazyDLL("Advapi32.dll")
kernel = syscall.NewLazyDLL("Kernel32.dll")
)
// 开机时间
func GetStartTime() string {
GetTickCount := kernel.NewProc("GetTickCount")
r, _, _ := GetTickCount.Call()
if r == 0 {
return ""
}
ms := time.Duration(r * 1000 * 1000)
return ms.String()
}
// 当前用户名
func GetUserName() string {
var size uint32 = 128
var buffer = make([]uint16, size)
user := syscall.StringToUTF16Ptr("USERNAME")
domain := syscall.StringToUTF16Ptr("USERDOMAIN")
r, err := syscall.GetEnvironmentVariable(user, &buffer[0], size)
if err != nil {
return ""
}
buffer[r] = '@'
old := r + 1
if old >= size {
return syscall.UTF16ToString(buffer[:r])
}
r, err = syscall.GetEnvironmentVariable(domain, &buffer[old], size-old)
return syscall.UTF16ToString(buffer[:old+r])
}
// 系统版本
func GetSystemVersion() string {
version, err := syscall.GetVersion()
if err != nil {
return ""
}
return fmt.Sprintf("%d.%d (%d)", byte(version), uint8(version>>8), version>>16)
}
type diskusage struct {
Path string `json:"path"`
Total uint64 `json:"total"`
Free uint64 `json:"free"`
}
func usage(getDiskFreeSpaceExW *syscall.LazyProc, path string) (diskusage, error) {
lpFreeBytesAvailable := int64(0)
var info = diskusage{Path: path}
diskret, _, err := getDiskFreeSpaceExW.Call(
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(info.Path))),
uintptr(unsafe.Pointer(&lpFreeBytesAvailable)),
uintptr(unsafe.Pointer(&(info.Total))),
uintptr(unsafe.Pointer(&(info.Free))))
if diskret != 0 {
err = nil
}
return info, err
}
// 硬盘信息
func GetDiskInfo() (infos []diskusage) {
GetLogicalDriveStringsW := kernel.NewProc("GetLogicalDriveStringsW")
GetDiskFreeSpaceExW := kernel.NewProc("GetDiskFreeSpaceExW")
lpBuffer := make([]byte, 254)
diskret, _, _ := GetLogicalDriveStringsW.Call(
uintptr(len(lpBuffer)),
uintptr(unsafe.Pointer(&lpBuffer[0])))
if diskret == 0 {
return
}
for _, v := range lpBuffer {
if v >= 65 && v <= 90 {
path := string(v) + ":"
if path == "A:" || path == "B:" {
continue
}
info, err := usage(GetDiskFreeSpaceExW, string(v)+":")
if err != nil {
continue
}
infos = append(infos, info)
}
}
return infos
}
// CPU信息
// 简单的获取方法fmt.Sprintf("Num:%d Arch:%s\n", runtime.NumCPU(), runtime.GOARCH)
func GetCpuInfo() string {
var size uint32 = 128
var buffer = make([]uint16, size)
var index = uint32(copy(buffer, syscall.StringToUTF16("Num:")) - 1)
nums := syscall.StringToUTF16Ptr("NUMBER_OF_PROCESSORS")
arch := syscall.StringToUTF16Ptr("PROCESSOR_ARCHITECTURE")
r, err := syscall.GetEnvironmentVariable(nums, &buffer[index], size-index)
if err != nil {
return ""
}
index += r
index += uint32(copy(buffer[index:], syscall.StringToUTF16(" Arch:")) - 1)
r, err = syscall.GetEnvironmentVariable(arch, &buffer[index], size-index)
if err != nil {
return syscall.UTF16ToString(buffer[:index])
}
index += r
return syscall.UTF16ToString(buffer[:index+r])
}
type memoryStatusEx struct {
cbSize uint32
dwMemoryLoad uint32
ullTotalPhys uint64 // in bytes
ullAvailPhys uint64
ullTotalPageFile uint64
ullAvailPageFile uint64
ullTotalVirtual uint64
ullAvailVirtual uint64
ullAvailExtendedVirtual uint64
}
// 内存信息
func GetMemory() string {
GlobalMemoryStatusEx := kernel.NewProc("GlobalMemoryStatusEx")
var memInfo memoryStatusEx
memInfo.cbSize = uint32(unsafe.Sizeof(memInfo))
mem, _, _ := GlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memInfo)))
if mem == 0 {
return ""
}
return fmt.Sprint(memInfo.ullTotalPhys/(1024*1024)) + "MB"
}
type intfInfo struct {
Name string
Ipv4 []string
Ipv6 []string
}
// 网卡信息
func GetIntfs() []intfInfo {
intf, err := net.Interfaces()
if err != nil {
return []intfInfo{}
}
//fmt.Println(intf)
var is = make([]intfInfo, len(intf))
for i, v := range intf {
if (v.Flags & net.FlagBroadcast) > 0 {
ips, err := v.Addrs()
if err != nil {
continue
}
is[i].Name = v.Name
for _, ip := range ips {
if strings.Contains(ip.String(), ":") {
is[i].Ipv6 = append(is[i].Ipv6, ip.String())
} else {
is[i].Ipv4 = append(is[i].Ipv4, ip.String())
}
}
}
}
return is
}
// 主板信息
func GetMoreCpuInfo() string {
var s = []struct {
Name string
}{}
err := wmi.Query("SELECT * FROM Win32_Processor", &s)
if err != nil {
return ""
}
return s[0].Name
}
// 主板信息
func GetMotherboardInfo() string {
var s = []struct {
Product string
}{}
err := wmi.Query("SELECT Product FROM Win32_BaseBoard WHERE (Product IS NOT NULL)", &s)
if err != nil {
return ""
}
return s[0].Product
}
// SerialNumber信息
func GetSerialNumber() string {
var s = []struct {
SerialNumber string
}{}
err := wmi.Query("SELECT SerialNumber FROM Win32_DiskDrive WHERE (SerialNumber IS NOT NULL) ", &s) //AND (MediaType LIKE 'Fixed hard disk%')
if err != nil {
return ""
}
fmt.Println(s)
fmt.Println("====SerialNumber===")
return s[0].SerialNumber
}
// BIOS信息
func GetBiosInfo() string {
var s = []struct {
Name string
}{}
err := wmi.Query("SELECT Name FROM Win32_BIOS WHERE (Name IS NOT NULL)", &s) // WHERE (BIOSVersion IS NOT NULL)
if err != nil {
return ""
}
return s[0].Name
}

View File

@ -0,0 +1,32 @@
package asset_info
import (
"fmt"
"runtime"
"testing"
)
func TestGetBiosInfo(t *testing.T) {
fmt.Printf("开机时长:%s\n", GetStartTime())
fmt.Printf("当前用户:%s\n", GetUserName())
fmt.Printf("当前系统:%s\n", runtime.GOOS)
fmt.Printf("系统版本:%s\n", GetSystemVersion())
fmt.Printf("Bios:%s\n", GetBiosInfo())
fmt.Printf("Motherboard:\t%s\n", GetMotherboardInfo())
fmt.Printf("CPU:\t%s\n", GetCpuInfo())
fmt.Printf("CPU:\t%s\n", GetMoreCpuInfo())
fmt.Printf("Memory:\t%s\n", GetMemory())
fmt.Printf("Disk:\t%v\n", GetDiskInfo())
intfs := GetIntfs()
for _, i := range intfs {
fmt.Printf("Interfaces:\t%v\n", i)
}
number := GetSerialNumber()
fmt.Printf("number:\t%v\n", number)
}

View File

@ -0,0 +1,58 @@
package heartbeat
import (
"encoding/json"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config/agent"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/model/nats_msg_model"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/nats_service/definition"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/service/heartbeat_service"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/log"
natsClient "git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/nats-client"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/utils/randomutils"
"time"
)
var (
commonConfig = config.Config
)
func Strat() {
InitHeartBeatScheduler()
}
// InitHeartBeatScheduler
// 初始化 heartbeat 定时器
func InitHeartBeatScheduler() {
log.Infof("启动心跳服务")
// 每 30 秒钟时执行一次
randomNumber := randomutils.GetRandomNumber(-10, 10)
ticker := time.NewTicker(time.Duration(commonConfig.Schedule.HeartBeat+int64(randomNumber)) * time.Second) // 创建一个定时器
go func() {
for {
select {
case <-ticker.C:
doHeartBeatMQ()
}
}
}()
}
func doHeartBeatMQ() {
bytes, err := json.Marshal(heartbeat_service.AgentState)
if err != nil {
log.Infof("上报心跳信息序列化失败:%s", err)
return
}
msg := nats_msg_model.MsgModel{
Func: definition.HEALTHCHECK,
Body: bytes,
Version: "v1",
Rid: agent.Agent.RID,
}
marshal, _ := msg.Marshal()
log.Infof("上报心跳")
natsClient.Publish(definition.ToScheduleSubject, marshal)
}

View File

@ -0,0 +1,11 @@
package definition
import (
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/utils"
"path/filepath"
)
var (
RunDirectory, _ = utils.GetCurrentPath()
CompressedAgentPath = filepath.Join(RunDirectory, "../upgrade")
)

View File

@ -0,0 +1,18 @@
package definition
const (
HEALTHCHECK = "cfn.schedule.health.probe"
ASSETINFO = "cfn.schedule.asset.base_info"
GETCOMPANY = "cfn.schedule.asset.company"
// AGENTUPGRADERESULT = "cfn.schedule.deamon.agent_upgrade_result"
AGENTLOG = "cfn.agent.log.agent"
TELEGRAFLOG = "cfn.agent.log.telegraf"
COMPONENTINFO = "cfn.agent.component.detail_info"
TELEGRAFCONF = "cfn.agent.component.telegraf_conf" // 更新telegraf配置文件
AGENTDOWNLOAD = "cfn.agent.agent.download"
UPGRADEPLAN = "cfn.agent.agent.upgrade_plan"
UPGRADEIMMEDIATELY = "cfn.agent.agent.upgrade_immediately"
AGENTDOWNLOADLOCAL = "cfn.agent.agent.download_local"
)

View File

@ -0,0 +1,62 @@
package definition
import (
"encoding/json"
"net/http"
)
func UnmarshalMsgModel(data []byte) (Response, error) {
var r Response
err := json.Unmarshal(data, &r)
return r, err
}
func (r *Response) Marshal() ([]byte, error) {
return json.Marshal(r)
}
type Response struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data []byte `json:"data"`
}
func Resp() *Response {
// 初始化response
return &Response{
Code: 0,
Msg: "",
Data: nil,
}
}
// FailCode 自定义错误码返回
func (r *Response) Fail(msg ...string) *Response {
r.Code = http.StatusInternalServerError
if msg != nil {
r.Msg = msg[0]
}
return r
}
// FailCode 自定义错误码返回
func (r *Response) FailWithData(data []byte, msg ...string) *Response {
r.Code = http.StatusInternalServerError
if msg != nil {
r.Msg = msg[0]
}
r.Data = data
return r
}
// Success 正确返回
func (r *Response) Success(data []byte, msg ...string) *Response {
r.Code = http.StatusOK
if msg != nil {
r.Msg = msg[0]
}
r.Data = data
return r
}

View File

@ -0,0 +1,16 @@
package definition
import (
"fmt"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config/agent"
)
var (
ToAgentUnicastSubject = fmt.Sprintf("cfn_to_agent_unicast_%s", agent.Agent.RID)
ToAgentBroadcastSubject = "cfn_to_agent_broadcast"
ToAgentBroadcastPublicEnterpriseSubject = fmt.Sprintf("cfn_to_agent_broadcast_public_%s", agent.Agent.Enterprise)
ToScheduleSubject = "cfn_to_schedule"
ToAgentBroadcastPrivateEnterpriseSubject = fmt.Sprintf("cfn_to_agent_broadcast_private_%s", agent.Agent.Enterprise)
ToScheduleQueueSubject = "cfn_to_schedule_queue"
)

View File

@ -0,0 +1,482 @@
package handle
import (
"encoding/json"
"fmt"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config/agent"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config/bin_path"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/model/nats_msg_model"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/nats_service/definition"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/service/component"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/service/heartbeat_service"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/service/log_service"
minioClient "git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/file-download-client"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/go-sysinfo/providers/shared"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/log"
natsClient "git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/nats-client"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/utils/compression"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/utils/randomutils"
"github.com/nats-io/nats.go"
"gopkg.in/yaml.v3"
"io/fs"
"os"
"path/filepath"
"strconv"
"strings"
"time"
)
var (
UpgradePlan = &nats_msg_model.UpgradePlan{}
)
func HandleMsg(msg *nats.Msg, model nats_msg_model.MsgModel) {
var err error
switch model.Func {
case definition.AGENTLOG:
lineNum := string(model.Body)
lineUnit, err2 := strconv.ParseUint(lineNum, 10, 64)
if err2 != nil {
lineUnit = 100
}
info, err := log_service.GetAgentLog(lineUnit)
if err != nil {
log.Errorf("获取Agent日志报错 %s", err)
ret, _ := definition.Resp().Fail(err.Error()).Marshal()
msg.Respond(ret)
} else {
marshal, _ := json.Marshal(info)
ret, _ := definition.Resp().Success(marshal, "OK!").Marshal()
msg.Respond(ret)
}
break
case definition.TELEGRAFLOG:
lineNum := string(model.Body)
lineUnit, err2 := strconv.ParseUint(lineNum, 10, 64)
if err2 != nil {
lineUnit = 100
}
info, err := log_service.GetAgentUpgradeLog(lineUnit)
if err != nil {
log.Errorf("获取Telegraf日志报错 %s", err)
ret, _ := definition.Resp().Fail(err.Error()).Marshal()
msg.Respond(ret)
} else {
marshal, _ := json.Marshal(info)
ret, _ := definition.Resp().Success(marshal, "OK!").Marshal()
msg.Respond(ret)
}
break
case definition.COMPONENTINFO:
info, err := component.GetComInfo()
if err != nil {
log.Errorf("获取组件详情报错: %s", err)
ret, _ := definition.Resp().Fail(err.Error()).Marshal()
msg.Respond(ret)
} else {
marshal, _ := json.Marshal(info)
ret, _ := definition.Resp().Success(marshal, "OK!").Marshal()
msg.Respond(ret)
}
break
case definition.TELEGRAFCONF: // 更新telegraf配置文件
component.UpdateTelegrafConfig(model.Body)
if err != nil {
log.Errorf("更新Telegraf配置报错 %s", err)
ret, _ := definition.Resp().Fail(err.Error()).Marshal()
msg.Respond(ret)
} else {
ret, _ := definition.Resp().Success([]byte("完成配置文件更新!"), "OK!").Marshal()
msg.Respond(ret)
}
break
case definition.UPGRADEIMMEDIATELY: // 单个升级(包含升级包地址、升级配置),并解压至指定目录,对于失败的情况给与结果反馈(仅报告失败结果,成功与否由升级程序判断)
upgradeCMD, err := nats_msg_model.UnmarshalUpgradeCMD(model.Body) // 解析命令
if err != nil {
log.Errorf("消息body格式有误 %s", err)
result := nats_msg_model.NewUpgradeResult(upgradeCMD, "消息body格式有误", "0")
marshal, err := json.Marshal(result)
ret, _ := definition.Resp().FailWithData(marshal, err.Error()).Marshal()
msg.Respond(ret)
return
}
if heartbeat_service.AgentState.AgentVersion == upgradeCMD.Version {
log.Info(definition.UPGRADEIMMEDIATELY + "当前运行版本无需升级!")
result := nats_msg_model.NewUpgradeResult(upgradeCMD, "当前运行版本无需升级!", "0")
marshal, _ := json.Marshal(result)
ret, _ := definition.Resp().FailWithData(marshal, "当前运行版本无需升级!").Marshal()
msg.Respond(ret)
return
}
if !(heartbeat_service.AgentState.OSType == upgradeCMD.OsType && heartbeat_service.AgentState.Architecture == upgradeCMD.ArchType) {
log.Info(definition.UPGRADEIMMEDIATELY + "操作系统或服务器架构与本机不符!")
result := nats_msg_model.NewUpgradeResult(upgradeCMD, "操作系统或服务器架构与本机不符!", "0")
marshal, _ := json.Marshal(result)
ret, _ := definition.Resp().FailWithData(marshal, definition.UPGRADEIMMEDIATELY+"操作系统或服务器架构与本机不符!").Marshal()
msg.Respond(ret)
return
}
// 下载升级包至本地 upgrade 目录
localUpgradeCompressedFile := filepath.Join(definition.CompressedAgentPath, upgradeCMD.Filename)
err = minioClient.DownloadToLocal(upgradeCMD.DownUrl, upgradeCMD.Filename, localUpgradeCompressedFile, 3)
if err != nil {
log.Errorf("下载安装包至本地失败: %s", err)
result := nats_msg_model.NewUpgradeResult(upgradeCMD, "下载安装包至本地失败!", "0")
marshal, _ := json.Marshal(result)
ret, _ := definition.Resp().FailWithData(marshal, fmt.Sprintf(definition.UPGRADEIMMEDIATELY+"下载安装包至本地失败: %s", err)).Marshal()
msg.Respond(ret)
return
}
// response请求端
log.Infof(definition.UPGRADEIMMEDIATELY+"下载成功,%s,%s", upgradeCMD.Filename, upgradeCMD.Version)
ret, _ := definition.Resp().Success([]byte(definition.UPGRADEIMMEDIATELY + "下载成功!")).Marshal()
msg.Respond(ret)
// 将安装包文件解压到以版本命名的目录
unCompression(upgradeCMD.Filename, upgradeCMD.CompressionType, upgradeCMD.Version)
// 更新升级计划信息
updateUpgradeVersionInfo(upgradeCMD, true)
break
case definition.AGENTDOWNLOAD: // 小助手升级包下载命令接收接口,并解压至指定目录 【下载所有版本、所有架构的升级包,仅解压符合自己版本、架构的升级包,已供后续升级】。对于失败的情况给与结果反馈
if agent.Agent.Role == "Cache" {
// 解析命令
upgradeCMD, err := nats_msg_model.UnmarshalUpgradeCMD(model.Body)
if err != nil {
log.Errorf(definition.AGENTDOWNLOAD+"消息body格式有误 %s", err)
reportUpgradeRrrors(upgradeCMD, "消息body格式有误!")
return
}
// 下载升级包至本地 upgrade 目录
localUpgradeCompressedFile := filepath.Join(definition.CompressedAgentPath, upgradeCMD.Filename)
err = minioClient.DownloadToLocal(upgradeCMD.DownUrl, upgradeCMD.Filename, localUpgradeCompressedFile, 3)
if err != nil {
log.Errorf(definition.AGENTDOWNLOAD+"下载安装包至本地失败: %s", err)
reportUpgradeRrrors(upgradeCMD,
fmt.Sprintf("下载安装包至本地失败!升级包:%s, 下载缓存机:%s 企业:%s", upgradeCMD.Filename, agent.Agent.RID, agent.Agent.Enterprise),
)
return
}
log.Infof(definition.AGENTDOWNLOAD+"下载成功,%s,%s", upgradeCMD.Filename, upgradeCMD.Version)
// 通知企业内其他一体机来下载
// todo 内网IP
ip, _, _ := shared.NamedNetwork(agent.Agent.NetInterface)
LocalUpgradeCMD := nats_msg_model.LocalUpgradeCMD{
AgentId: upgradeCMD.AgentId,
CompressionType: upgradeCMD.CompressionType,
Filename: upgradeCMD.Filename,
Version: upgradeCMD.Version,
IP: ip,
Port: config.Config.Server.Port,
OsType: upgradeCMD.OsType,
ArchType: upgradeCMD.ArchType,
// 备用
DownUrl: upgradeCMD.DownUrl,
}
bytes, _ := LocalUpgradeCMD.Marshal()
msg := nats_msg_model.MsgModel{
Func: definition.AGENTDOWNLOADLOCAL,
Body: bytes,
Version: "v1",
Rid: agent.Agent.RID,
}
marshal, _ := msg.Marshal()
err = natsClient.Publish(definition.ToAgentBroadcastPrivateEnterpriseSubject, marshal)
if err != nil {
log.Errorf(definition.AGENTDOWNLOAD+"安装包本地广播失败: %s", err)
reportUpgradeRrrors(upgradeCMD,
fmt.Sprintf("安装包本地广播失败:%s下载缓存机%s频道%s", upgradeCMD.Filename, agent.Agent.RID, agent.Agent.Enterprise),
)
return
}
// 将安装包文件解压到以版本命名的目录,仅解压符合自己版本、架构的升级包,已供后续升级
// 如果缓存机下载升级包失败,则通过手工升级
if heartbeat_service.AgentState.AgentVersion == upgradeCMD.Version {
log.Infof(definition.AGENTDOWNLOAD+"版本与本机运行版本一至: %s", upgradeCMD.Version)
return
}
if !checkOsTypeAndArchSame(upgradeCMD) {
return
}
unCompression(upgradeCMD.Filename, upgradeCMD.CompressionType, upgradeCMD.Version)
// 更新升级计划信息
updateUpgradeVersionInfo(upgradeCMD, false)
}
break
case definition.UPGRADEPLAN: // 升级计划下发更新upgradelock文件
plan, err := nats_msg_model.UnmarshalUpgradePlan(model.Body)
if err != nil {
log.Errorf(definition.UPGRADEPLAN+"消息body格式有误 %s", err)
reportUpgradePlanRrrors(plan, "消息body格式有误!")
return
}
if plan.DeviceType != "0" && agent.Agent.Type != plan.DeviceType {
log.Info(definition.UPGRADEPLAN + "设备不匹配!")
//reportUpgradePlanRrrors(plan, fmt.Sprintf("设备不匹配:%s", agent.Agent.RID), "0")
return
}
updateUpgradeTimePlan(plan)
break
case definition.AGENTDOWNLOADLOCAL: // 从企业内缓存机下载,并解压至指定目录,对于失败的情况给与结果反馈
if agent.Agent.Role != "Cache" {
// 先收集缓存机IP列表,
localUpgradeCMD, err := nats_msg_model.UnmarshalLocalUpgradeCMD(model.Body)
if err != nil {
log.Errorf(definition.AGENTDOWNLOADLOCAL+"消息body格式有误 %s", err)
return
}
if agent.Agent.Type != UpgradePlan.DeviceType {
log.Info(definition.AGENTDOWNLOADLOCAL + "设备不匹配!")
return
}
if heartbeat_service.AgentState.AgentVersion == localUpgradeCMD.Version {
log.Info(definition.AGENTDOWNLOADLOCAL + "当前运行版本为最新版本!")
return
}
if !checkOsTypeAndArchSameLocal(localUpgradeCMD) {
return
}
// 新的版本到来了清空CacheIPs列表开启一个新的doLocalDownload
// todo: 支持处理连续两次紧急升级情况处理, 需要支持取消上一次未执行完的doLocalDownload方法
if len(CacheIPs) > 0 {
if CacheIPs[0].Version != localUpgradeCMD.Version {
CacheIPs = []nats_msg_model.LocalUpgradeCMD{}
}
}
if len(CacheIPs) == 0 {
go doLocalDownloadAndUnComporess(localUpgradeCMD)
}
CacheIPs = append(CacheIPs, localUpgradeCMD)
}
break
}
}
func checkOsTypeAndArchSameLocal(upgradeCMD nats_msg_model.LocalUpgradeCMD) bool {
localArch := strings.ToLower(heartbeat_service.AgentState.Architecture)
cmdArch := strings.ToLower(upgradeCMD.ArchType)
if strings.Index(localArch, cmdArch) >= 0 || strings.Index(cmdArch, localArch) >= 0 {
} else {
log.Infof(definition.AGENTDOWNLOAD+"Architecture(%s)与本机(%s)不一致", upgradeCMD.ArchType, heartbeat_service.AgentState.Architecture)
return false
}
localOS := strings.ToLower(heartbeat_service.AgentState.OSType)
cmdOS := strings.ToLower(upgradeCMD.OsType)
if strings.Index(localOS, cmdOS) >= 0 || strings.Index(cmdOS, localOS) >= 0 {
} else {
log.Infof(definition.AGENTDOWNLOAD+"OSType(%s)与本机(%s)不一致", upgradeCMD.OsType, heartbeat_service.AgentState.OSType)
return false
}
return true
}
func checkOsTypeAndArchSame(upgradeCMD nats_msg_model.UpgradeCMD) bool {
localArch := strings.ToLower(heartbeat_service.AgentState.Architecture)
cmdArch := strings.ToLower(upgradeCMD.ArchType)
if strings.Index(localArch, cmdArch) >= 0 || strings.Index(cmdArch, localArch) >= 0 {
} else {
log.Infof(definition.AGENTDOWNLOAD+"Architecture(%s)与本机(%s)不一致", upgradeCMD.ArchType, heartbeat_service.AgentState.Architecture)
return false
}
localOS := strings.ToLower(heartbeat_service.AgentState.OSType)
cmdOS := strings.ToLower(upgradeCMD.OsType)
if strings.Index(localOS, cmdOS) >= 0 || strings.Index(cmdOS, localOS) >= 0 {
} else {
log.Infof(definition.AGENTDOWNLOAD+"OSType(%s)与本机(%s)不一致", upgradeCMD.OsType, heartbeat_service.AgentState.OSType)
return false
}
return true
}
func reportUpgradeRrrors(upgradeCMD nats_msg_model.UpgradeCMD, upgradeResult string) {
result := nats_msg_model.NewUpgradeResult(upgradeCMD, upgradeResult, "0")
marshal, _ := json.Marshal(result)
natsClient.Publish(definition.ToScheduleSubject, marshal)
}
func reportLocalUpgradeRrrors(upgradeCMD nats_msg_model.LocalUpgradeCMD, upgradeResult string) {
result := nats_msg_model.NewLocalUpgradeResult(upgradeCMD, upgradeResult, "0")
marshal, _ := json.Marshal(result)
natsClient.Publish(definition.ToScheduleSubject, marshal)
}
func reportUpgradePlanRrrors(upgradePlan nats_msg_model.UpgradePlan, upgradeResult string) {
result := nats_msg_model.NewUpgradePlanResult(upgradePlan, upgradeResult, "0")
marshal, _ := json.Marshal(result)
natsClient.Publish(definition.ToScheduleSubject, marshal)
}
func readUpgradePlan() error {
if UpgradePlan.UpgradeRule == "" || UpgradePlan.Version == "" {
return nil
}
upgradeByte, err := os.ReadFile(bin_path.UPGRADEPLAN)
if err != nil {
log.Error(definition.UPGRADEIMMEDIATELY + "读取配置文件失败:" + err.Error())
return nil
}
yaml.Unmarshal(upgradeByte, UpgradePlan)
return err
}
func updateUpgradeTimePlan(plan nats_msg_model.UpgradePlan) {
log.Info(definition.UPGRADEPLAN + "开始升级计划文本")
err := readUpgradePlan()
if err != nil {
reportUpgradePlanRrrors(plan, fmt.Sprintf("读取配置文件失败:%s", agent.Agent.RID))
return
}
UpgradePlan.UpgradeRule = plan.UpgradeRule
UpgradePlan.UpgradeTime = plan.UpgradeTime
UpgradePlan.DeviceType = plan.DeviceType
UpgradePlan.Status = plan.Status
UpgradePlan.RID = agent.Agent.RID
out, _ := yaml.Marshal(UpgradePlan)
err = os.WriteFile(bin_path.UPGRADEPLAN, out, fs.ModePerm)
if err != nil {
log.Error(definition.UPGRADEPLAN + "写升级计划文本失败:" + err.Error())
reportUpgradePlanRrrors(plan, fmt.Sprintf("写升级计划文本失败:%s", agent.Agent.RID))
}
log.Info(definition.UPGRADEPLAN + "完成升级计划文本")
}
// updateUpgradeInfo 更新版本
func updateUpgradeVersionInfo(upgradeCMD nats_msg_model.UpgradeCMD, immediately bool) {
log.Info(definition.UPGRADEPLAN + "开始升级计划文本")
err := readUpgradePlan()
if err != nil {
reportUpgradeRrrors(upgradeCMD, fmt.Sprintf("读取配置文件失败:%s", agent.Agent.RID))
return
}
UpgradePlan.CurrentVerson = heartbeat_service.AgentState.AgentVersion
UpgradePlan.Version = upgradeCMD.Version
UpgradePlan.AgentId = upgradeCMD.AgentId
UpgradePlan.Option = "upgrade"
if immediately {
UpgradePlan.UpgradeRule = "0" // 0:立即升级 1按计划升级
}
UpgradePlan.RID = agent.Agent.RID
out, _ := yaml.Marshal(UpgradePlan)
err = os.WriteFile(bin_path.UPGRADEPLAN, out, fs.ModePerm)
if err != nil {
log.Info(definition.UPGRADEPLAN + "写升级计划文本失败:" + err.Error())
reportUpgradeRrrors(upgradeCMD, fmt.Sprintf("写升级计划文本失败:%s", agent.Agent.RID))
}
log.Info(definition.UPGRADEPLAN + "完成升级计划文本")
}
func doLocalDownloadAndUnComporess(localUpgradeCMD nats_msg_model.LocalUpgradeCMD) {
// 5分钟后开始下载
randomNumber := 60*5 + randomutils.GetRandomNumber(-100, 200)
ticker := time.NewTicker(time.Duration(randomNumber) * time.Second)
log.Infof(definition.UPGRADEPLAN+"%d秒后开始下载", randomNumber)
select {
case <-ticker.C:
log.Infof(definition.UPGRADEPLAN + "开始下载......")
// 从缓存机中随机选一个随机等1~10分钟下载
// 下载安装包至 localUpgradeCompressedFile
localUpgradeCompressedFile := filepath.Join(definition.CompressedAgentPath, localUpgradeCMD.Filename)
url := fmt.Sprintf("http://%s:%d?filename=%s", localUpgradeCMD.IP, localUpgradeCMD.Port, localUpgradeCMD.Filename)
err := minioClient.DownloadToLocal(url, localUpgradeCMD.Filename, localUpgradeCompressedFile, 3)
if err != nil {
log.Errorf(definition.AGENTDOWNLOADLOCAL+"下载安装包至本地失败: %s", err)
log.Errorf("使用备用下载地址下载安装包至本地......")
// 直接去minio下载
err = minioClient.DownloadToLocal(localUpgradeCMD.DownUrl, localUpgradeCMD.Filename, localUpgradeCompressedFile, 1)
if err != nil {
log.Errorf("使用备用下载地址下载安装包至本地失败: %s", err)
reportLocalUpgradeRrrors(localUpgradeCMD,
fmt.Sprintf("下载安装包至本地失败:%s企业频道%s", localUpgradeCMD.Filename, definition.AGENTDOWNLOADLOCAL))
return
}
}
log.Infof(definition.UPGRADEPLAN + "下载完成")
// 将安装包文件解压到以版本命名的目录
unCompression(localUpgradeCMD.Filename, localUpgradeCMD.CompressionType, localUpgradeCMD.Version)
heartbeat_service.AgentState.AgentVersion = localUpgradeCMD.Version
// 清空
CacheIPs = make([]nats_msg_model.LocalUpgradeCMD, 5)
}
}
// unCompression 将安装包文件解压到以版本命名的目录
func unCompression(filename, compressionType, version string) {
log.Infof("开始解压%s版本小助手至本地......", version)
versionedAgentPath := filepath.Join(definition.RunDirectory, "../upgrade", version)
// 如果 path 路径不存在,会有 err然后通过 IsNotExist 判定文件路径是否存在,如果 true 则不存在,注意用 os.ModePerm 这样文件是可以写入的
if _, err := os.Stat(versionedAgentPath); os.IsNotExist(err) {
// mkdir 创建目录mkdirAll 可创建多层级目录
os.MkdirAll(versionedAgentPath, os.ModePerm)
}
if compressionType == compression.ZIP {
compression.NewZipHandler().UnZip(filepath.Join(definition.CompressedAgentPath, filename), versionedAgentPath)
} else {
compression.NewTGZHandler().UNTarGZ(filepath.Join(definition.CompressedAgentPath, filename), versionedAgentPath)
}
log.Infof("已完成解压小助手%s至%s", filepath.Join(definition.CompressedAgentPath, filename), versionedAgentPath)
}

View File

@ -0,0 +1,5 @@
package handle
import "git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/model/nats_msg_model"
var CacheIPs = make([]nats_msg_model.LocalUpgradeCMD, 50)

View File

@ -0,0 +1,23 @@
package nats_service
import (
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/nats_service/cfn_to_agent_broadcast"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/nats_service/cfn_to_agent_broadcast_private_enterprise"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/nats_service/cfn_to_agent_broadcast_public_enterprice"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/nats_service/cfn_to_agent_unicast"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/nats_service/cfn_to_schdule/asset_info"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/nats_service/cfn_to_schdule/heartbeat"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/log"
)
func init() {
log.Infof("启动nats订阅服务")
go cfn_to_agent_unicast.Start()
go cfn_to_agent_broadcast.Start()
go cfn_to_agent_broadcast_private_enterprise.Start()
go cfn_to_agent_broadcast_public_enterprice.Start()
asset_info.Strat()
heartbeat.Strat()
}

Binary file not shown.

View File

@ -0,0 +1,8 @@
package contract
type Configuration interface {
Secret() []byte
JWTCert() []byte
JWTTokenLife() int
JWTIssuer() string
}

View File

@ -0,0 +1,6 @@
package contract
type LoginInfo interface {
GetUserID() int
GetUserName() string
}

View File

@ -0,0 +1,6 @@
package contract
type User interface {
GetUserID() int
GetUserName() string
}

View File

@ -0,0 +1,14 @@
package authen
import (
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/pkg/authen/contract"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/pkg/authen/utility"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/pkg/authen/utility/crypto"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/pkg/authen/utility/jwt"
)
var (
Configuration contract.Configuration = utility.NewBaseConfig()
LoginInfoCryptor = crypto.NewAEADCryptor(Configuration)
JWTAuthorizer = jwt.NewJWTAuthorizer(Configuration, LoginInfoCryptor)
)

View File

@ -0,0 +1,189 @@
package utility
import (
"encoding/pem"
"github.com/golang/glog"
"io/ioutil"
"os"
"strconv"
"strings"
)
func NewBaseConfig() *cfg {
return &cfg{
secret: secret(),
jwtCert: jwtCert(),
jwtTokenLife: jwtTokenLife(),
jwtIssuer: jwtIssuer(),
}
}
type cfg struct {
secret Lazy
jwtCert Lazy
jwtTokenLife Lazy
jwtIssuer Lazy
}
func (s cfg) Secret() (secret []byte) {
Must(s.secret.Value(&secret))
return
}
func (s cfg) JWTCert() (jwtCert []byte) {
Must(s.jwtCert.Value(&jwtCert))
return
}
func (s cfg) JWTTokenLife() (tokenLife int) {
Must(s.jwtTokenLife.Value(&tokenLife))
return
}
func (s cfg) JWTIssuer() (issuer string) {
Must(s.jwtIssuer.Value(&issuer))
return
}
func (s cfg) Data() interface{} {
return &struct {
Secret string `json:"secret"`
JWTCert string `json:"jwtCert"`
JWTTokenLife int `json:"jwtTokenLife"`
JWTIssuer string `json:"jwtIssuer"`
}{
Secret: "********",
JWTCert: "********",
JWTTokenLife: s.JWTTokenLife(),
JWTIssuer: s.JWTIssuer(),
}
}
func GetEnv(key, defaultValue string) (value string) {
if value = os.Getenv(key); value == "" {
value = defaultValue
}
return
}
func secret() Lazy {
return NewLazy(func() (value interface{}, err error) {
if s := GetEnv("AEAD_SECRET", "internal"); s == "" || s == "internal" {
value = []byte("dazyunsecretkeysforuserstenx20141019generatedKey")
return
} else {
value = []byte(s)
}
return
})
}
func jwtCert() Lazy {
return NewLazy(func() (value interface{}, err error) {
if c := GetEnv("JWT_CERT", "internal"); c == "" || c == "internal" {
value = loadSecret()
return
} else if _, err = os.Stat(c); err == nil {
var content []byte
if content, err = ioutil.ReadFile(c); err != nil {
return
}
block, _ := pem.Decode(content)
value = block.Bytes
return
}
return
})
}
func jwtTokenLife() Lazy {
return NewLazy(func() (value interface{}, err error) {
hourStr := GetEnv("BEARER_TOKEN_LIFE", "2")
var hour int
if hour, err = strconv.Atoi(hourStr); err != nil {
glog.Fatalf("parse jwt token life failed, should be specified by number in hour, %s", err)
}
value = hour
return
})
}
func jwtIssuer() Lazy {
return NewLazy(func() (value interface{}, err error) {
value = GetEnv("TOKEN_ISSUER", "api-server")
return
})
}
func corsAllowHeaders() Lazy {
return NewLazy(func() (value interface{}, err error) {
headers := GetEnv(
"ALLOW_HEADERS",
"Content-Type,username,authorization,teamspace,project,onbehalfuser")
value = strings.Split(headers, ",")
return
})
}
func corsAllowMethods() Lazy {
return NewLazy(func() (value interface{}, err error) {
methods := GetEnv("ALLOW_METHODS", "GET,POST,PUT,DELETE,PATCH")
value = strings.Split(methods, ",")
return
})
}
func loadSecret() []byte {
block, _ := pem.Decode([]byte(`-----BEGIN RSA PRIVATE KEY-----
MIIJKQIBAAKCAgEA2XUrxPC2ZzfLXiGz3J+BJmfpzNWyRNhUEdljCb9QfMz/54t1
Eri+R3XEvPE+h7n7izBYohv/qXstwM55SBrLqhHVx8qD9SB5FfvkFjU1Q8K+d/1C
KPQpGZnckCtr9c+LjXVB6h1yXP5lBcmbR2SNBAhN+zRdOAoxyw2CgycCo0kyAotT
a9EiKYVLoP4TyDJJIebRp2rRVENBl647jC2Lp13YEXeZhxe6gHw2yEJcg0e8qn3A
hw/842CNbhCVO5kvEhFnCrfJ7w/K7FpS4sQQzI4BocwrvDJxbwBH7RS9Q4+bax5k
RQqB5C6bGWS59ePmqSJ/HjPBPaWcXT/FaFCqZX6umCiAkVWi2F6PK/Un3mkbCa3u
AnqjPO0urgjel3W7kGbHZc1qnSPypUPhmuoLcLCZvzfpY6sl6rUyn8Pbbx3AaEbn
Taxn2wvWVYAik9eeSO3mXOqdZOyFxL1oQe+dv5BjfC/KaeTA5LDPQZ+GpqUq/1ya
lkeEUU8UsrOuSnmekxYQkHEOJ+LAK/aiCsVkbe05Ues4lAFB8g8FZ9Fo/yoCSAzs
AMC4MPFqtNE+GeZPNAsGaNh3GUDWET7IRmu/scZI5L/eBkAyPwsKohkZOpAzfLEx
5OiewUQ9J5zUBXZuKaZL/5HYyqf6/stItzU7UtP62X8cLi8NnC1Vq+4c9mMCAwEA
AQKCAgEAkgCrrIT50v+RGdiDDKRDcGfggFkSYkrk1z8f0dGT1tdFEk9+AV3s08ns
l/dZxoNGssN5Hw6xbzd3FrcKkzD6gWuMH6KHSrPM2MfQ8mAzLRW6EJIIM7sLRVca
0el1iQsaZZXO9cNjn7BmX6ZnDV4jmAuDYCBeXlvp5q1hbXFpwfxJCZBGKGO4Diyj
BKrS2V154Ls7FK8RcQPfLFodPRbvZyYJBmFIwX1bCR1dIsP7nWEy+T2JYKWJY5jW
HIohyGwnQHhSuM2BVXNDCcHzWLHPnafSzLFqw+cSZjbIFBQSpyPqc9dp9zkA0RXB
qSEKAmBL5E93De4t1pg1Dh7dChbu8A0BjeT9YOX3eLdSnu5A9tJXu8lubyzRBjNE
360tFwC8c4IAs0KuEq3W1tzv4AEPqyx/k0V/o1d8do9WL7NqtiEk/EuMr5pkPOmb
yUQOT9qY/B1bMk8jHllRE6E68BdhFa6pbgVrpsFehXslukN/QsgCK4yEsS22aE0R
K4TLmRaYT8JU9hlbY86dRhqNKM+m5aH4Aa1owUj6nZQq3zYgY+0SoCdlJdGSD0gG
LN5E4i2tlPvxBo/z7ObV9Cc+zI1OwcH5WvcBYINYDPLN9Fr9iZzLC0zI1H7eL0ut
0eI+4BfytTk8Ff8EA2mLrfYy1fyNZqBol7lyzIg6iTBDaLzUCTECggEBAPjFmarO
dsj2KDWr1VOobwaoY54Q/AavRARnGi24QcprHLQAJsKIUbSmMoIV/qRBUhyw88VB
LCRW92kK4GJJIOwkr8l/zNIJRGRg/CK4E0S3vu4GA1x300VAole/nk/jUKQGCUL9
27XJrrOKNz1Equn98OSeRB9j7AJ0aPy5BafI2PWoUoMPfpWfULeK8eBAxiYMewwk
VpBzJr/FoZD4QgFKXhk6PoxdqdEaRQxySRWNCwgjVsSxYKVxO47bd3lJjGgXF2sd
hfGnurBZt0jL7CmmdcI4t8+05svZrw02L+GPmp6dnpmVudlKdTbJPjRdW/SVAFuc
vwtXrbD3glY5pccCggEBAN/GpsnePTRwGKsM43RLDlKM0SGMbpAoORFNC/X6PtQ9
nLNM+y+ZUYVT+/TZXsKY7vOKOFFxcS/vt3Sez6CH1fkiEj7eHMFadjnYQp4mDJUh
NuT3eOCCLnqImuVhyuGjb0kVo+Uw7NLKcWFshj16ybCO/3dSLAAf/QWjk9XMVarP
0GHXysqOE+6aqvVwjqgZcXrteP8z/Xrij2pVsDUn6+o7E9c/snUAxpNxO5pKuaI0
cYpLC6YILhbwLgICo22wY4W3Cd7GNJ+F8UK9QZChnbJmrMG7gqtD2wqNKiiKue4T
n3jGG9W6DRwYsVExDsWTC8WPJ5ZULBZ8dDY5OXmPeoUCggEAXHIB0sl6tt9Sve8n
DTmQWKcGrdyd61YCLqipv8ezGyeGuRU9UhkaU8lXB6Roxl1HyEWxsOGxJ6fxtOVH
0P5f76EKehS15m9vLOYljDlfX6/wkb9GTHxy1E9ahMU+bW2JsApWMsDnfrx94VZB
hNEZum6VsD9oDUoykA72XMPc6CbpCREN6Io/fhaABlTp4W3wtH760t5GFNPV2Hn2
ukqnLJeYNEPCrqK30m6yrhdiNVH+gX2wZtOLmK9ldIb19Opx9NRv7WxBNDYiWBpe
0/yDvE6RgCVXmSYehi5UsNIsJOQaj0r/fw92ytqyiDNsnET9QPyF74VmMS7Z6uNv
Wd9+TQKCAQBVFD0ToShaCIiIeCT+cQ7n+dwFSlQ7AN/5oPZ8NgGvRiGO1iTmSv+A
lpbD1+U8TVMESzfwVxY2qIhykXLVUO/cgcS4HFCIfvFWOs/ROxwrku5BDYnqqfQr
6EYkEhNFyJKmEdE3cWuJFSkYZl9/fnCybRvZ7OcHwSG9BB1P+xlTESHkIVxbuLsB
S9LV8E58wPexShpnxQeJshvezOdqvlvmuUFo5DHgZEQbiMClf+WmMxQ8BR5PqOqF
FBoZ75DdQmQEUbwx89/MCuvYeQY1jAzd6EWkfrtGjEz6bQNrWJsqVlGaZI/uqYcU
eJrqCKHaIncmTLA7apM8lWLFvuoIOrHVAoIBAQDzs6q8kcDRwJhvGCbCf2wGpRTZ
Jza0O/toOSgI7fqrOopub/XZ/mNCsa/fFskbkJJwBj34Mt3wb59P9zFVIRyX+amh
YREfbwk/PF8fEW6OH0FFtP6Y5D0K8MV/0qls7lVTPXeKT7UXA1nQHbBG0Bb1G2Kq
hhovPyYZzh0xOmiXC0z8pBn1BLMnbC7/PUkDiVBmxJYAilD11xJDx+LLEuCzC8vL
J2FMsw2T/L4egMn2Ae17AuVXOxgTkkfIf1NI4AtoznnFmhtG4+ztFyoOAOUUDE2L
8kjUZ1BV35VkZFSz5NPbdelAp4HzkhdbUvfA9MotTtYtN8mgTPJ2neq8Lx4Z
-----END RSA PRIVATE KEY-----`))
return block.Bytes
}

View File

@ -0,0 +1,83 @@
package crypto
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha512"
"golang.org/x/crypto/pbkdf2"
"io"
)
func NewAEADCryptor(c config) *aead {
return &aead{
secret: c.Secret(),
}
}
type aead struct {
secret []byte
}
func (a aead) Encrypt(content []byte) (encrypted []byte, err error) {
var salt []byte
if salt, err = randBytes(64); err != nil {
return
}
var block cipher.Block
if block, err = aes.NewCipher(a.key(salt)); err != nil {
return
}
var iv []byte
if iv, err = randBytes(12); err != nil {
return
}
if _, err = io.ReadFull(rand.Reader, iv); err != nil {
return
}
var aes256gcm cipher.AEAD
if aes256gcm, err = cipher.NewGCM(block); err != nil {
return
}
withTag := aes256gcm.Seal(nil, iv, content, nil)
encryptedLen := len(withTag) - 16
withoutTag := withTag[:encryptedLen]
tag := withTag[encryptedLen:]
encrypted = bytes.Join([][]byte{salt, iv, tag, withoutTag}, []byte{})
return
}
func (a aead) Decrypt(encrypted []byte) (content []byte, err error) {
if len(encrypted) <= 92 {
err = Undecryptable
return
}
salt := encrypted[:64]
iv := encrypted[64:76]
tag := encrypted[76:92]
withoutTag := encrypted[92:]
withTag := bytes.Join([][]byte{withoutTag, tag}, []byte{})
var block cipher.Block
if block, err = aes.NewCipher(a.key(salt)); err != nil {
return
}
var aes256gcm cipher.AEAD
if aes256gcm, err = cipher.NewGCM(block); err != nil {
return
}
content, err = aes256gcm.Open(nil, iv, withTag, nil)
return
}
func (a aead) key(salt []byte) []byte {
return pbkdf2.Key(a.secret, salt, 2145, 32, sha512.New)
}
func randBytes(length int) (bytes []byte, err error) {
bytes = make([]byte, length)
if _, err = io.ReadFull(rand.Reader, bytes); err != nil {
return
}
return
}

View File

@ -0,0 +1,69 @@
package crypto
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
)
var (
seckey = []byte("Q1A2Z3X!D^R$T&G*B(N)U088") //24Byte
base64Tables = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
iv = []byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
)
func base64Decode(src string) ([]byte, error) {
coder := base64.NewEncoding(base64Tables)
return coder.DecodeString(src)
}
func aesPadding(src []byte, blockSize int) []byte {
padding := blockSize - len(src)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(src, padtext...)
}
func aesUnPadding(src []byte) []byte {
length := len(src)
unpadding := int(src[length-1])
return src[:(length - unpadding)]
}
func Encrypt(src string) (string, error) {
block, err := aes.NewCipher(seckey)
if err != nil {
return "", nil
}
arr := aesPadding([]byte(src), aes.BlockSize)
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(arr, arr)
return string(arr), nil
}
func Decrypt(src string) (string, error) {
block, err := aes.NewCipher(seckey)
if err != nil {
return "", nil
}
arr := []byte(src)
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(arr, arr)
arr = aesUnPadding(arr)
return string(arr), nil
}
func Base64AndDecrypt(src string) (string, error) {
block, err := aes.NewCipher(seckey)
if err != nil {
return "", nil
}
arr, err := base64Decode(src)
if err != nil {
return "", err
}
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(arr, arr)
arr = aesUnPadding(arr)
return string(arr), nil
}

View File

@ -0,0 +1,35 @@
package crypto
import (
"errors"
"hash"
)
var Undecryptable = errors.New("undecryptable input")
type config interface {
Secret() []byte
}
// https://nodejs.org/api/crypto.html#crypto_crypto_createdecipher_algorithm_password_options
// openssl/evp.h - EVP_BytesToKey
func bytesToKey(hashAlgorithm func() hash.Hash, secret, salt []byte, iteration int, keySize, ivSize int) (key, iv []byte) {
h := hashAlgorithm()
var d, result []byte
sum := make([]byte, 0, h.Size())
for len(result) < keySize+ivSize {
h.Reset()
h.Write(d)
h.Write(secret)
h.Write(salt)
sum = h.Sum(sum[:0])
for j := 1; j < iteration; j++ {
h.Reset()
h.Write(sum)
sum = h.Sum(sum[:0])
}
d = append(d[:0], sum...)
result = append(result, d...)
}
return result[:keySize], result[keySize : keySize+ivSize]
}

View File

@ -0,0 +1,87 @@
package crypto
import (
"crypto/cipher"
"crypto/des"
"crypto/md5"
)
func NewDESCryptor(c config) *desEDE3CBC {
k, iv := bytesToKey(md5.New, c.Secret(), []byte{}, 1, 24, 8)
return &desEDE3CBC{
key: k,
iv: iv,
}
}
type desEDE3CBC struct {
key []byte
iv []byte
}
func (d desEDE3CBC) Encrypt(content []byte) (encrypted []byte, err error) {
var block cipher.Block
if block, err = des.NewTripleDESCipher(d.key); err != nil {
return
}
cbc := cipher.NewCBCEncrypter(block, d.iv)
encrypted, err = d.crypt(content, cbc)
return
}
func (d desEDE3CBC) Decrypt(encrypted []byte) (content []byte, err error) {
var block cipher.Block
if block, err = des.NewTripleDESCipher(d.key); err != nil {
return
}
cbc := cipher.NewCBCDecrypter(block, d.iv)
content, err = d.crypt(encrypted, cbc)
return
}
func (d desEDE3CBC) crypt(in []byte, cbc cipher.BlockMode) (out []byte, err error) {
blockSize := cbc.BlockSize()
padded := padding(in, blockSize)
entriesCount := len(padded)
crypted := make([][]byte, entriesCount)
for i := 0; i < entriesCount; i++ {
crypted[i] = make([]byte, blockSize)
cbc.CryptBlocks(crypted[i], padded[i])
}
contentSize := len(in)
out = make([]byte, contentSize)
for i := 0; i < entriesCount; i++ {
for j := 0; j < blockSize; j++ {
index := i*blockSize + j
if index >= contentSize {
break
}
out[index] = crypted[i][j]
}
}
return
}
func padding(content []byte, blockSize int) (padded [][]byte) {
contentLength := len(content)
size := contentLength / blockSize
if contentLength%blockSize != 0 {
size++
}
padded = make([][]byte, size)
for i := 0; i < size; i++ {
padded[i] = make([]byte, blockSize)
entry := padded[i]
for j := 0; j < blockSize; j++ {
index := i*blockSize + j
if index >= contentLength {
for k := j; k < blockSize; k++ {
entry[k] = 0
}
break
}
entry[j] = content[index]
}
}
return
}

View File

@ -0,0 +1,181 @@
package jwt
import (
"encoding/base64"
"errors"
"github.com/dgrijalva/jwt-go"
"strings"
"time"
)
var (
UnexpectedSingingMethod = errors.New("unexpected signing method")
UnknownEntity = errors.New("unknown entity")
)
func NewJWTAuthorizer(c config, cryptor cryptor) *authorizer {
tl := time.Duration(c.JWTTokenLife())
return &authorizer{
tokenLifeInHour: tl,
tokenLifeInSecond: int(time.Hour * tl / time.Second),
issuer: c.JWTIssuer(),
cert: c.JWTCert(),
cryptor: cryptor,
}
}
type config interface {
JWTCert() []byte
JWTTokenLife() int
JWTIssuer() string
}
type loginInfo interface {
GetUserID() int
GetUserName() string
GetUserToken() string
}
type authorizer struct {
tokenLifeInHour time.Duration
tokenLifeInSecond int
issuer string
cert []byte
cryptor cryptor
}
type entity struct {
Encrypted string `json:"encrypted"`
jwt.StandardClaims `json:",inline"`
}
func (a authorizer) Authorize(li loginInfo) (token string, err error) {
i := &info{
Username: li.GetUserName(),
Token: li.GetUserToken(),
UserID: li.GetUserID(),
}
now := time.Now()
var encrypted string
if encrypted, err = encryptLoginInfo(i, a.cryptor); err != nil {
return
}
claims := jwt.NewWithClaims(jwt.SigningMethodHS512, &entity{
Encrypted: encrypted,
StandardClaims: jwt.StandardClaims{
ExpiresAt: now.Add(a.tokenLifeInHour * time.Hour).Unix(),
Issuer: a.issuer,
},
})
var rawToken string
if rawToken, err = claims.SignedString(a.cert); err != nil {
return
}
token = (&dto{
Token: rawToken,
ExpiresIn: a.tokenLifeInSecond,
IssuedAt: now,
UserID: i.UserID,
}).String()
return
}
func (a authorizer) Validate(token string) (l loginInfo, err error) {
var t *jwt.Token
if t, err = jwt.ParseWithClaims(token, &entity{}, a.validateCert); err != nil {
return
}
obj, ok := t.Claims.(*entity)
if !ok {
err = UnknownEntity
return
}
var li *info
if li, err = decryptLoginInfo(obj.Encrypted, a.cryptor); err != nil {
return
}
l = li
return
}
const (
bearerKeyword = "Bearer"
bearerKeywordLength = len(bearerKeyword)
)
func (authorizer) IsBearerToken(rawToken string) (ok bool, token string) {
ok = len(rawToken) > bearerKeywordLength &&
strings.EqualFold(bearerKeyword, rawToken[:bearerKeywordLength])
if ok {
token = strings.TrimSpace(rawToken[bearerKeywordLength:])
}
return
}
func (authorizer) IsTokenExpired(err error) bool {
if jve, ok := err.(*jwt.ValidationError); ok && jve.Inner != nil {
return jve.Errors&jwt.ValidationErrorExpired == jwt.ValidationErrorExpired
}
return false
}
func (a authorizer) validateCert(token *jwt.Token) (obj interface{}, err error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
err = UnexpectedSingingMethod
return
}
return a.cert, nil
}
var (
secret = loadSecret()
)
func loadSecret() []byte {
block, _ := base64.StdEncoding.DecodeString(`IUkVLcM72OGEOJgQX3BXjLP4dsLs084joI2aQWcmB8rLxPyEX2cxLdVllRrx/v/Tzh2iSPsftmcABQ+q5kVYdQ==`)
return block
}
type LoginInfo struct {
Username string `json:"username"`
Encrypted string `json:"encrypted"`
}
type tokenEntity struct {
Encrypted string `json:"encrypted"`
Username string `json:"login_loginname"`
Role int32 `json:"role"`
ApiToken string `json:"api_token"`
LoginAppId string `json:"login_app_id"`
LoginUid string `json:"login_uid"`
LoginAccountId string `json:"login_account_id"`
ClientIp string `json:"client_ip"`
LoginAccountName string `json:"login_account_name"`
UsersAppId string `json:"users_app_id"`
LoginUname string `json:"login_uname"`
jwt.StandardClaims
}
func (authorizer) ValidateToken(rawToken string) (loginInfo *LoginInfo, err error) {
var token *jwt.Token
if token, err = jwt.ParseWithClaims(rawToken, &tokenEntity{}, validateSecret); err != nil {
return nil, err
}
obj, ok := token.Claims.(*tokenEntity)
if !ok {
return nil, UnknownEntity
}
loginInfo = &LoginInfo{
Username: obj.Username,
Encrypted: obj.Encrypted,
}
return
}
func validateSecret(token *jwt.Token) (obj interface{}, err error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
err = UnexpectedSingingMethod
return
}
return secret, nil
}

View File

@ -0,0 +1,71 @@
package jwt
import (
"encoding/base64"
"encoding/json"
"time"
)
type dto struct {
Token string `json:"token"`
ExpiresIn int `json:"expiresIn"`
IssuedAt time.Time `json:"issuedAt"`
UserID int `json:"userID"`
}
func (t dto) String() string {
c, _ := json.Marshal(t)
return string(c)
}
type cryptor interface {
Encrypt(content []byte) (encrypted []byte, err error)
Decrypt(encrypted []byte) (content []byte, err error)
}
type info struct {
Username string `json:"username"`
Token string `json:"token"`
UserID int `json:"userId"`
}
func (i info) GetUserID() int {
return i.UserID
}
func (i info) GetUserName() string {
return i.Username
}
func (i info) GetUserToken() string {
return i.Token
}
func encryptLoginInfo(i *info, cryptor cryptor) (encrypted string, err error) {
var buffer []byte
if buffer, err = json.Marshal(i); err != nil {
return
}
if buffer, err = cryptor.Encrypt(buffer); err != nil {
return
}
encrypted = base64.StdEncoding.EncodeToString(buffer)
return
}
func decryptLoginInfo(encrypted string, cryptor cryptor) (decrypted *info, err error) {
var buffer []byte
buffer, err = base64.StdEncoding.DecodeString(encrypted)
if err != nil {
return
}
if buffer, err = cryptor.Decrypt(buffer); err != nil {
return
}
var t info
if err = json.Unmarshal(buffer, &t); err != nil {
return
}
decrypted = &t
return
}

View File

@ -0,0 +1,55 @@
package utility
import (
"errors"
"reflect"
"sync"
)
type Lazy interface {
Value(value interface{}) (err error)
}
var (
TypeMismatched = errors.New("type mismatched")
)
type lazy struct {
lock *sync.Once
fetch func() (value interface{}, err error)
value interface{}
done bool
}
func (l *lazy) Value(value interface{}) (err error) {
if l.done {
l.setValueTo(value)
return
}
l.lock.Do(func() {
if l.value, err = l.fetch(); err != nil {
l.lock = new(sync.Once)
return
} else {
l.setValueTo(value)
l.done = true
}
})
return
}
func (l lazy) setValueTo(receiver interface{}) (err error) {
rv := reflect.Indirect(reflect.ValueOf(receiver))
vv := reflect.ValueOf(l.value)
if vv.Type().AssignableTo(rv.Type()) && rv.CanSet() {
rv.Set(reflect.ValueOf(l.value))
}
return TypeMismatched
}
func NewLazy(fetch func() (value interface{}, err error)) Lazy {
return &lazy{
lock: new(sync.Once),
fetch: fetch,
}
}

View File

@ -0,0 +1,23 @@
package utility
import "testing"
func TestLazy_Value(t *testing.T) {
i := 0
someLazyValue := NewLazy(func() (value interface{}, err error) {
value = "some lazy value"
i++
return
})
var theValueOfSomeLazyValue string
if err := someLazyValue.Value(&theValueOfSomeLazyValue); err != nil {
t.Fatalf("get value failed, %s", err)
}
t.Logf("value of lazy: %s", theValueOfSomeLazyValue)
if err := someLazyValue.Value(&theValueOfSomeLazyValue); err != nil {
t.Fatalf("get value failed, %s", err)
}
if i > 1 {
t.Fatalf("lazy should only evaluate once, but %d times", i)
}
}

View File

@ -0,0 +1,38 @@
package utility
import "reflect"
func Must(err error) {
if err != nil {
panic(err)
}
}
type receiver interface {
Value(interface{})
}
type holder struct {
value interface{}
}
func (h holder) Value(receiver interface{}) {
reflect.Indirect(reflect.ValueOf(receiver)).Set(reflect.ValueOf(h.value))
}
// So everyone who may use this, must be familiar with golang.
// Then they should take care with the 'receiver'.
// func someMethod(someArg string, otherArg int) (returnValue int, err error)
// for instance a method like above, then MustGet can used like below
// var returnValue int
// MustGet(someMethod("someArg", /* otherArg */ 888)).Value(&returnValue)
// and if someMethod's second return value (the err) was not nil
// the expression panic, other way the 'returnValue' should be the first
// return value of someMethod.
// YOU SHOULD take care of the receiver type yourself, if the 'var returnValue int'
// line goes to 'var returnValue string', then it also panic, since the first
// return value of someMethod is int not string.
func MustGet(anything interface{}, err error) receiver {
Must(err)
return &holder{value: anything}
}

View File

@ -0,0 +1,57 @@
package utility
import (
"errors"
"testing"
)
func chaosMonkeyA(t *testing.T) error {
t.Logf("chaosMonkeyA")
return errors.New("chaosMonkeyA")
}
func chaosMonkeyB(t *testing.T) (string, error) {
t.Logf("chaosMonkeyB")
return "chaosMonkeyB", errors.New("chaosMonkeyB")
}
func iAmWalkingInLine(t *testing.T) (float64, error) {
t.Logf("iAmWalkingInLine")
return 88888888.88888888, nil
}
func TestMust(t *testing.T) {
func() {
defer func() {
if err := recover(); err != nil {
t.Logf("caseA: should panic, %s", err)
} else {
t.Fatalf("caseA: should panic, but didn't")
}
}()
Must(chaosMonkeyA(t))
}()
func() {
defer func() {
if err := recover(); err != nil {
t.Logf("caseB: should panic, %s", err)
} else {
t.Fatalf("caseB: should panic, but didn't")
}
}()
var value string
MustGet(chaosMonkeyB(t)).Value(&value)
}()
func() {
defer func() {
if err := recover(); err != nil {
t.Fatalf("caseC: should not panic, but paniced %s", err)
} else {
t.Logf("caseC: everything went fine")
}
}()
var value float64
MustGet(iAmWalkingInLine(t)).Value(&value)
t.Logf("caseC: value, %f", value)
}()
}

View File

@ -0,0 +1,38 @@
package errors
const (
SUCCESS = 200
FAILURE = 600
NotFound = 404
InvalidParameter = 400
ServerError = 500
TooManyRequests = 429
AuthorizationError = 401
RBACError = 403
)
type ErrorText struct {
Language string
}
func NewErrorText(language string) *ErrorText {
return &ErrorText{
Language: language,
}
}
func (et *ErrorText) Text(code int) (str string) {
var ok bool
switch et.Language {
case "zh_CN":
str, ok = zhCNText[code]
case "en":
str, ok = enUSText[code]
default:
str, ok = zhCNText[code]
}
if !ok {
return "unknown error"
}
return
}

View File

@ -0,0 +1,16 @@
package errors
import (
"testing"
)
func TestText(t *testing.T) {
var errorText = NewErrorText("zh_CN")
if "OK" != errorText.Text(0) {
t.Error("text 返回 msg 不是预期的")
}
if "unknown error" != errorText.Text(1202389) {
t.Error("text 返回 msg 不是预期的")
}
}

View File

@ -0,0 +1,12 @@
package errors
var enUSText = map[int]string{
SUCCESS: "OK",
FAILURE: "FAIL",
NotFound: "resources not found",
ServerError: "Internal server error",
TooManyRequests: "Too many requests",
InvalidParameter: "Parameter error",
AuthorizationError: "Authorization error",
RBACError: "No access",
}

View File

@ -0,0 +1,63 @@
package errors
import (
"errors"
"fmt"
c "git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config"
)
type BusinessError struct {
code int
message string
contextErr []error
}
func (e *BusinessError) Error() string {
return fmt.Sprintf("[Code]:%d [Msg]:%s, [context error] %s", e.code, e.message, e.contextErr)
}
func (e *BusinessError) GetCode() int {
return e.code
}
func (e *BusinessError) GetMessage() string {
return e.message
}
func (e *BusinessError) SetCode(code int) {
e.code = code
}
func (e *BusinessError) SetMessage(message string) {
e.message = message
}
func (e *BusinessError) SetContextErr(err error) {
e.contextErr = append(e.contextErr, err)
}
func (e *BusinessError) GetContextErr() []error {
return e.contextErr
}
// NewBusinessError Create a business error
func NewBusinessError(code int, message ...string) *BusinessError {
var msg string
if message != nil {
msg = message[0]
} else {
msg = NewErrorText(c.Config.Language).Text(code)
}
err := new(BusinessError)
err.SetCode(code)
err.SetMessage(msg)
return err
}
func AsBusinessError(err error) (*BusinessError, error) {
var BusinessError = new(BusinessError)
if errors.As(err, &BusinessError) {
return BusinessError, nil
}
return nil, err
}

View File

@ -0,0 +1,12 @@
package errors
var zhCNText = map[int]string{
SUCCESS: "OK",
FAILURE: "FAIL",
NotFound: "资源不存在",
ServerError: "服务器内部错误",
TooManyRequests: "请求过多",
InvalidParameter: "参数错误",
AuthorizationError: "权限错误",
RBACError: "暂无访问权限",
}

View File

@ -0,0 +1,51 @@
package func_make
import (
"errors"
"reflect"
)
type FuncMap map[string]reflect.Value
func New() FuncMap {
return make(FuncMap, 2)
}
func (f FuncMap) Register(name string, fn any) error {
v := reflect.ValueOf(fn)
if v.Kind() != reflect.Func {
return errors.New(name + " is not a function type.")
}
f[name] = v
return nil
}
func (f FuncMap) Registers(funcMap map[string]any) (err error) {
for k, v := range funcMap {
err = f.Register(k, v)
if err != nil {
break
}
}
return
}
func (f FuncMap) Call(name string, params ...any) (result []reflect.Value, err error) {
if _, ok := f[name]; !ok {
err = errors.New(name + " method does not exist.")
return
}
in := make([]reflect.Value, len(params))
for k, param := range params {
in[k] = reflect.ValueOf(param)
}
defer func() {
if e := recover(); e != nil {
err = errors.New("call " + name + " method fail. " + e.(string))
}
}()
result = f[name].Call(in)
return
}

View File

@ -0,0 +1,45 @@
package func_make
import (
"testing"
)
var (
funcMap = map[string]interface{}{
"test": func(str string) string {
return str
},
}
funcMake = New()
)
func TestRegisters(t *testing.T) {
err := funcMake.Registers(funcMap)
if err != nil {
t.Errorf("绑定失败")
}
}
func TestRegister(t *testing.T) {
err := funcMake.Register("test1", func(str ...string) string {
var res string
for _, v := range str {
res += v
}
return res
})
if err != nil {
t.Errorf("绑定失败")
}
}
func TestCall(t *testing.T) {
TestRegisters(t)
TestRegister(t)
if _, err := funcMake.Call("test", "1"); err != nil {
t.Errorf("请求test方法失败:%s", err)
}
if _, err := funcMake.Call("test1", "2323", "ddd"); err != nil {
t.Errorf("请求test1方法失败:%s", err)
}
}

View File

@ -0,0 +1,47 @@
package request
import (
"bytes"
"errors"
"github.com/gin-gonic/gin"
"io/ioutil"
"net/http"
)
func GetQueryParams(c *gin.Context) map[string]any {
query := c.Request.URL.Query()
var queryMap = make(map[string]any, len(query))
for k := range query {
queryMap[k] = c.Query(k)
}
return queryMap
}
func GetPostFormParams(c *gin.Context) (map[string]any, error) {
if err := c.Request.ParseMultipartForm(32 << 20); err != nil {
if !errors.Is(err, http.ErrNotMultipart) {
return nil, err
}
}
var postMap = make(map[string]any, len(c.Request.PostForm))
for k, v := range c.Request.PostForm {
if len(v) > 1 {
postMap[k] = v
} else if len(v) == 1 {
postMap[k] = v[0]
}
}
return postMap, nil
}
func GetBody(c *gin.Context) []byte {
// 读取body数据
body, err := c.GetRawData()
if err != nil {
return nil
}
//把读过的字节流重新放到body
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
return body
}

View File

@ -0,0 +1,142 @@
package response
import (
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/pkg/errors"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
type result struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data interface{} `json:"data"`
Cost string `json:"cost"`
}
type Response struct {
httpCode int
result *result
}
func Resp() *Response {
// 初始化response
return &Response{
httpCode: http.StatusOK,
result: &result{
Code: 0,
Msg: "",
Data: nil,
Cost: "",
},
}
}
// Fail 错误返回
func (r *Response) Fail(c *gin.Context, code int, msg string, data ...any) {
r.SetCode(code)
r.SetMessage(msg)
if data != nil {
r.WithData(data[0])
}
r.json(c)
}
// FailCode 自定义错误码返回
func (r *Response) FailCode(c *gin.Context, code int, msg ...string) {
r.SetCode(code)
if msg != nil {
r.SetMessage(msg[0])
}
r.json(c)
}
// Success 正确返回
func (r *Response) Success(c *gin.Context) {
r.SetCode(errors.SUCCESS)
r.json(c)
}
// WithDataSuccess 成功后需要返回值
func (r *Response) WithDataSuccess(c *gin.Context, data interface{}) {
r.SetCode(errors.SUCCESS)
r.WithData(data)
r.json(c)
}
// SetCode 设置返回code码
func (r *Response) SetCode(code int) *Response {
r.result.Code = code
return r
}
// SetHttpCode 设置http状态码
func (r *Response) SetHttpCode(code int) *Response {
r.httpCode = code
return r
}
type defaultRes struct {
Result any `json:"result"`
}
// WithData 设置返回data数据
func (r *Response) WithData(data any) *Response {
switch data.(type) {
case string, int, bool:
r.result.Data = &defaultRes{Result: data}
default:
r.result.Data = data
}
return r
}
// SetMessage 设置返回自定义错误消息
func (r *Response) SetMessage(message string) *Response {
r.result.Msg = message
return r
}
var ErrorText = errors.NewErrorText(config.Config.Language)
// json 返回 gin 框架的 HandlerFunc
func (r *Response) json(c *gin.Context) {
if r.result.Msg == "" {
r.result.Msg = ErrorText.Text(r.result.Code)
}
// if r.Data == nil {
// r.Data = struct{}{}
// }
r.result.Cost = time.Since(c.GetTime("requestStartTime")).String()
c.AbortWithStatusJSON(r.httpCode, r.result)
}
// Success 业务成功响应
func Success(c *gin.Context, data ...any) {
if data != nil {
Resp().WithDataSuccess(c, data[0])
return
}
Resp().Success(c)
}
// FailCode 业务失败响应
func FailCode(c *gin.Context, code int, data ...any) {
if data != nil {
Resp().WithData(data[0]).FailCode(c, code)
return
}
Resp().FailCode(c, code)
}
// Fail 业务失败响应
func Fail(c *gin.Context, code int, message string, data ...any) {
if data != nil {
Resp().WithData(data[0]).FailCode(c, code, message)
return
}
Resp().FailCode(c, code, message)
}

View File

@ -0,0 +1,56 @@
package utils
import (
"database/sql/driver"
"fmt"
"strings"
"time"
)
type FormatDate struct {
time.Time
}
const (
timeFormat = "2006-01-02 15:04:05"
)
func (t FormatDate) MarshalJSON() ([]byte, error) {
if &t == nil || t.IsZero() {
return []byte("null"), nil
}
return []byte(fmt.Sprintf("\"%s\"", t.Format(timeFormat))), nil
}
func (t FormatDate) Value() (driver.Value, error) {
var zeroTime time.Time
if t.Time.UnixNano() == zeroTime.UnixNano() {
return nil, nil
}
return t.Time, nil
}
func (t *FormatDate) Scan(v interface{}) error {
if value, ok := v.(time.Time); ok {
*t = FormatDate{value}
return nil
}
return fmt.Errorf("can not convert %v to timestamp", v)
}
func (t *FormatDate) String() string {
if t == nil || t.IsZero() {
return ""
}
return fmt.Sprintf("%s", t.Time.Format(timeFormat))
}
func (t *FormatDate) UnmarshalJSON(data []byte) error {
str := string(data)
if str == "null" {
return nil
}
t1, err := time.ParseInLocation(timeFormat, strings.Trim(str, "\""), time.Local)
*t = FormatDate{t1}
return err
}

View File

@ -0,0 +1,30 @@
package routers
import (
controllerV1 "git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/controller/v1"
"github.com/gin-gonic/gin"
)
func setApiRoute(r *gin.Engine) {
// version 1
v1 := r.Group("/api/v1")
{
//v1.POST("/login", controllerV1.Login)
//v1.GET("/host/info", controllerV1.GetAssertInfo)
v1.POST("/asset", controllerV1.AssetInformationEntry)
v1.POST("/shutdown", controllerV1.Shutdown)
v1.GET("/host/compose", controllerV1.GetComponentInfo)
v1.GET("/log/agent", controllerV1.GetAgentLog)
v1.GET("/log/agent/upgrade", controllerV1.GetAgentUpgradeLog)
v1.GET("/log/telegraf", controllerV1.GetTelegrafLog)
v1.POST("/telegraf/config", controllerV1.UpdateTelegrafConfig)
v1.POST("/telegraf/config/recover", controllerV1.RecoverConfig)
v1.GET("/agent/download", controllerV1.DownloadAgent)
}
}

View File

@ -0,0 +1,75 @@
package routers
import (
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/middleware"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/pkg/errors"
response2 "git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/pkg/response"
"github.com/gin-gonic/gin"
"io/ioutil"
"net/http"
)
func SetRouters() *gin.Engine {
var r *gin.Engine
if config.Config.Debug == false {
// 生产模式
r = ReleaseRouter()
r.Use(
middleware.AuthenticationHandler(),
middleware.RequestCostHandler(),
middleware.CustomLogger(),
middleware.CustomRecovery(),
middleware.CorsHandler(),
middleware.AppContextHandler(),
middleware.AuthorizationHandler(),
)
} else {
// 开发调试模式
r = gin.New()
r.Use(
//gin.Logger(),
middleware.AuthenticationHandler(),
middleware.RequestCostHandler(),
middleware.CustomLogger(),
middleware.CustomRecovery(),
middleware.CorsHandler(),
middleware.AppContextHandler(),
middleware.AuthorizationHandler(),
)
}
//// set up trusted agents
//err := r.SetTrustedProxies([]string{"127.0.0.1"})
//if err != nil {
// panic(err)
//}
// ping
//r.Any("/ping", func(c *gin.Context) {
// c.AbortWithStatusJSON(http.StatusOK, gin.H{
// "message": "pong!",
// })
//})
// 设置 API 路由
setApiRoute(r)
r.NoRoute(func(c *gin.Context) {
response2.Resp().SetHttpCode(http.StatusNotFound).FailCode(c, errors.NotFound)
})
return r
}
// ReleaseRouter 生产模式使用官方建议设置为 release 模式
func ReleaseRouter() *gin.Engine {
// 切换到生产模式
gin.SetMode(gin.ReleaseMode)
// 禁用 gin 输出接口访问日志
gin.DefaultWriter = ioutil.Discard
engine := gin.New()
return engine
}

View File

@ -0,0 +1,152 @@
package component
import (
"errors"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/utils"
"strings"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/model/component"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/go-sysinfo"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/go-sysinfo/types"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/log"
telegrafConfig "github.com/influxdata/telegraf/config"
"github.com/influxdata/telegraf/plugins/outputs/http"
"github.com/influxdata/telegraf/plugins/outputs/prometheus_client"
_ "github.com/influxdata/telegraf/plugins/parsers/prometheus"
_ "github.com/influxdata/telegraf/plugins/serializers/json"
_ "github.com/influxdata/telegraf/plugins/serializers/prometheus"
_ "github.com/influxdata/telegraf/plugins/serializers/prometheusremotewrite"
_ "github.com/influxdata/telegraf/plugins/inputs/cpu" // register plugin
_ "github.com/influxdata/telegraf/plugins/inputs/disk" // register plugin
_ "github.com/influxdata/telegraf/plugins/inputs/diskio" // register plugin
//_ "github.com/influxdata/telegraf/plugins/inputs/all"
_ "github.com/influxdata/telegraf/plugins/inputs/http" // register plugin
_ "github.com/influxdata/telegraf/plugins/inputs/kernel" // register plugin
_ "github.com/influxdata/telegraf/plugins/inputs/linux_cpu" // register plugin
_ "github.com/influxdata/telegraf/plugins/inputs/mem" // register plugin
_ "github.com/influxdata/telegraf/plugins/inputs/nats" // register plugin
_ "github.com/influxdata/telegraf/plugins/inputs/net" // register plugin
_ "github.com/influxdata/telegraf/plugins/inputs/netstat" // register plugin
_ "github.com/influxdata/telegraf/plugins/inputs/nstat" // register plugin
_ "github.com/influxdata/telegraf/plugins/inputs/processes" // register plugin
_ "github.com/influxdata/telegraf/plugins/inputs/swap" // register plugin
_ "github.com/influxdata/telegraf/plugins/inputs/sysstat" // register plugin
_ "github.com/influxdata/telegraf/plugins/inputs/system" // register plugin
_ "github.com/influxdata/telegraf/plugins/inputs/systemd_units" // register plugin
_ "github.com/influxdata/telegraf/plugins/inputs/win_eventlog" // register plugin
_ "github.com/influxdata/telegraf/plugins/inputs/win_services" // register plugin
_ "github.com/influxdata/telegraf/plugins/inputs/wireless" // register plugin
)
func GetComInfo() ([]component.Component, error) {
var telegrafCom component.Component
info, err := GetTelegrafProcessInfo()
if err != nil {
telegrafCom.COMName = "telegraf"
telegrafCom.COMPort = 0
telegrafCom.COMType = "telegraf"
telegrafCom.COMVersion = "1.28.2"
telegrafCom.Status = "0"
} else {
telegrafCom.COMName = "telegraf"
telegrafCom.COMPort = 0
telegrafCom.COMType = "telegraf"
telegrafCom.COMVersion = "1.28.2"
telegrafCom.LastStarttime = info.StartTime
telegrafCom.Status = "1"
}
runDirectory, _ := utils.GetCurrentPath()
conf := runDirectory + "/data-collector/telegraf/conf/telegraf.conf"
c := telegrafConfig.NewConfig()
err = c.LoadConfig(conf)
if err != nil {
log.Errorf("读取Telegraf配置失败%s", err)
log.Errorf("读取Telegraf配置失败%s", conf)
} else {
inputs := c.Inputs
for _, input := range inputs {
telegrafCom.Config.Metrics = append(telegrafCom.Config.Metrics, input.Config.Name)
}
outputs := c.Outputs
for _, output := range outputs {
prometheusClient, ok := output.Output.(*prometheus_client.PrometheusClient)
if ok {
ms1 := component.MetricServer{
Name: output.Config.Name,
Address: prometheusClient.Listen + prometheusClient.Path,
}
telegrafCom.Config.MetricServer = append(telegrafCom.Config.MetricServer, ms1)
} else {
httpClient, ok := output.Output.(*http.HTTP)
if ok {
ms2 := component.MetricServer{
Name: output.Config.Name,
Address: httpClient.URL,
}
telegrafCom.Config.MetricServer = append(telegrafCom.Config.MetricServer, ms2)
}
}
}
telegrafCom.Config.Tags = c.Tags
}
data := make([]component.Component, 1)
data[0] = telegrafCom
return data, nil
}
func GetTelegrafProcessInfo() (*types.ProcessInfo, error) {
processes, err := sysinfo.Processes()
if err != nil {
log.Errorf("心跳检测服务调用失败!")
return nil, err
}
for _, process := range processes {
info, err := process.Info()
if err != nil {
continue
}
if strings.Contains(info.Name, "telegraf") || strings.Contains(info.Name, "Telegraf") {
return &info, nil
}
}
return nil, errors.New("telegraf采集器进程未运行")
}
func GetProcessExporterProcessInfo() (*types.ProcessInfo, error) {
processes, err := sysinfo.Processes()
if err != nil {
log.Errorf("心跳检测服务调用失败!")
return nil, err
}
for _, process := range processes {
info, err := process.Info()
if err != nil {
continue
}
if strings.Contains(info.Name, "process-exporter") || strings.Contains(info.Name, "process-exporter") {
return &info, nil
}
}
return nil, errors.New("process-exporte采集器进程未运行")
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,68 @@
package component
import (
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/boot"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config/bin_path"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/log"
process_manager "git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/process-manager"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/utils"
"io/fs"
"os"
"path/filepath"
"time"
)
var (
telegrafConfFile = filepath.Join(bin_path.BINDIR, "/data-collector/telegraf/conf/", "telegraf.conf")
bakFile = filepath.Join(bin_path.BINDIR, "/data-collector/telegraf/conf/", "telegraf.conf.bak")
)
func UpdateTelegrafConfig(configText []byte) error {
// 1.先备份
oldConfig, err := os.ReadFile(telegrafConfFile)
err = os.WriteFile(bakFile, oldConfig, fs.ModePerm)
if err != nil {
panic("备份文件失败:" + err.Error())
return err
}
// 2.后替换
err = os.WriteFile(telegrafConfFile, configText, fs.ModePerm)
if err != nil {
panic("替换文件失败:" + err.Error())
go rollback(false, err)
return err
}
// 3.再启动,让minit重启
utils.StopCh <- os.Interrupt
time.Sleep(time.Second * 5)
go process_manager.Start(boot.ProcessUnitDir)
return err
}
func RecoverConfig() {
config, _ := os.ReadFile(bakFile)
os.WriteFile(telegrafConfFile, config, fs.ModePerm)
utils.StopCh <- os.Interrupt
time.Sleep(time.Second * 5)
go process_manager.Start(boot.ProcessUnitDir)
}
func rollback(needRestart bool, err error) {
log.Infof("Telegraf配置更新失败: %s", err)
config, _ := os.ReadFile(bakFile)
os.WriteFile(telegrafConfFile, config, fs.ModePerm)
if needRestart {
utils.StopCh <- os.Interrupt
time.Sleep(time.Second * 5)
go process_manager.Start(boot.ProcessUnitDir)
}
}

View File

@ -0,0 +1,102 @@
package heartbeat_service
import (
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/config/agent"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/model/heartbeat"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/internal/service/component"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/go-sysinfo"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/go-sysinfo/providers/shared"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule-agent/pkg/go-sysinfo/types"
"strings"
"time"
)
var (
agentConfig = agent.Agent
commonConfig = config.Config
AgentState = heartbeat.HeartBeat{
AgentVersion: "xxx",
IPAddress: "xxx",
LastStarttime: time.Now(),
MACAddress: "xxx",
SerialNo: "xxx",
}
)
var (
host types.Host
ip, mac string
)
func init() {
host, _ = sysinfo.Host()
ip, mac, _ = shared.NamedNetwork(agentConfig.NetInterface)
RefreshHeartBeatInfo()
}
// RefreshHeartBeatInfo
// 更新心跳信息中的组件信息, 检查Telegraf状态
func RefreshHeartBeatInfo() {
// 每 15 秒钟时执行一次
ticker := time.NewTicker(15 * time.Second)
go func() {
for {
select {
case <-ticker.C:
// 读取状态 更新状态
//0:离线1:在线2:故障
AgentState.IPAddress = ip
AgentState.MACAddress = mac
AgentState.SerialNo = agentConfig.RID
AgentState.AgentVersion = commonConfig.AgentVersion
AgentState.LastStarttime = host.Info().BootTime
AgentState.Architecture = host.Info().Architecture
AgentState.KernelVersion = host.Info().KernelVersion
AgentState.OS = host.Info().OS.Type + " " + host.Info().OS.Platform + " " + host.Info().OS.Version
AgentState.OSType = strings.ToLower(host.Info().OS.Type)
telegraf, err := component.GetTelegrafProcessInfo()
if err != nil {
AgentState.COMInfo = []heartbeat.COMInfo{
{
Name: "telegraf",
LastStarttime: time.Now(),
Status: "2",
},
}
} else {
AgentState.COMInfo = []heartbeat.COMInfo{
{
Name: "telegraf",
LastStarttime: telegraf.StartTime,
Status: "1",
},
}
}
processExporter, err := component.GetProcessExporterProcessInfo()
if err != nil {
AgentState.COMInfo = []heartbeat.COMInfo{
{
Name: "process-exporter",
LastStarttime: time.Now(),
Status: "2",
},
}
} else {
AgentState.COMInfo = []heartbeat.COMInfo{
{
Name: "process-exporter",
LastStarttime: processExporter.StartTime,
Status: "1",
},
}
}
}
}
}()
}

Some files were not shown because too many files have changed in this diff Show More