Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

View File

@ -0,0 +1,22 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/admin/main/config/cmd:all-srcs",
"//app/admin/main/config/conf:all-srcs",
"//app/admin/main/config/dao:all-srcs",
"//app/admin/main/config/http:all-srcs",
"//app/admin/main/config/model:all-srcs",
"//app/admin/main/config/pkg/lint:all-srcs",
"//app/admin/main/config/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,128 @@
### config-admin
#### Version 1.5.21
>1. 增加历史版本文件的diff接口
>2. 修改lintConfig方法
#### Version 1.5.20
>1. 修复创建应用时status为0的bug
#### Version 1.5.19
>1. 应用名显示和隐藏功能
#### Version 1.5.17
>1. 优化 lint 错误信息
>2. 添加 identity lint
#### Version 1.5.16
>1. 按环境搜索正在使用文件的服务名
#### Version 1.5.15
>1. 配置中心api接口home/tag/update支持强制更新
#### Version 1.5.13
>1. 移除检查 toml 文件顶层 kv
#### Version 1.5.12
>1. 服务树项目权限验证取缓存
#### Version 1.5.11
>1. 服务树项目权限验证时如果没有任何权限则返回404避免后续方法applist空指针
#### Version 1.5.10
>1. toml 配置文件后端lint, 语法检查, 不允许顶层KV, 不允许老的 app config
>2. json 配置文件后端lint, 语法检查
#### Version 1.5.9
>1. 保存拷贝的文件时,进行最新源文件判断,最新文件非自己建立的时候进行提示,开启默认验证
#### Version 1.5.8
>1. 发版获取文件接口更新从最多获取每个文件6个版本改成20个同时如果当前发布的文件版本不在其中的话就单独加入
>2. 保存拷贝的文件时,进行最新源文件判断,最新文件非自己建立的时候进行提示
#### Version 1.5.7
>1. 全局面强制发版本时清除单机强制
>2. 配置中心app服务名同步
#### Version 1.5.6
>1. 添加caster获取token接口
>2. 修复app接口时间显示的问题
>3. 回滚操作更改为重新发一个新版本
#### Version 1.5.5
>1. 修复权限验证时user获取不到的bug
>2. 增加缓存有效时间60秒一更新
>3. 增加手动更新缓存功能
#### Version 1.5.4
>1. 优化返回的message信息
#### Version 1.5.3
>1. zone复制取消机房值的验证
#### Version 1.5.2
>1. 公共配置多服务推送bug修复
#### Version 1.5.1
>1. 公共配置多服务推送
#### Version 1.4.4
>1. 修复获取文件列表中如果有引用公共配置可能出现的404问题
#### Version 1.4.3
>1. 修复连续删除的文件会出现在发版中
>2. 删除未配置文件导致无法再添加该文件,因此改为只要是删除统一状态改为配置完成
#### Version 1.4.2
>1. 增加sh003和sh004机房
#### Version 1.4.1
>1. 添加全局面强制更新及选择主机强制更新功能
#### Version 1.3.2
>1. configservice client
#### Version 1.3.1
>1. 增加hz001机房
#### Version 1.3.0
>1. 增加对canal的接口支持
>2. req结构体放入model
#### Version 1.2.9
>1. 修复ctx阻塞连接泄露
#### Version 1.2.8
>1. 修复事务回滚用错的bug
#### Version 1.2.7
>1. 修复configs接口上一个发版文件id不正确的问题
#### Version 1.2.6
>1. 修复新项目无法建build的问题
#### Version 1.2.6
>1. 平台管理透传功能
#### Version 1.2.5
>1. 修复配置中心文件添加无法成功的问题form值为0的bind验证有坑
#### Version 1.2.4
>1. 配置获取接口安全权限增加
>2. sh001的配置复制到sh002功能
>3. 添加文件中选择公共文件的列表只显业配置完成
>4. 修改验证模式从pr变为bm的
#### Version 1.2.1
>1. 修复添加文件时公共文件不是最新的bug
#### Version 1.2.0
>1. bm架构
>2. 通过接口添加文件和发版
#### Version 1.1.3
>1. 己删文件隐藏
#### Version 1.1.2
>1. 公共配置
#### Version 1.1.1
>1. configs接口加入is_delete字段显示
#### Version 1.1.0
>1. build删除
>2. 文件删除
>3. 发版界面改版
#### Version 1.0.5
>1. 迁目录加diff接口
#### Version 1.0.4
>1. bug修复模糊查询只查询项目名部门和项目组非模糊查询
#### Version 1.0.3
>1. 修复配置中心的模糊查询功能
#### Version 1.0.2
>1. 修复app列表错误
#### Version 1.0.1
>1. 增加删除版本接口
>2. 修复环境列表token错误的bug
#### Version 1.0.0
>1. 提供sven 配置中心模块接口
>2. 配置变更通知config-service
>3. 从config-service获取主机信息列表

View File

@ -0,0 +1,14 @@
# Owner
haoguanwei
lintanghui
chenzhihui
# Author
zhoujixiang
lintanghui
linli
# Reviewer
haoguanwei
linli
lintanghui
chenzhihui

View File

@ -0,0 +1,20 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- chenzhihui
- haoguanwei
- linli
- lintanghui
- zhoujixiang
labels:
- admin
- admin/main/config
- main
options:
no_parent_owners: true
reviewers:
- chenzhihui
- haoguanwei
- linli
- lintanghui
- zhoujixiang

View File

@ -0,0 +1,21 @@
# go-common/app/admin/config
##### 项目简介
> 1. sven配置中心模块接口
> 2. 配置中心推送和主机列表
##### 编译环境
> 1. 请只用golang v1.7.x以上版本编译执行。
##### 依赖包
> 1. 公共依赖
##### 编译执行
> 1. 启动执行
> 2. 项目文档http://info.bilibili.co/pages/viewpage.action?pageId=1742325
##### 测试
> 1. 执行当前目录下所有测试文件,测试所有功能
##### 特别说明
> 2. 管理平台地址 http://sven.bilibili.co

View File

@ -0,0 +1,44 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "cmd",
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
data = ["config-admin-example.toml"],
importpath = "go-common/app/admin/main/config/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/config/conf:go_default_library",
"//app/admin/main/config/http:go_default_library",
"//app/admin/main/config/pkg/lint/json:go_default_library",
"//app/admin/main/config/pkg/lint/toml:go_default_library",
"//app/admin/main/config/service:go_default_library",
"//library/log:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,81 @@
[log]
dir = "/data/log/config-admin/"
[auth]
managerHost = "http://uat-manager.bilibili.co"
dashboardHost = "http://dashboard-mng.bilibili.co"
dashboardCaller = "sven"
[auth.DsHTTPClient]
key = "sven"
secret = "a9564ebc3289b7a14551baf8ad5ec60a"
dial = "1s"
timeout = "1s"
keepAlive = "60s"
[auth.DsHTTPClient.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[auth.MaHTTPClient]
key = "f6433799dbd88751"
secret = "36f8ddb1806207fe07013ab6a77a3935"
dial = "1s"
timeout = "1s"
keepAlive = "60s"
[auth.MaHTTPClient.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[auth.session]
sessionIDLength = 32
cookieLifeTime = 1800
cookieName = "sven-apm"
domain = ".bilibili.co"
[auth.session.Memcache]
name = "go-business/auth"
proto = "tcp"
addr = "172.18.33.61:11232"
active = 10
idle = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "80s"
[httpClient]
key = "test"
secret = "e6c4c252dc7e3d8a90805eecd7c73396"
dial = "1s"
timeout = "10s"
keepAlive = "60s"
timer = 1000
[httpClient.breaker]
window = "10s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[orm]
dsn = "test:test@tcp(172.16.33.205:3308)/bilibili_config?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 5
idleTimeout = "4h"
[ormapm]
dsn = "test:test@tcp(172.16.33.205:3308)/bilibili_apm?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 5
idleTimeout = "4h"
[tree]
platform = "2F3b8fDVGlMnj8aCDlMaW"
[ConfSvr]
timeout = "1s"

View File

@ -0,0 +1,47 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"go-common/app/admin/main/config/conf"
"go-common/app/admin/main/config/http"
"go-common/app/admin/main/config/service"
"go-common/library/log"
// register config lint
_ "go-common/app/admin/main/config/pkg/lint/json"
_ "go-common/app/admin/main/config/pkg/lint/toml"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
log.Error("conf.Init() error(%v)", err)
panic(err)
}
// init log
log.Init(conf.Conf.Log)
defer log.Close()
log.Info("config-admin start")
svr := service.New(conf.Conf)
http.Init(conf.Conf, svr)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("config-admin get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
svr.Close()
log.Info("config-admin exit")
return
case syscall.SIGHUP:
// TODO reload
default:
return
}
}
}

View File

@ -0,0 +1,37 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["conf.go"],
importpath = "go-common/app/admin/main/config/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/conf:go_default_library",
"//library/database/orm:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/permit:go_default_library",
"//library/net/rpc:go_default_library",
"//vendor/github.com/BurntSushi/toml:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,98 @@
package conf
import (
"errors"
"flag"
"go-common/library/conf"
"go-common/library/database/orm"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/permit"
"go-common/library/net/rpc"
"github.com/BurntSushi/toml"
)
var (
confPath string
// Conf conf
Conf = &Config{}
client *conf.Client
)
// Config config
type Config struct {
// identify
Auth *permit.Config
// log
Log *log.Config
// orm
ORM *orm.Config
// http client
HTTPClient *bm.ClientConfig
//ConfSvr
ConfSvr *rpc.ClientConfig
//tree
Tree *ServiceTree
// db apm
ORMApm *orm.Config
//BM
BM *bm.ServerConfig
}
// ServiceTree service tree.
type ServiceTree struct {
Platform string
}
func init() {
flag.StringVar(&confPath, "conf", "", "config file")
}
// Init init.
func Init() (err error) {
if confPath != "" {
return local()
}
return remote()
}
func local() (err error) {
_, err = toml.DecodeFile(confPath, &Conf)
return
}
func remote() (err error) {
if client, err = conf.New(); err != nil {
return
}
if err = load(); err != nil {
return
}
go func() {
for range client.Event() {
log.Info("config reload")
if err := load(); err != nil {
log.Error("config reload error (%v)", err)
}
}
}()
return
}
func load() (err error) {
var (
s string
ok bool
tmpConf *Config
)
if s, ok = client.Toml2(); !ok {
return errors.New("load config center error")
}
if _, err = toml.Decode(s, &tmpConf); err != nil {
return errors.New("could not decode config")
}
*Conf = *tmpConf
return
}

View File

@ -0,0 +1,57 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"tree_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/admin/main/config/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"tree.go",
],
importpath = "go-common/app/admin/main/config/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/config/conf:go_default_library",
"//app/admin/main/config/model:go_default_library",
"//library/database/orm:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//vendor/github.com/jinzhu/gorm:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,54 @@
package dao
import (
"context"
"go-common/app/admin/main/config/conf"
"go-common/library/database/orm"
bm "go-common/library/net/http/blademaster"
"github.com/jinzhu/gorm"
)
// Dao dao.
type Dao struct {
c *conf.Config
DB *gorm.DB
DBApm *gorm.DB
client *bm.Client
}
// New new a dao and return.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
DB: orm.NewMySQL(c.ORM),
DBApm: orm.NewMySQL(c.ORMApm),
client: bm.NewClient(c.HTTPClient),
}
d.initORM()
return
}
func (d *Dao) initORM() {
d.DB.LogMode(true)
d.DBApm.LogMode(true)
}
// Ping check connection of db , mc.
func (d *Dao) Ping(c context.Context) (err error) {
if d.DB != nil {
err = d.DB.DB().PingContext(c)
}
return
}
// Close close connection of db , mc.
func (d *Dao) Close() {
if d.DB != nil {
d.DB.Close()
}
if d.DBApm != nil {
d.DBApm.Close()
}
}

View File

@ -0,0 +1,45 @@
package dao
import (
"flag"
"os"
"strings"
"testing"
"go-common/app/admin/main/config/conf"
gock "gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.common-arch.config-admin")
flag.Set("conf_token", "0OuIaZNZU2Yfa4lXM6e4p2XeGtiQuwyF")
flag.Set("tree_id", "9366")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../cmd/config-admin-example.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
return r
}

View File

@ -0,0 +1,201 @@
package dao
import (
"bytes"
"context"
"fmt"
"net/http"
"strings"
"time"
"go-common/app/admin/main/config/model"
"go-common/library/ecode"
"go-common/library/log"
)
var (
tokenURI = "http://easyst.bilibili.co/v1/token"
dataURI = "http://easyst.bilibili.co/v1/node/apptree"
authURI = "http://easyst.bilibili.co/v1/auth"
nodeURI = "http://easyst.bilibili.co/v1/node/bilibili%s"
appsURI = "http://easyst.bilibili.co/v1/node/role/app"
prefix = []byte("bilibili.")
)
// Token get Token.
func (d *Dao) Token(c context.Context, body string) (msg map[string]interface{}, err error) {
var (
req *http.Request
)
if req, err = http.NewRequest("POST", tokenURI, strings.NewReader(body)); err != nil {
log.Error("Token url(%s) error(%v)", tokenURI, err)
return
}
var res struct {
Code int `json:"code"`
Data map[string]interface{} `json:"data"`
Message string `json:"message"`
Status int `json:"status"`
}
if err = d.client.Do(c, req, &res); err != nil {
log.Error("d.Token url(%s) res(%+v) err(%v)", tokenURI, res, err)
return
}
if res.Code != 90000 {
err = fmt.Errorf("error code :%d", res.Code)
log.Error("Status url(%s) res(%v)", tokenURI, res)
return
}
msg = res.Data
return
}
// Auth get Token.
func (d *Dao) Auth(c context.Context, cookie string) (msg map[string]interface{}, err error) {
var (
req *http.Request
)
if req, err = http.NewRequest("GET", authURI, nil); err != nil {
log.Error("Token url(%s) error(%v)", tokenURI, err)
return
}
req.Header.Set("Cookie", cookie)
var res struct {
Code int `json:"code"`
Data map[string]interface{} `json:"data"`
Message string `json:"message"`
Status int `json:"status"`
}
if err = d.client.Do(c, req, &res); err != nil {
log.Error("d.Token url(%s) res($s) err(%v)", tokenURI, res, err)
return
}
if res.Code != 90000 {
err = fmt.Errorf("error code :%d", res.Code)
log.Error("Status url(%s) res(%v)", tokenURI, res)
return
}
msg = res.Data
return
}
// Tree get service tree.
func (d *Dao) Tree(c context.Context, token string) (data interface{}, err error) {
var (
req *http.Request
tmp map[string]interface{}
ok bool
)
if req, err = http.NewRequest("GET", dataURI, nil); err != nil {
log.Error("Status url(%s) error(%v)", dataURI, err)
return
}
req.Header.Set("X-Authorization-Token", token)
req.Header.Set("Content-Type", "application/json")
var res struct {
Code int `json:"code"`
Data map[string]map[string]interface{} `json:"data"`
Message string `json:"message"`
Status int `json:"status"`
}
if err = d.client.Do(c, req, &res); err != nil {
log.Error("d.Status url(%s) res($s) err(%v)", dataURI, res, err)
return
}
if res.Code != 90000 {
err = fmt.Errorf("error code :%d", res.Code)
log.Error("Status url(%s) res(%v)", dataURI, res)
return
}
if tmp, ok = res.Data["bilibili"]; ok {
data, ok = tmp["children"]
}
if !ok {
err = ecode.NothingFound
}
return
}
// Role get service tree.
func (d *Dao) Role(c context.Context, user, token string) (nodes *model.CacheData, err error) {
var (
req *http.Request
)
if req, err = http.NewRequest("GET", appsURI, nil); err != nil {
log.Error("Status url(%s) error(%v)", dataURI, err)
return
}
req.Header.Set("X-Authorization-Token", token)
req.Header.Set("Content-Type", "application/json")
var res struct {
Code int `json:"code"`
Data []*model.RoleNode `json:"data"`
Message string `json:"message"`
Status int `json:"status"`
}
if err = d.client.Do(c, req, &res); err != nil {
log.Error("d.Status url(%s) res($s) err(%v)", dataURI, res, err)
return
}
if res.Code != 90000 {
err = fmt.Errorf("error code :%d", res.Code)
log.Error("Status url(%s) res(%v)", dataURI, res)
return
}
nodes = &model.CacheData{Data: make(map[int64]*model.RoleNode)}
nodes.CTime = time.Now()
for _, node := range res.Data {
if bytes.Equal(prefix, []byte(node.Path)[0:9]) {
node.Path = string([]byte(node.Path)[9:])
}
nodes.Data[node.ID] = node
}
return
}
// NodeTree get service tree.
func (d *Dao) NodeTree(c context.Context, token, bu, team string) (nodes []*model.Node, err error) {
var (
req *http.Request
node string
)
if len(bu) != 0 {
node = "." + bu
}
if len(team) != 0 {
node = "." + team
}
if len(node) == 0 {
nodes = append(nodes, &model.Node{Name: "main", Path: "main"})
nodes = append(nodes, &model.Node{Name: "ai", Path: "ai"})
return
}
if req, err = http.NewRequest("GET", fmt.Sprintf(nodeURI, node), nil); err != nil {
log.Error("Status url(%s) error(%v)", dataURI, err)
return
}
req.Header.Set("X-Authorization-Token", token)
req.Header.Set("Content-Type", "application/json")
var res struct {
Code int `json:"code"`
Data *model.Res `json:"data"`
Message string `json:"message"`
Status int `json:"status"`
}
if err = d.client.Do(c, req, &res); err != nil {
log.Error("d.Status url(%s) res($s) err(%v)", dataURI, res, err)
return
}
if res.Code != 90000 {
err = fmt.Errorf("error code :%d", res.Code)
log.Error("Status url(%s) error(%v)", dataURI, err)
return
}
for _, tnode := range res.Data.Data {
if bytes.Equal(prefix, []byte(tnode.Path)[0:9]) {
tnode.Path = string([]byte(tnode.Path)[9:])
}
nodes = append(nodes, &model.Node{Name: tnode.Name, Path: tnode.Path})
}
return
}

View File

@ -0,0 +1,137 @@
package dao
import (
"context"
"net/http"
"testing"
"github.com/smartystreets/goconvey/convey"
gock "gopkg.in/h2non/gock.v1"
)
var token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJtYWluIiwicGxhdGZvcm1faWQiOiIyRjNiOGZEVkdsTW5qOGFDRGxNYVciLCJleHAiOjE1NDA2NDE3MjQsImlzcyI6Im1haW4ifQ.SxKceDl69N1su3kDO70c4P1NuPhXOxp5rXpM3n8Jyig"
func TestToken(t *testing.T) {
d.client.SetTransport(gock.DefaultTransport)
convey.Convey("get token", t, func(ctx convey.C) {
ctx.Convey("When http response code != 0", func(ctx convey.C) {
httpMock("POST", "http://easyst.bilibili.co/v1/token").Reply(200).JSON(`{
"code": 90000,
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJtYWluIiwicGxhdGZvcm1faWQiOiIyRjNiOGZEVkdsTW5qOGFDRGxNYVciLCJleHAiOjE1NDA2NDE3MjQsImlzcyI6Im1haW4ifQ.SxKceDl69N1su3kDO70c4P1NuPhXOxp5rXpM3n8Jyig",
"user_name": "main",
"secret": "",
"expired": 1540641724
},
"message": "success",
"status": 200
}`)
data, err := d.Token(context.Background(), "")
ctx.Convey("Then err should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(data, convey.ShouldNotBeNil)
})
})
ctx.Reset(func() {
gock.Off()
d.client.SetTransport(http.DefaultClient.Transport)
})
})
}
func TestAuth(t *testing.T) {
d.client.SetTransport(gock.DefaultTransport)
convey.Convey("get auth", t, func(ctx convey.C) {
ctx.Convey("When http response code != 0", func(ctx convey.C) {
httpMock("GET", "http://easyst.bilibili.co/v1/auth").Reply(200).JSON(`{"code":90000,"message":"success"}`)
_, err := d.Auth(context.Background(), "sven-apm=afab110001a20fa3a1c9b5bd67564ccd71c6253406725184bfa5d88c7ece9d17; Path=/; Domain=bilibili.co; Expires=Tue, 23 Oct 2018 07:25:02 GMT; Max-Age=1800; HttpOnly")
ctx.Convey("Then err should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
// ctx.So(data, convey.ShouldNotBeNil)
})
})
ctx.Reset(func() {
gock.Off()
d.client.SetTransport(http.DefaultClient.Transport)
})
})
}
func TestRole(t *testing.T) {
d.client.SetTransport(gock.DefaultTransport)
convey.Convey("TestRole", t, func(ctx convey.C) {
ctx.Convey("When http response code != 0", func(ctx convey.C) {
httpMock("GET", "http://easyst.bilibili.co/v1/node/role/app").Reply(200).JSON(`{"code":90000,"message":"success"}`)
data, err := d.Role(context.Background(), "linli", token)
ctx.Convey("Then err should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(data, convey.ShouldNotBeNil)
})
})
ctx.Reset(func() {
gock.Off()
d.client.SetTransport(http.DefaultClient.Transport)
})
})
}
func TestNodeTree(t *testing.T) {
d.client.SetTransport(gock.DefaultTransport)
convey.Convey("NodeTree", t, func(ctx convey.C) {
ctx.Convey("When http response code != 0", func(ctx convey.C) {
httpMock("GET", "http://easyst.bilibili.co/v1/node/bilibili.main.common-arch").Reply(200).JSON(`{
"status": 200,
"message": "success",
"code": 90000,
"data": {
"count": 0,
"results": 20,
"page": 1,
"data": null
}
}`)
_, err := d.NodeTree(context.Background(), token, "main.common-arch", "")
ctx.Convey("Then err should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
// ctx.So(data, convey.ShouldNotBeNil)
})
})
ctx.Reset(func() {
gock.Off()
d.client.SetTransport(http.DefaultClient.Transport)
})
})
}
func TestTree(t *testing.T) {
d.client.SetTransport(gock.DefaultTransport)
convey.Convey("TestTree", t, func(ctx convey.C) {
ctx.Convey("When http response code != 0", func(ctx convey.C) {
httpMock("GET", "http://easyst.bilibili.co/v1/node/apptree").Reply(200).JSON(`{
"code": 90000,
"data": {
"bilibili": {
"id": 0,
"name": "bilibili",
"alias": "哔哩哔哩",
"type": 1,
"path": "bilibili",
"tags": {},
"children": null
}
},
"message": "success",
"status": 200
}`)
_, err := d.Tree(context.Background(), token)
ctx.Convey("Then err should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
// ctx.So(data, convey.ShouldNotBeNil)
})
})
ctx.Reset(func() {
gock.Off()
d.client.SetTransport(http.DefaultClient.Transport)
})
})
}

View File

@ -0,0 +1,49 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"apm.go",
"app.go",
"build.go",
"common.go",
"conf_svr.go",
"config.go",
"http.go",
"tag.go",
"tree.go",
],
importpath = "go-common/app/admin/main/config/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/config/conf:go_default_library",
"//app/admin/main/config/model:go_default_library",
"//app/admin/main/config/service:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/permit:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/jinzhu/gorm:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,36 @@
package http
import (
"go-common/app/admin/main/config/model"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
func apmCopy(c *bm.Context) {
res := map[string]interface{}{}
user := user(c)
v := new(model.ApmCopyReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApp(c, user, c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
cnt := 0
if err = svr.DB.Model(&model.App{}).Where("tree_id=?", v.TreeID).Count(&cnt).Error; err != nil {
log.Error("svr.ApmCopy count error(%v)", err)
res["message"] = "查询该服务失败"
c.JSONMap(res, err)
return
}
if cnt <= 0 {
log.Error("svr.ApmCopy count (%v)", cnt)
res["message"] = "未找到该服务"
c.JSONMap(res, err)
return
}
c.JSON(nil, svr.Apm(v.TreeID, v.Name, v.ApmName, user))
}

View File

@ -0,0 +1,277 @@
package http
import (
"go-common/app/admin/main/config/model"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"strconv"
"strings"
)
func updateToken(c *bm.Context) {
v := new(model.UpdateTokenReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApp(c, user(c), c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
c.JSON(nil, err)
return
}
if err = svr.UpdateToken(c, v.Env, v.Zone, v.TreeID); err != nil {
c.JSON(nil, err)
return
}
c.JSON(nil, err)
}
func create(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.CreateReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApp(c, user(c), c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
creates := []string{"dev", "fat1", "uat", "pre", "prod"}
for _, val := range creates {
if err = svr.CreateApp(v.AppName, val, model.DefaultZone, v.TreeID); err != nil {
res["message"] = "创建app失败"
c.JSONMap(res, err)
return
}
}
c.JSON(nil, err)
}
func appList(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.AppListReq)
err := c.Bind(v)
if err != nil {
return
}
nodes, err := svr.AuthApps(c, user(c), c.Request.Header.Get("Cookie"))
if err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
app, err := svr.AppList(c, v.Bu, v.Team, v.AppName, model.DefaultEnv, model.DefaultZone, v.Ps, v.Pn, nodes, v.Status)
if err != nil {
res["message"] = "数据获取失败"
c.JSONMap(res, err)
return
}
result := app
c.JSON(result, nil)
}
func envsByTeam(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.EnvsByTeamReq)
err := c.Bind(v)
if err != nil {
return
}
nodes, err := svr.AuthApps(c, user(c), c.Request.Header.Get("Cookie"))
if err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
data, err := svr.EnvsByTeam(c, v.AppName, v.Zone, nodes)
if err != nil {
c.JSON(nil, err)
return
}
result := data
c.JSON(result, nil)
}
func envs(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.EnvsReq)
err := c.Bind(v)
if err != nil {
return
}
user := user(c)
nodes, err := svr.AuthApps(c, user, c.Request.Header.Get("Cookie"))
if err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.Envs(c, user, v.AppName, v.Zone, v.TreeID, nodes))
}
func nodeTree(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.NodeTreeReq)
err := c.Bind(v)
if err != nil {
return
}
cookie := c.Request.Header.Get("Cookie")
user := user(c)
nodes, err := svr.AuthApps(c, user, cookie)
if err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.Node(c, user, v.Node, v.Team, cookie, nodes))
}
func zoneCopy(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.ZoneCopyReq)
err := c.Bind(v)
if err != nil {
return
}
if v.From == v.To {
res["message"] = "来源机房和目标机房不能是同一个"
c.JSONMap(res, ecode.RequestErr)
return
}
if _, err = svr.AuthApp(c, user(c), c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
if err = svr.ZoneCopy(c, v.AppName, v.From, v.To, v.TreeID); err != nil {
res["message"] = "拷贝失败"
c.JSONMap(res, err)
return
}
c.JSON(nil, err)
}
func casterEnvs(c *bm.Context) {
v := new(model.CasterEnvsReq)
err := c.Bind(v)
if err != nil {
return
}
if v.Auth != "caster_envs_all" {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(svr.CasterEnvs(v.Zone, v.TreeID))
}
func rename(c *bm.Context) {
res := map[string]interface{}{}
v := new(struct {
TreeID int64 `form:"tree_id" validate:"required"`
})
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApp(c, user(c), c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(nil, svr.AppRename(v.TreeID, user(c), c.Request.Header.Get("Cookie")))
}
func getApps(c *bm.Context) {
v := new(struct {
Name string `form:"name" validate:"required"`
Env string `form:"env" validate:"required"`
})
err := c.Bind(v)
if err != nil {
return
}
apps, err := svr.GetApps(v.Env)
if err != nil {
c.JSON(nil, err)
return
}
var appIDS []int64
for _, val := range apps {
appIDS = append(appIDS, val.ID)
}
if len(appIDS) == 0 {
c.JSON(nil, ecode.RequestErr)
return
}
builds, err := svr.AllBuilds(appIDS)
if err != nil {
c.JSON(nil, err)
return
}
var tagIDS []int64
for _, val := range builds {
tagIDS = append(tagIDS, val.TagID)
}
tags, err := svr.GetConfigIDS(tagIDS)
if err != nil {
c.JSON(nil, err)
return
}
var configIDS []int64
for _, val := range tags {
tmpIDs := strings.Split(val.ConfigIDs, ",")
for _, vv := range tmpIDs {
id, err := strconv.ParseInt(vv, 10, 64)
if err != nil {
log.Error("strconv.ParseInt() error(%v)", err)
return
}
configIDS = append(configIDS, id)
}
}
var appids []int64
var appslist []*model.App
var names []string
if len(configIDS) > 0 {
configs, err := svr.GetConfigs(configIDS, v.Name)
if err != nil {
c.JSON(nil, err)
return
}
for _, val := range configs {
appids = append(appids, val.AppID)
}
appslist, err = svr.IdsGetApps(appids)
if err != nil {
c.JSON(nil, err)
return
}
for _, val := range appslist {
names = append(names, val.Name)
}
}
c.JSON(names, nil)
}
func upAppStatus(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.AppStatusReq)
err := c.Bind(v)
if err != nil {
return
}
if !(v.Status == model.StatusShow || v.Status == model.StatusHidden) {
c.JSON(nil, ecode.RequestErr)
return
}
_, err = svr.AuthApps(c, user(c), c.Request.Header.Get("Cookie"))
if err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(nil, svr.UpAppStatus(c, v.Status, v.TreeID))
}

View File

@ -0,0 +1,94 @@
package http
import (
"strings"
"go-common/app/admin/main/config/model"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
)
func createBuild(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.CreateBuildReq)
err := c.Bind(v)
if err != nil {
return
}
name := user(c)
if _, err = svr.AuthApp(c, name, c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
if len(strings.TrimSpace(v.Name)) == 0 {
res["message"] = "name不能为空"
c.JSONMap(res, ecode.RequestErr)
return
}
build := &model.Build{}
build.TagID = v.TagID
build.Operator = name
build.Name = v.Name
if err = svr.CreateBuild(build, v.TreeID, v.Env, v.Zone); err != nil {
res["message"] = "创建build失败"
c.JSONMap(res, err)
return
}
c.JSON(nil, err)
}
func builds(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.BuildsReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApp(c, user(c), c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.Builds(v.TreeID, v.AppName, v.Env, v.Zone))
}
func build(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.BuildReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApps(c, user(c), c.Request.Header.Get("Cookie")); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.Build(v.BuildID))
}
func buildDel(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.BuildReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApps(c, user(c), c.Request.Header.Get("Cookie")); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
if err = svr.GetDelInfos(c, v.BuildID); err != nil {
res["message"] = "主机列表中有正在使用该build的机器请让主机离线3小时自动清除后再删除"
c.JSONMap(res, err)
return
}
if err = svr.Delete(v.BuildID); err != nil {
res["message"] = "删除build失败"
c.JSONMap(res, err)
return
}
c.JSON(nil, err)
}

View File

@ -0,0 +1,164 @@
package http
import (
"go-common/app/admin/main/config/model"
bm "go-common/library/net/http/blademaster"
"go-common/library/time"
"strconv"
"strings"
)
func createComConfig(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.CreateComConfigReq)
err := c.Bind(v)
if err != nil {
return
}
name := user(c)
if _, err = svr.AuthApps(c, name, c.Request.Header.Get("Cookie")); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
conf := &model.CommonConf{}
conf.Operator = name
conf.State = v.State
conf.Comment = v.Comment
conf.Mark = v.Mark
conf.Name = v.Name
c.JSON(nil, svr.CreateComConf(conf, v.Team, v.Env, v.Zone, v.SkipLint))
}
func comValue(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.ComValueReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApps(c, user(c), c.Request.Header.Get("Cookie")); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.ComConfig(v.ConfigID))
}
func configsByTeam(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.ConfigsByTeamReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApps(c, user(c), c.Request.Header.Get("Cookie")); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.ComConfigsByTeam(v.Team, v.Env, v.Zone, v.Ps, v.Pn))
}
func comConfigsByName(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.ComConfigsByNameReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApps(c, user(c), c.Request.Header.Get("Cookie")); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.ComConfigsByName(v.Team, v.Env, v.Zone, v.Name))
}
func updateComConfValue(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.UpdateComConfValueReq)
err := c.Bind(v)
if err != nil {
return
}
user := user(c)
if _, err = svr.AuthApps(c, user, c.Request.Header.Get("Cookie")); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
conf := &model.CommonConf{}
conf.Mtime = time.Time(v.Mtime)
conf.Mark = v.Mark
conf.ID = v.ID
conf.State = v.State
conf.Comment = v.Comment
conf.Operator = user
conf.Name = v.Name
c.JSON(nil, svr.UpdateComConfValue(conf, v.SkipLint))
}
func namesByTeam(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.NamesByTeamReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApps(c, user(c), c.Request.Header.Get("Cookie")); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.NamesByTeam(v.Team, v.Env, v.Zone))
}
func appByTeam(c *bm.Context) {
v := new(struct {
CommonConfigID int64 `form:"common_config_id" validate:"required"`
})
err := c.Bind(v)
if err != nil {
return
}
tagMap, err := svr.AppByTeam(v.CommonConfigID)
if err != nil {
c.JSON(nil, err)
return
}
c.JSON(tagMap, nil)
}
func tagPush(c *bm.Context) {
v := new(struct {
CommonConfigID int64 `form:"common_config_id" validate:"required"`
Tags string `form:"tags" validate:"required"`
})
err := c.Bind(v)
if err != nil {
return
}
user := user(c)
tagMap, err := svr.AppByTeam(v.CommonConfigID)
if err != nil {
c.JSON(nil, err)
return
}
res := make(map[int64]interface{})
tagIDS := strings.Split(v.Tags, ",")
for _, val := range tagIDS {
val, _ := strconv.ParseInt(val, 10, 64)
if _, ok := tagMap[val]; ok {
err = svr.CommonPush(c, val, v.CommonConfigID, user)
if err == nil {
res[val] = "success"
} else {
res[val] = "fail"
}
} else {
res[val] = "data error"
}
}
c.JSON(res, nil)
}

View File

@ -0,0 +1,59 @@
package http
import (
"go-common/app/admin/main/config/model"
bm "go-common/library/net/http/blademaster"
)
func setToken(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.SetTokenReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApp(c, user(c), c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
// update & write cache
if err = svr.SetToken(c, v.TreeID, v.Env, v.Zone, v.Token); err != nil {
res["message"] = "重置token失败"
c.JSONMap(res, err)
return
}
c.JSON(nil, err)
}
// hosts client hosts
func hosts(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.HostsReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApp(c, user(c), c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.Hosts(c, v.TreeID, v.App, v.Env, v.Zone))
}
//clear host in redis
func clearhost(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.HostsReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApp(c, user(c), c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(nil, svr.ClearHost(c, v.TreeID, v.Env, v.Zone))
}

View File

@ -0,0 +1,617 @@
package http
import (
"encoding/json"
"fmt"
"go-common/app/admin/main/config/model"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/time"
"strconv"
"strings"
"github.com/jinzhu/gorm"
)
func createConfig(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.CreateConfigReq)
err := c.Bind(v)
if err != nil {
return
}
user := user(c)
if _, err = svr.AuthApp(c, user, c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
conf := &model.Config{}
conf.Operator = user
conf.Name = v.Name
conf.Mark = v.Mark
conf.Comment = v.Comment
conf.State = v.State
conf.From = v.From
c.JSON(nil, svr.CreateConf(conf, v.TreeID, v.Env, v.Zone, v.SkipLint))
}
func lintConfig(c *bm.Context) {
var req struct {
Name string `form:"name" validate:"required"`
Comment string `form:"comment" validate:"required"`
}
if err := c.Bind(&req); err != nil {
// ignore error
return
}
c.JSON(svr.LintConfig(req.Name, req.Comment))
}
func updateConfValue(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.UpdateConfValueReq)
err := c.Bind(v)
if err != nil {
return
}
user := user(c)
if _, err = svr.AuthApps(c, user, c.Request.Header.Get("Cookie")); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
conf := &model.Config{}
conf.Name = v.Name
conf.ID = v.ID
conf.Operator = user
conf.Mark = v.Mark
conf.Comment = v.Comment
conf.State = v.State
conf.Mtime = time.Time(v.Mtime)
var configs *model.Config
configs, err = svr.Value(v.ID)
if err != nil {
res["message"] = "未找到源文件"
c.JSONMap(res, err)
return
}
if v.NewCommon > 0 {
common := &model.CommonConf{}
common2 := &model.CommonConf{}
if err = svr.DB.Where("id = ?", configs.From).First(common).Error; err != nil {
res["message"] = "未找到公共源文件"
c.JSONMap(res, err)
return
}
if err = svr.DB.Where("team_id = ? and name = ? and state = 2 and id = ?", common.TeamID, common.Name, v.NewCommon).Order("id desc").First(common2).Error; err != nil {
res["message"] = "未找到最新的公共文件"
c.JSONMap(res, err)
return
}
conf.From = v.NewCommon
}
//验证是否最新源文件
newConfig := &model.Config{}
if err = svr.DB.Where("app_id = ? and name = ?", configs.AppID, configs.Name).Order("id desc").First(newConfig).Error; err != nil {
res["message"] = "未找到最新文件"
c.JSONMap(res, err)
return
}
//默认验证ignore 0
if newConfig.ID != v.ID && v.Ignore == 0 && user != newConfig.Operator {
err = ecode.ConfigNotNow
res["message"] = fmt.Sprintf("当前源文件:%d有最新源文件版本%d操作人:%s是否继续提交", v.ID, newConfig.ID, newConfig.Operator)
c.JSONMap(res, err)
return
}
c.JSON(nil, svr.UpdateConfValue(conf, v.SkipLint))
}
func value(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.ValueReq)
err := c.Bind(v)
if err != nil {
return
}
var TreeID int64
TreeID, err = svr.ConfigGetTreeID(v.ConfigID)
if err != nil {
res["message"] = "未找到tree_id"
c.JSONMap(res, err)
return
}
if _, err = svr.AuthApp(c, user(c), c.Request.Header.Get("Cookie"), TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.Value(v.ConfigID))
}
func configsByBuildID(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.ConfigsByBuildIDReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApps(c, user(c), c.Request.Header.Get("Cookie")); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.ConfigsByBuildID(v.BuildID))
}
func configsByTagID(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.ConfigsByTagIDReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApps(c, user(c), c.Request.Header.Get("Cookie")); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.ConfigsByTagID(v.TagID))
}
func configsByAppName(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.ConfigsByAppNameReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApp(c, user(c), c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.ConfigsByAppName(v.AppName, v.Env, v.Zone, v.TreeID, 0))
}
func configSearchAll(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.ConfigSearchAllReq)
err := c.Bind(v)
if err != nil {
return
}
nodes, err := svr.AuthApps(c, user(c), c.Request.Header.Get("Cookie"))
if err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.ConfigSearchAll(c, v.Env, v.Zone, v.Like, nodes))
}
func configSearchApp(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.ConfigSearchAppReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApp(c, user(c), c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.ConfigSearchApp(c, v.AppName, v.Env, v.Zone, v.Like, v.BuildID, v.TreeID))
}
func configsByName(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.ConfigsByNameReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApp(c, user(c), c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.ConfigsByTree(v.TreeID, v.Env, v.Zone, v.Name))
}
func configs(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.ConfigsReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApp(c, user(c), c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.Configs(v.AppName, v.Env, v.Zone, v.BuildID, v.TreeID))
}
func configRefs(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.ConfigRefsReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApp(c, user(c), c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.ConfigRefs(v.AppName, v.Env, v.Zone, v.BuildID, v.TreeID))
}
func namesByAppName(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.NamesByAppNameReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApp(c, user(c), c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.NamesByAppTree(v.AppName, v.Env, v.Zone, v.TreeID))
}
func diff(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.DiffReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApps(c, user(c), c.Request.Header.Get("Cookie")); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.Diff(v.ConfigID, v.BuildID))
}
func configDel(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.ConfigDelReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApps(c, user(c), c.Request.Header.Get("Cookie")); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(nil, svr.ConfigDel(v.ConfigID))
}
func configBuildInfos(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.ConfigBuildInfosReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApp(c, user(c), c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.BuildConfigInfos(v.AppName, v.Env, v.Zone, v.BuildID, v.TreeID))
}
func configUpdate(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.ConfigUpdateReq)
err := c.Bind(v)
if err != nil {
return
}
app := &model.App{}
if err = svr.DB.Where("name = ? and env = ? and zone = ? and tree_id = ? and token = ?", v.AppName, v.Env, v.Zone, v.TreeID, v.Token).First(app).Error; err != nil {
res["message"] = "参数不正确,未找到该服务"
c.JSONMap(res, err)
return
}
var obj []map[string]string
err = json.Unmarshal([]byte(v.Data), &obj)
tx := svr.DB.Begin()
for _, val := range obj {
if len(val["name"]) > 0 {
config := &model.Config{}
if err = tx.Where("app_id = ? and name = ? and state = 1", app.ID, val["name"]).First(config).Error; err != nil {
if err != gorm.ErrRecordNotFound {
c.JSON(nil, err)
tx.Rollback()
return
}
} else {
//把老的更新了再加新的
ups := map[string]interface{}{
"state": 2,
}
if err = tx.Model(&model.App{}).Where("id = ? ", config.ID).Updates(ups).Error; err != nil {
c.JSON(nil, err)
tx.Rollback()
return
}
}
//加新的
m := &model.Config{
AppID: app.ID,
Name: val["name"],
Comment: val["comment"],
State: 2,
Mark: val["mark"],
Operator: v.User,
}
db := tx.Create(m)
if err = db.Error; err != nil {
res["message"] = "创建失败"
c.JSONMap(res, err)
tx.Rollback()
return
}
} else {
c.JSON(nil, ecode.RequestErr)
tx.Rollback()
return
}
}
tx.Commit()
c.JSON(nil, err)
}
func tagUpdate(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.TagUpdateReq)
err := c.Bind(v)
if err != nil {
return
}
if len(strings.TrimSpace(v.Build)) == 0 {
c.JSON(nil, ecode.RequestErr)
return
}
app := &model.App{}
if err = svr.DB.Where("name = ? and env = ? and zone = ? and tree_id = ? and token = ?", v.AppName, v.Env, v.Zone, v.TreeID, v.Token).First(app).Error; err != nil {
res["message"] = "参数不正确,未找到该服务"
c.JSONMap(res, err)
return
}
confs := []*model.Config{}
tags := &model.Tag{}
tag := &model.Tag{}
build := &model.Build{}
tagConfigs := []*model.Config{}
var in []string
var in2 []string
var nameString string
tmp := make(map[string]struct{})
if v.ConfigIDs == "" && v.Names == "" {
c.JSON(nil, ecode.RequestErr)
return
} else if v.Names != "" {
in = strings.Split(v.Names, ",")
if err = svr.DB.Select("max(id) as id,name").Where("app_id = ? and state = 2 and is_delete = 0 and name in (?)", app.ID, in).Group("name").Find(&confs).Error; err != nil {
res["message"] = "未找到发版文件"
c.JSONMap(res, err)
return
}
for _, vv := range confs {
if len(nameString) > 0 {
nameString = nameString + ","
}
nameString = nameString + strconv.FormatInt(vv.ID, 10)
}
tag.ConfigIDs = nameString
} else if v.ConfigIDs != "" {
in = strings.Split(v.ConfigIDs, ",")
if err = svr.DB.Where("app_id = ? and state = 2 and is_delete = 0 and id in (?)", app.ID, in).Find(&confs).Error; err != nil {
res["message"] = "未找到发版文件"
c.JSONMap(res, err)
return
}
tag.ConfigIDs = v.ConfigIDs
}
if v.Names != "" && v.Increment == 1 {
if err = svr.DB.Where("app_id = ? and name = ?", app.ID, v.Build).Order("id desc").First(build).Error; err != nil {
res["message"] = "未找到对应的build"
c.JSONMap(res, err)
return
}
if err = svr.DB.Where("app_id = ? and build_id = ?", app.ID, build.ID).Order("id desc").First(tags).Error; err != nil {
res["message"] = "未找到对应的tag"
c.JSONMap(res, err)
return
}
in2 = strings.Split(tags.ConfigIDs, ",")
if err = svr.DB.Where("app_id = ? and state = 2 and id in (?)", app.ID, in2).Find(&tagConfigs).Error; err != nil {
res["message"] = "未找到tag中的文件"
c.JSONMap(res, err)
return
}
for _, vv := range tagConfigs {
tss := 0
for _, vvv := range confs {
if vv.Name == vvv.Name {
tss = 1
}
}
if tss != 1 {
if len(nameString) > 0 {
nameString = nameString + ","
}
nameString = nameString + strconv.FormatInt(vv.ID, 10)
}
}
tag.ConfigIDs = nameString
} else {
if len(confs) != len(in) {
res["message"] = "发版数据不符"
c.JSONMap(res, ecode.RequestErr)
return
}
for _, vv := range confs {
if _, ok := tmp[vv.Name]; !ok {
tmp[vv.Name] = struct{}{}
}
}
if len(tmp) != len(confs) {
res["message"] = "有重复的文件名"
c.JSONMap(res, ecode.RequestErr)
return
}
}
tag.Operator = v.User
tag.Mark = v.Mark
if v.Force == 1 {
tag.Force = 1
}
c.JSON(nil, svr.UpdateTag(c, v.TreeID, v.Env, v.Zone, v.Build, tag))
}
func canalTagUpdate(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.CanalTagUpdateReq)
err := c.Bind(v)
if err != nil {
return
}
if v.Force != 1 {
v.Force = 0
}
if len(strings.TrimSpace(v.Build)) == 0 {
c.JSON(nil, ecode.RequestErr)
return
}
app := &model.App{}
if err = svr.DB.Where("name = ? and env = ? and zone = ? and tree_id = ? and token = ?", v.AppName, v.Env, v.Zone, v.TreeID, v.Token).First(app).Error; err != nil {
res["message"] = "参数不正确,未找到该服务"
c.JSONMap(res, err)
return
}
confs := []*model.Config{}
configs := []*model.Config{}
tags := &model.Tag{}
tag := &model.Tag{}
build := &model.Build{}
tagConfigs := []*model.Config{}
var in []string
var in2 []string
var nameString string
tmp := make(map[string]struct{})
in = strings.Split(v.ConfigIDs, ",")
if err = svr.DB.Where("app_id = ? and state = 2 and id in(?)", app.ID, in).Find(&configs).Error; err != nil {
res["message"] = "未找到文件"
c.JSONMap(res, err)
return
}
if len(configs) != len(in) {
res["message"] = fmt.Sprintf("数据不匹配,传的数据为(%v)条,查到的数据为(%v)条,app_id(%v),config_ids(%v),in(%v)", len(in), len(configs), app.ID, v.ConfigIDs, in)
err = ecode.RequestErr
c.JSONMap(res, err)
return
}
if err = svr.DB.Where("app_id = ? and name = ?", app.ID, v.Build).Order("id desc").First(build).Error; err != nil {
res["message"] = "未找到对应的build"
c.JSONMap(res, err)
return
}
if err = svr.DB.Where("app_id = ? and build_id = ?", app.ID, build.ID).Order("id desc").First(tags).Error; err != nil {
res["message"] = "未找到对应的tag"
c.JSONMap(res, err)
return
}
in2 = strings.Split(tags.ConfigIDs, ",")
if err = svr.DB.Where("app_id = ? and state = 2 and id in (?)", app.ID, in2).Find(&tagConfigs).Error; err != nil {
res["message"] = "未找到tag中的文件"
c.JSONMap(res, err)
return
}
if err = svr.DB.Select("id,app_id,name,`from`,state,mark,operator,ctime,mtime").Where(in2).Find(&confs).Error; err != nil {
log.Error("ConfigsByIDs(%v) error(%v)", in2, err)
res["message"] = "config文件未找到"
c.JSONMap(res, err)
return
}
for _, val := range confs {
for _, vv := range configs {
if val.Name == vv.Name {
if len(nameString) > 0 {
nameString = nameString + ","
}
nameString = nameString + strconv.FormatInt(vv.ID, 10)
tmp[vv.Name] = struct{}{}
}
}
if _, ok := tmp[val.Name]; !ok {
if len(nameString) > 0 {
nameString = nameString + ","
}
nameString = nameString + strconv.FormatInt(val.ID, 10)
}
}
for _, val := range configs {
if _, ok := tmp[val.Name]; !ok {
if len(nameString) > 0 {
nameString = nameString + ","
}
nameString = nameString + strconv.FormatInt(val.ID, 10)
}
}
tag.ConfigIDs = nameString
tag.Operator = v.User
tag.Mark = v.Mark
tag.Force = v.Force
c.JSON(nil, svr.UpdateTag(c, v.TreeID, v.Env, v.Zone, v.Build, tag))
}
func canalConfigCreate(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.CanalConfigCreateReq)
err := c.Bind(v)
if err != nil {
return
}
if err = svr.CanalCheckToken(v.AppName, v.Env, v.Zone, v.Token); err != nil {
res["message"] = "未找到数据"
c.JSONMap(res, err)
return
}
conf := &model.Config{}
conf.Operator = v.User
conf.Name = v.Name
conf.Mark = v.Mark
conf.Comment = v.Comment
conf.State = v.State
conf.From = v.From
c.JSON(nil, svr.CreateConf(conf, v.TreeID, v.Env, v.Zone, true))
}
func canalNameConfigs(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.CanalNameConfigsReq)
err := c.Bind(v)
if err != nil {
return
}
if err = svr.CanalCheckToken(v.AppName, v.Env, v.Zone, v.Token); err != nil {
res["message"] = "未找到数据"
c.JSONMap(res, err)
return
}
c.JSON(svr.ConfigsByTree(v.TreeID, v.Env, v.Zone, v.Name))
}

View File

@ -0,0 +1,136 @@
package http
import (
"net/http"
"go-common/app/admin/main/config/conf"
"go-common/app/admin/main/config/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/permit"
)
var (
svr *service.Service
authSrv *permit.Permit
)
// Init init config.
func Init(c *conf.Config, s *service.Service) {
svr = s
authSrv = permit.New(c.Auth)
engine := bm.DefaultServer(c.BM)
innerRouter(engine)
if err := engine.Start(); err != nil {
log.Error("engine.Start error(%v)", err)
panic(err)
}
}
// innerRouter init inner router.
func innerRouter(e *bm.Engine) {
e.Ping(ping)
b := e.Group("x/admin/config", authSrv.Verify())
d := e.Group("x/admin/config")
{
notAuth := d.Group("/")
{
notAuth.POST("home/config/update", configUpdate)
notAuth.POST("home/tag/update", tagUpdate)
notAuth.POST("canal/tag/update", canalTagUpdate)
notAuth.POST("canal/name/configs", canalNameConfigs)
notAuth.POST("canal/config/create", canalConfigCreate)
notAuth.POST("caster/envs", casterEnvs)
notAuth.GET("get/apps", getApps)
}
service := b.Group("/service")
{
service.POST("/token/set", setToken)
service.GET("/host/infos", hosts)
service.POST("/delete", clearhost)
}
app := b.Group("/app")
{
app.POST("/token/update", updateToken)
app.POST("/create", create)
app.GET("/apps", appList)
app.GET("/envs", envs)
app.GET("/nodeTree", nodeTree)
app.POST("/zone/copy", zoneCopy)
app.POST("/rename", rename)
app.POST("/status", upAppStatus)
}
bu := b.Group("/build")
{
bu.POST("/create", createBuild)
bu.POST("/tag/update", updateTag)
bu.POST("/tagid/update", updateTagID)
bu.GET("/builds", builds)
bu.GET("/build", build)
bu.POST("/delete", buildDel)
bu.POST("/hosts/force", hostsForce)
bu.POST("/clear/force", clearForce)
}
config := b.Group("/config")
{
config.POST("/create", createConfig)
config.POST("/lint", lintConfig)
config.POST("/value/update", updateConfValue)
config.GET("/app/configs", configsByAppName)
config.GET("/build/configs", configsByBuildID)
config.GET("/tag/configs", configsByTagID)
config.GET("/name/configs", configsByName)
config.GET("/names", namesByAppName)
config.GET("/configs", configs)
config.GET("/all/search", configSearchAll)
config.GET("/app/search", configSearchApp)
config.GET("/refs", configRefs)
config.GET("/value", value)
config.GET("/diff", diff)
config.POST("/delete", configDel)
config.GET("/build/infos", configBuildInfos)
}
common := b.Group("/common")
{
common.POST("/create", createComConfig)
common.POST("/value/update", updateComConfValue)
common.GET("/name/configs", comConfigsByName)
common.GET("/configs", configsByTeam)
common.GET("/names", namesByTeam)
common.GET("/value", comValue)
common.GET("/envs", envsByTeam)
common.GET("/app", appByTeam)
common.GET("/tag/push", tagPush)
}
tags := b.Group("/tag")
{
tags.POST("/create", createTag)
tags.GET("/last/tags", lastTags)
tags.GET("/build/tags", tagsByBuild)
tags.GET("/tag", tag)
tags.GET("/config/diff", tagConfigDiff)
}
apm := b.Group("/apm")
{
apm.GET("/copy", apmCopy)
}
tree := b.Group("/tree")
{
tree.GET("/update", syncTree)
}
}
}
// ping check server ok.
func ping(ctx *bm.Context) {
if err := svr.Ping(); err != nil {
log.Error("service ping error(%v)", err)
ctx.AbortWithStatus(http.StatusServiceUnavailable)
}
}
func user(c *bm.Context) (username string) {
usernameI, _ := c.Get("username")
username, _ = usernameI.(string)
return
}

View File

@ -0,0 +1,222 @@
package http
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"go-common/app/admin/main/config/model"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
func createTag(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.CreateTagReq)
err := c.Bind(v)
if err != nil {
return
}
user := user(c)
if _, err = svr.AuthApp(c, user, c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
tag := &model.Tag{}
tag.Mark = v.Mark
tag.ConfigIDs = v.ConfigIDs
tag.Operator = user
c.JSON(nil, svr.CreateTag(tag, v.TreeID, v.Env, v.Zone))
}
func lastTags(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.LastTagsReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApp(c, user(c), c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.LastTags(v.TreeID, v.Env, v.Zone, v.Build))
}
func tagsByBuild(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.TagsByBuildReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApp(c, user(c), c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.TagsByBuild(v.AppName, v.Env, v.Zone, v.Build, v.Ps, v.Pn, v.TreeID))
}
func tag(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.TagReq)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApps(c, user(c), c.Request.Header.Get("Cookie")); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
c.JSON(svr.Tag(v.TagID))
}
func updateTag(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.UpdatetagReq)
err := c.Bind(v)
if err != nil {
return
}
if v.Force != 1 {
v.Force = 0
}
user := user(c)
if _, err = svr.AuthApp(c, user, c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
if len(strings.TrimSpace(v.Build)) == 0 {
res["message"] = "build不能为空"
c.JSONMap(res, ecode.RequestErr)
return
}
tag := &model.Tag{}
tag.Operator = user
tag.Mark = v.Mark
tag.ConfigIDs = v.ConfigIDs
tag.Force = v.Force
c.JSON(nil, svr.UpdateTag(c, v.TreeID, v.Env, v.Zone, v.Build, tag))
}
func updateTagID(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.UpdateTagIDReq)
err := c.Bind(v)
if err != nil {
return
}
user := user(c)
if _, err = svr.AuthApp(c, user, c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
if len(strings.TrimSpace(v.Build)) == 0 {
res["message"] = "build不能为空"
c.JSONMap(res, ecode.RequestErr)
return
}
tag := &model.Tag{}
if tag, err = svr.RollBackTag(v.TagID); err != nil {
res["message"] = "tag_id有误"
c.JSONMap(res, ecode.RequestErr)
return
}
tag.Operator = user
tag.Mark = fmt.Sprintf("回滚操作原tag_id%d", v.TagID)
c.JSON(nil, svr.UpdateTag(c, v.TreeID, v.Env, v.Zone, v.Build, tag))
}
func hostsForce(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.CreateForceReq)
err := c.Bind(v)
if err != nil {
return
}
user := user(c)
if _, err = svr.AuthApp(c, user, c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
var mHosts model.MapHosts
err = json.Unmarshal([]byte(v.Hosts), &mHosts)
if err != nil {
res["message"] = "解析hosts失败"
c.JSONMap(res, err)
return
}
c.JSON(nil, svr.UpdateForce(c, v.TreeID, v.Version, v.Env, v.Zone, v.Build, user, mHosts))
}
func clearForce(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.ClearForceReq)
err := c.Bind(v)
if err != nil {
return
}
user := user(c)
if _, err = svr.AuthApp(c, user, c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
var mHosts model.MapHosts
err = json.Unmarshal([]byte(v.Hosts), &mHosts)
if err != nil {
res["message"] = "解析hosts失败"
c.JSONMap(res, err)
return
}
c.JSON(nil, svr.ClearForce(c, v.TreeID, v.Env, v.Zone, v.Build, mHosts))
}
func tagConfigDiff(c *bm.Context) {
res := map[string]interface{}{}
v := new(model.TagConfigDiff)
err := c.Bind(v)
if err != nil {
return
}
if _, err = svr.AuthApp(c, user(c), c.Request.Header.Get("Cookie"), v.TreeID); err != nil {
res["message"] = "服务树权限不足"
c.JSONMap(res, err)
return
}
tag, err := svr.LastTasConfigDiff(v.TagID, v.AppID, v.BuildID)
if err != nil {
res["message"] = "版本未找到"
c.JSONMap(res, err)
return
}
var config *model.Config
var configIDS []int64
if len(tag.ConfigIDs) > 0 {
tmpIDs := strings.Split(tag.ConfigIDs, ",")
for _, vv := range tmpIDs {
id, err := strconv.ParseInt(vv, 10, 64)
if err != nil {
log.Error("strconv.ParseInt() error(%v)", err)
return
}
configIDS = append(configIDS, id)
}
config, err = svr.GetConfig(configIDS, v.Name)
if err != nil {
res["message"] = "配置文件未找到"
c.JSONMap(res, err)
return
}
}
c.JSON(config, err)
}

View File

@ -0,0 +1,10 @@
package http
import (
bm "go-common/library/net/http/blademaster"
)
func syncTree(c *bm.Context) {
svr.SyncTree(c, user(c), c.Request.Header.Get("Cookie"))
c.JSON(nil, nil)
}

View File

@ -0,0 +1,38 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"apm.go",
"app.go",
"build.go",
"common.go",
"config.go",
"force.go",
"tag.go",
"team.go",
],
importpath = "go-common/app/admin/main/config/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["//library/time:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,84 @@
package model
import (
xtime "go-common/library/time"
)
// TableName case tablename.
func (*ServiceName) TableName() string {
return "service_name"
}
// ServiceName service name.
type ServiceName struct {
ID int `gorm:"column:id" json:"id"`
Name string `gorm:"column:name" json:"name"`
Remark string `gorm:"column:remark" json:"remark"`
Token string `gorm:"column:token" json:"token"`
ConfigID string `gorm:"column:config_id" json:"config_id"`
ProjectTeamID string `gorm:"column:project_team_id" json:"project_team_id"`
Environment int8 `gorm:"column:environment" json:"environment"`
Public string `gorm:"column:public" json:"public"`
CTime xtime.Time `gorm:"column:ctime" json:"ctime"`
MTime xtime.Time `gorm:"column:mtime" json:"mtime"`
}
// TableName case tablename.
func (*ServiceConfig) TableName() string {
return "service_config"
}
// ServiceConfig service config.
type ServiceConfig struct {
ID int `gorm:"column:id" json:"id"`
ServiceID int `gorm:"column:service_id" json:"service_id"`
Suffix string `gorm:"column:suffix" json:"suffix"`
Config string `gorm:"column:config" json:"config"`
State int8 `gorm:"column:state" json:"state"`
Operator string `gorm:"column:operator" json:"operator"`
Remark string `gorm:"column:remark" json:"remark"`
CTime xtime.Time `gorm:"column:ctime" json:"ctime"`
MTime xtime.Time `gorm:"column:mtime" json:"mtime"`
}
// TableName case tablename.
func (*ServiceConfigValue) TableName() string {
return "service_config_value"
}
// ServiceConfigValue service config value.
type ServiceConfigValue struct {
ID int `gorm:"column:id" json:"id"`
ConfigID int `gorm:"column:config_id" json:"config_id"`
Name string `gorm:"column:name" json:"name"`
Config string `gorm:"column:config" json:"config"`
State int8 `gorm:"column:state" json:"state"`
Operator string `gorm:"column:operator" json:"operator"`
NamespaceID int `gorm:"column:namespace_id" json:"namespace_id"`
CTime xtime.Time `gorm:"column:ctime" json:"ctime"`
MTime xtime.Time `gorm:"column:mtime" json:"mtime"`
}
// TableName case tablename.
func (*BuildVersion) TableName() string {
return "build_version"
}
// BuildVersion build version.
type BuildVersion struct {
ID int `gorm:"column:id" json:"id"`
ServiceID int `gorm:"column:service_id" json:"service_id"`
Version string `gorm:"column:version" json:"version"`
Remark string `gorm:"column:remark" json:"remark"`
State int8 `gorm:"column:state" json:"state"`
ConfigID int `gorm:"column:config_id" json:"config_id"`
CTime xtime.Time `gorm:"column:ctime" json:"ctime"`
MTime xtime.Time `gorm:"column:mtime" json:"mtime"`
}
//ApmCopyReq ...
type ApmCopyReq struct {
Name string `form:"name" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
ApmName string `form:"apmname" validate:"required"`
}

View File

@ -0,0 +1,180 @@
package model
import (
"time"
xtime "go-common/library/time"
)
const (
// Ops ops.
Ops = 3
// Rds rds.
Rds = 2
// DefaultEnv defaultEnv.
DefaultEnv = "dev"
// DefaultZone defaultzone.
DefaultZone = "sh001"
//StatusShow status show
StatusShow = 1
//StatusHidden status hidden
StatusHidden = 2
)
//App app.
type App struct {
ID int64 `json:"id" gorm:"primary_key"`
Name string `json:"name"`
TreeID int64 `json:"tree_id"`
Env string `json:"env"`
Zone string `json:"zone"`
Token string `json:"token"`
Status int8 `json:"status"`
Ctime xtime.Time `json:"ctime"`
Mtime xtime.Time `json:"mtime"`
}
// TableName app
func (App) TableName() string {
return "app"
}
// Node node.
type Node struct {
Name string `json:"name"`
Path string `json:"path"`
TreeID int64 `json:"tree_id"`
}
// TreeNode TreeNode.
type TreeNode struct {
Alias string `json:"alias"`
CreatedAt string `json:"created_at"`
Name string `json:"name"`
Path string `json:"path"`
Tags interface{} `json:"tags"`
Type int `json:"type"`
}
// Res res.
type Res struct {
Count int `json:"count"`
Data []*TreeNode `json:"data"`
Page int `json:"page"`
Results int `json:"results"`
}
// AppPager app pager
type AppPager struct {
Total int64 `json:"total"`
Pn int64 `json:"pn"`
Ps int64 `json:"ps"`
Items []*App `json:"items"`
}
// Resp tree resp
type Resp struct {
Data map[string]*Tree `json:"data"`
}
// Tree node.
type Tree struct {
Name string `json:"name"`
Type int `json:"type"`
Path string `json:"path"`
Tags *TreeTag `json:"tags"`
Children map[string]*Tree `json:"children"`
}
//TreeTag tree tag.
type TreeTag struct {
Ops string `json:"ops"`
Rds string `json:"rds"`
}
//Env env.
type Env struct {
Name string `json:"name"`
NikeName string `json:"nike_name"`
Token string `json:"token"`
}
//RoleNode roleNode .
type RoleNode struct {
ID int64 `json:"id"`
Name string `json:"name"`
Path string `json:"path"`
Type int8 `json:"type"`
Role int8 `json:"role"`
}
//UpdateTokenReq ...
type UpdateTokenReq struct {
AppName string `form:"app_name" validate:"required"`
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
}
//CreateReq ...
type CreateReq struct {
AppName string `form:"app_name" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
}
//AppListReq ...
type AppListReq struct {
AppName string `form:"app_name"`
Bu string `form:"bu"`
Team string `form:"team"`
Pn int64 `form:"pn" default:"1" validate:"min=1"`
Ps int64 `form:"ps" default:"20" validate:"min=1"`
Status int8 `form:"status"`
}
//EnvsByTeamReq ...
type EnvsByTeamReq struct {
AppName string `form:"app_name"`
Zone string `form:"zone"`
Team string `form:"team"`
}
//EnvsReq ...
type EnvsReq struct {
AppName string `form:"app_name" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
Zone string `form:"zone" validate:"required"`
}
//NodeTreeReq ...
type NodeTreeReq struct {
Node string `form:"node"`
Team string `form:"team"`
}
//ZoneCopyReq ...
type ZoneCopyReq struct {
AppName string `form:"app_name" validate:"required"`
From string `form:"from_zone" validate:"required"`
To string `form:"to_zone" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
}
//CasterEnvsReq ...
type CasterEnvsReq struct {
TreeID int64 `form:"tree_id" validate:"required"`
Zone string `form:"zone" validate:"required"`
Auth string `form:"auth" validate:"required"`
}
//CacheData ...
type CacheData struct {
Data map[int64]*RoleNode `json:"data"`
CTime time.Time `json:"ctime"`
}
//AppStatusReq ...
type AppStatusReq struct {
TreeID int64 `form:"tree_id" validate:"required"`
Status int8 `form:"status" default:"1"`
}

View File

@ -0,0 +1,43 @@
package model
import "go-common/library/time"
//Build build.
type Build struct {
ID int64 `json:"id"`
AppID int64 `json:"app_id"`
Name string `json:"name"`
TagID int64 `json:"tag_id"`
Mark string `json:"mark"`
Operator string `json:"operator"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// TableName build.
func (Build) TableName() string {
return "build"
}
//CreateBuildReq ...
type CreateBuildReq struct {
AppName string `form:"app_name" validate:"required"`
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
Name string `form:"name" validate:"required"`
TagID int64 `form:"tag_id" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
}
//BuildsReq ...
type BuildsReq struct {
AppName string `form:"app_name" validate:"required"`
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
}
//BuildReq ...
type BuildReq struct {
BuildID int64 `form:"build_id" validate:"required"`
}

View File

@ -0,0 +1,106 @@
package model
import "go-common/library/time"
// CommonConf commonConf.
type CommonConf struct {
ID int64 `json:"id" gorm:"primary_key"`
TeamID int64 `json:"team_id"`
Name string `json:"name"`
Comment string `json:"comment"`
State int8 `json:"state"`
Mark string `json:"mark"`
Operator string `json:"operator"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// TableName commonConfig.
func (CommonConf) TableName() string {
return "common_config"
}
// CommonConfPager app pager
type CommonConfPager struct {
Total int64 `json:"total"`
Pn int64 `json:"pn"`
Ps int64 `json:"ps"`
Items []*CommonConf `json:"items"`
}
// CommonName app pager
type CommonName struct {
Name string `json:"name"`
ID int64 `json:"id"`
}
// CommonTemp app temp
type CommonTemp struct {
ID int64 `json:"id"`
}
// CommonCounts app counts
type CommonCounts struct {
Counts int64 `json:"counts"`
}
//CreateComConfigReq ...
type CreateComConfigReq struct {
Team string `form:"team" validate:"required"`
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
Name string `form:"name" validate:"required"`
State int8 `form:"state" validate:"required"`
Comment string `form:"comment" validate:"required"`
Mark string `form:"mark" validate:"required"`
SkipLint bool `form:"skiplint"`
}
//ComValueReq ...
type ComValueReq struct {
ConfigID int64 `form:"config_id" validate:"required"`
}
//ConfigsByTeamReq ...
type ConfigsByTeamReq struct {
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
Team string `form:"team" validate:"required"`
Pn int64 `form:"pn" default:"1" validate:"min=1"`
Ps int64 `form:"ps" default:"20" validate:"min=1"`
}
//ComConfigsByNameReq ...
type ComConfigsByNameReq struct {
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
Team string `form:"team" validate:"required"`
Name string `form:"name" validate:"required"`
}
//UpdateComConfValueReq ...
type UpdateComConfValueReq struct {
ID int64 `form:"config_id" validate:"required"`
State int8 `form:"state" validate:"required"`
ConfigID int64 `form:"config_id" validate:"required"`
Name string `form:"name" validate:"required"`
Comment string `form:"comment" validate:"required"`
Mark string `form:"mark" validate:"required"`
Mtime int64 `form:"mtime" validate:"required"`
SkipLint bool `form:"skiplint"`
}
//NamesByTeamReq ...
type NamesByTeamReq struct {
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
Team string `form:"team" validate:"required"`
}
// TagMap ...
type TagMap struct {
*Tag
AppName string `json:"app_name"`
BuildName string `json:"build_name"`
TreeID int64 `json:"tree_id"`
}

View File

@ -0,0 +1,275 @@
package model
import "go-common/library/time"
var (
//ConfigIng config ing.
ConfigIng = int8(1)
//ConfigEnd config end.
ConfigEnd = int8(2)
)
// Config config.
type Config struct {
ID int64 `json:"id" gorm:"primary_key"`
AppID int64 `json:"app_id"`
Name string `json:"name"`
Comment string `json:"comment"`
From int64 `json:"from"`
State int8 `json:"state"`
Mark string `json:"mark"`
Operator string `json:"operator"`
IsDelete int8 `json:"is_delete"`
NewCommon int64 `gorm:"-" json:"new_common"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// TableName config.
func (Config) TableName() string {
return "config"
}
//BuildFile file.
type BuildFile struct {
*Config
LastConf *Config `json:"last_conf"`
}
//ConfigRes configRes.
type ConfigRes struct {
Files []*Config `json:"files"`
BuildFiles []*BuildFile `json:"build_files"`
BuildNewFile []*Config `json:"build_new_file"`
}
//ConfigRefs ConfigRefs.
type ConfigRefs struct {
Configs []*ConfigRef `json:"configs"`
Ref *ConfigRef `json:"ref"`
Name string `json:"name"`
DeleteMAX int64 `json:"delete_max"`
}
//ConfigRef configRef.
type ConfigRef struct {
ID int64 `json:"id"`
Mark string `json:"mark"`
IsDelete int8 `json:"is_delete"`
}
//ConfigSearch config search resp.
type ConfigSearch struct {
App string `json:"app"`
TreeID int64 `json:"tree_id"`
Builds []string `json:"build"`
ConfID int64 `json:"config_id"`
Mark string `json:"mark"`
ConfName string `json:"conf_name"`
ConfValues []string `json:"conf_value"`
}
//CanalTagUpdateReq ...
type CanalTagUpdateReq struct {
AppName string `form:"app_name" validate:"required"`
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
ConfigIDs string `form:"config_ids"`
TreeID int64 `form:"tree_id" validate:"required"`
Token string `form:"token" validate:"required"`
User string `form:"user" validate:"required"`
Mark string `form:"mark" default:"canal发版"`
Build string `form:"build" default:"docker-1"`
Force int8 `form:"force"`
}
//CanalNameConfigsReq ...
type CanalNameConfigsReq struct {
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
AppName string `form:"app_name" validate:"required"`
Name string `form:"name" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
Token string `form:"token" validate:"required"`
}
//CanalConfigCreateReq ...
type CanalConfigCreateReq struct {
AppName string `form:"app_name" validate:"required"`
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
Name string `form:"name" validate:"required"`
State int8 `form:"state" validate:"required"`
From int64 `form:"from" default:"0"`
Comment string `form:"comment" validate:"required"`
Mark string `form:"mark" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
User string `form:"user" validate:"required"`
Token string `form:"token" valildate:"required"`
}
//CreateConfigReq ...
type CreateConfigReq struct {
AppName string `form:"app_name" validate:"required"`
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
Name string `form:"name" validate:"required"`
State int8 `form:"state" validate:"required"`
From int64 `form:"from" default:"0"`
Comment string `form:"comment" validate:"required"`
Mark string `form:"mark" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
SkipLint bool `form:"skiplint"`
}
//UpdateConfValueReq ...
type UpdateConfValueReq struct {
Name string `form:"name"`
ID int64 `form:"config_id" validate:"required"`
Mtime int64 `form:"mtime" validate:"required"`
State int8 `form:"state" validate:"required"`
Comment string `form:"comment" validate:"required"`
Mark string `form:"mark" validate:"required"`
NewCommon int64 `form:"new_common"`
Ignore int8 `form:"ignore"`
SkipLint bool `form:"skiplint"`
}
//ValueReq ...
type ValueReq struct {
ConfigID int64 `form:"config_id" validate:"required"`
}
//ConfigsByBuildIDReq ...
type ConfigsByBuildIDReq struct {
BuildID int64 `form:"build_id" validate:"required"`
}
//ConfigsByTagIDReq ...
type ConfigsByTagIDReq struct {
TagID int64 `form:"tag_id" validate:"required"`
}
//ConfigsByAppNameReq ...
type ConfigsByAppNameReq struct {
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
AppName string `form:"app_name" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
}
//ConfigSearchAllReq ...
type ConfigSearchAllReq struct {
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
Like string `form:"like" validate:"required"`
}
//ConfigSearchAppReq ...
type ConfigSearchAppReq struct {
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
AppName string `form:"app_name" validate:"required"`
Like string `form:"like" validate:"required"`
BuildID int64 `form:"build_id" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
}
//ConfigsByNameReq ...
type ConfigsByNameReq struct {
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
AppName string `form:"app_name" validate:"required"`
Name string `form:"name" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
}
//ConfigsReq ...
type ConfigsReq struct {
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
AppName string `form:"app_name" validate:"required"`
BuildID int64 `form:"build_id"`
TreeID int64 `form:"tree_id" validate:"required"`
}
//ConfigRefsReq ...
type ConfigRefsReq struct {
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
AppName string `form:"app_name" validate:"required"`
BuildID int64 `form:"build_id" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
}
//NamesByAppNameReq ...
type NamesByAppNameReq struct {
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
AppName string `form:"app_name" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
}
//DiffReq ...
type DiffReq struct {
ConfigID int64 `form:"config_id" validate:"required"`
BuildID int64 `form:"build_id"`
}
//ConfigDelReq ...
type ConfigDelReq struct {
ConfigID int64 `form:"config_id" validate:"required"`
}
//ConfigBuildInfosReq ...
type ConfigBuildInfosReq struct {
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
AppName string `form:"app_name" validate:"required"`
BuildID int64 `form:"build_id"`
TreeID int64 `form:"tree_id" validate:"required"`
}
//ConfigUpdateReq ...
type ConfigUpdateReq struct {
AppName string `form:"app_name" validate:"required"`
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
Data string `form:"data" validate:"required"`
Token string `form:"token" validate:"required"`
User string `form:"user" validate:"required"`
}
//TagUpdateReq ...
type TagUpdateReq struct {
AppName string `form:"app_name" validate:"required"`
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
ConfigIDs string `form:"config_ids"`
Mark string `form:"mark" validate:"required"`
Build string `form:"build" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
Token string `form:"token" validate:"required"`
User string `form:"user" validate:"required"`
Names string `form:"names"`
Increment int `form:"increment"`
Force int8 `form:"force"`
}
//SetTokenReq ...
type SetTokenReq struct {
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
App string `form:"service" validate:"required"`
Token string `form:"token" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
}
//HostsReq ...
type HostsReq struct {
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
App string `form:"service" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
}

View File

@ -0,0 +1,42 @@
package model
import "go-common/library/time"
//Force ...
type Force struct {
ID int64 `json:"id"`
AppID int64 `json:"app_id"`
Hostname string `json:"hostname"`
IP string `json:"ip"`
Version int64 `json:"version"`
Operator string `json:"operator"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// TableName force.
func (Force) TableName() string {
return "force"
}
//CreateForceReq ...
type CreateForceReq struct {
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
Build string `form:"build" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
Version int64 `form:"version"`
Hosts string `form:"hosts"`
}
//ClearForceReq ...
type ClearForceReq struct {
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
Build string `form:"build" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
Hosts string `form:"hosts"`
}
//MapHosts ...
type MapHosts map[string]string

View File

@ -0,0 +1,109 @@
package model
import "go-common/library/time"
//Tag db table tag.
type Tag struct {
ID int64 `json:"id" gorm:"primary_key"`
AppID int64 `json:"app_id"`
BuildID int64 `json:"build_id"`
ConfigIDs string `json:"config_ids"`
Mark string `json:"mark"`
Operator string `json:"operator"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
Force int8 `json:"force"`
}
// TableName tag.
func (Tag) TableName() string {
return "tag"
}
// TagPager tag pager
type TagPager struct {
Total int64 `json:"total"`
Pn int64 `json:"pn"`
Ps int64 `json:"ps"`
Items []*Tag `json:"items"`
}
//TagConfig tagConfig.
type TagConfig struct {
*Tag
Confs []*Config `json:"confs"`
}
// TagConfigPager tag configs pager.
type TagConfigPager struct {
Total int64 `json:"total"`
Pn int64 `json:"pn"`
Ps int64 `json:"ps"`
Items []*TagConfig `json:"items"`
}
//CreateTagReq ...
type CreateTagReq struct {
AppName string `form:"app_name" validate:"required"`
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
ConfigIDs string `form:"config_ids" validate:"required"`
Mark string `form:"mark" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
}
//LastTagsReq ...
type LastTagsReq struct {
AppName string `form:"app_name" validate:"required"`
Zone string `form:"zone" validate:"required"`
Env string `form:"env" validate:"required"`
Build string `form:"build" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
}
//TagsByBuildReq ...
type TagsByBuildReq struct {
AppName string `form:"app_name" validate:"required"`
Zone string `form:"zone" validate:"required"`
Env string `form:"env" validate:"required"`
Build string `form:"build" validate:"required"`
Pn int64 `form:"pn" default:"1" validate:"min=1"`
Ps int64 `form:"ps" default:"20" validate:"min=1"`
TreeID int64 `form:"tree_id" validate:"required"`
}
//TagReq ...
type TagReq struct {
TagID int64 `form:"tag_id" validate:"required"`
}
//UpdatetagReq ...
type UpdatetagReq struct {
AppName string `form:"app_name" validate:"required"`
Env string `form:"env" validate:"required"`
Zone string `form:"zone" validate:"required"`
ConfigIDs string `form:"config_ids" validate:"required"`
Mark string `form:"mark" validate:"required"`
Build string `form:"build" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
Force int8 `form:"force"`
}
//UpdateTagIDReq ...
type UpdateTagIDReq struct {
AppName string `form:"app_name" validate:"required"`
Zone string `form:"zone" validate:"required"`
Env string `form:"env" validate:"required"`
Build string `form:"build" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
TagID int64 `form:"tag_id" validate:"required"`
}
//TagConfigDiff ...
type TagConfigDiff struct {
TagID int64 `form:"tag_id" validate:"required"`
Name string `form:"name" validate:"required"`
TreeID int64 `form:"tree_id" validate:"required"`
AppID int64 `form:"app_id" validate:"required"`
BuildID int64 `form:"build_id" validate:"required"`
}

View File

@ -0,0 +1,18 @@
package model
import "go-common/library/time"
//Team team.
type Team struct {
ID int64 `json:"id" gorm:"primary_key"`
Name string `json:"name"`
Env string `json:"env"`
Zone string `json:"zone"`
Ctime time.Time `json:"ctime"`
Mtime time.Time `json:"mtime"`
}
// TableName team.
func (Team) TableName() string {
return "project_team"
}

View File

@ -0,0 +1,44 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = ["lint.go"],
importpath = "go-common/app/admin/main/config/pkg/lint",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_xtest",
srcs = ["lint_test.go"],
tags = ["automanaged"],
deps = [
"//app/admin/main/config/pkg/lint:go_default_library",
"//app/admin/main/config/pkg/lint/json:go_default_library",
"//app/admin/main/config/pkg/lint/toml:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/admin/main/config/pkg/lint/json:all-srcs",
"//app/admin/main/config/pkg/lint/toml:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,37 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["jsonlint_test.go"],
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["jsonlint.go"],
importpath = "go-common/app/admin/main/config/pkg/lint/json",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["//app/admin/main/config/pkg/lint:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,26 @@
package jsonlint
import (
"encoding/json"
"io"
"go-common/app/admin/main/config/pkg/lint"
)
const filetype = "json"
type jsonlint struct{}
func (jsonlint) Lint(r io.Reader) lint.Error {
var v interface{}
dec := json.NewDecoder(r)
err := dec.Decode(&v)
if err == nil {
return nil
}
return lint.Error{{Line: -1, Message: err.Error()}}
}
func init() {
lint.RegisterLinter(filetype, jsonlint{})
}

View File

@ -0,0 +1,38 @@
package jsonlint
import (
"bytes"
"testing"
)
var testdata = `
{
"a1": "a1",
"b2":
}
`
var testdataok = `
{
"hello": "world"
}
`
func TestJsonLint(t *testing.T) {
lint := jsonlint{}
r := bytes.NewBufferString(testdata)
lintErr := lint.Lint(r)
if lintErr == nil {
t.Fatalf("expect lintErr != nil")
}
t.Logf("%s", lintErr.Error())
}
func TestJsonLintOk(t *testing.T) {
lint := jsonlint{}
r := bytes.NewBufferString(testdataok)
lintErr := lint.Lint(r)
if lintErr != nil {
t.Error(lintErr)
}
}

View File

@ -0,0 +1,63 @@
package lint
import (
"errors"
"fmt"
"io"
"strings"
)
var linterMap map[string]Linter
// ErrLintNotExists .
var ErrLintNotExists = errors.New("linter not exists")
func init() {
linterMap = make(map[string]Linter)
}
// RegisterLinter register linter for a kind of file
func RegisterLinter(filetype string, linter Linter) {
if _, ok := linterMap[filetype]; ok {
panic("linter for filetype " + filetype + " already exists")
}
linterMap[filetype] = linter
}
// LineErr error contains line number
type LineErr struct {
Line int `json:"line"`
Message string `json:"message"`
}
// Error lint error
type Error []LineErr
func (errs Error) Error() string {
messages := make([]string, 0, len(errs))
for _, err := range errs {
messages = append(messages, fmt.Sprintf("%d:%s", err.Line, err.Message))
}
return strings.Join(messages, "\n")
}
func (errs Error) String() string {
return errs.Error()
}
// Linter lint config file
type Linter interface {
Lint(r io.Reader) Error
}
// Lint config file,
func Lint(filetype string, r io.Reader) error {
lint, ok := linterMap[filetype]
if !ok {
return ErrLintNotExists
}
if lintErr := lint.Lint(r); lintErr != nil {
return lintErr
}
return nil
}

View File

@ -0,0 +1,35 @@
package lint_test
import (
"bytes"
"testing"
"go-common/app/admin/main/config/pkg/lint"
_ "go-common/app/admin/main/config/pkg/lint/json"
_ "go-common/app/admin/main/config/pkg/lint/toml"
)
func TestLint(t *testing.T) {
jsonRead := bytes.NewBufferString(`{"hello": "world", "a1":"ab"}`)
err := lint.Lint("json", jsonRead)
if err != nil {
t.Errorf("%v", err)
}
tomlRead := bytes.NewBufferString(`[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00 # First class dates
[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true`)
err = lint.Lint("toml", tomlRead)
if err != nil {
t.Errorf("%v", err)
}
err = lint.Lint("test", tomlRead)
if err != lint.ErrLintNotExists {
t.Errorf("%v", err)
}
}

View File

@ -0,0 +1,43 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"testdata_test.go",
"tomllint_test.go",
],
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["tomllint.go"],
importpath = "go-common/app/admin/main/config/pkg/lint/toml",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/config/pkg/lint:go_default_library",
"//vendor/github.com/BurntSushi/toml:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,62 @@
package tomllint
var synataxerrordata = `
[owner]
name = "Tom Preston-Werner"
dob 1979-05-27T07:32:00-08:00 # First class dates
`
var normaldata = `
[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00 # First class dates
[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true
[servers]
# Indentation (tabs and/or spaces) is allowed but not required
[servers.alpha]
ip = "10.0.0.1"
dc = "eqdc10"
[servers.beta]
ip = "10.0.0.2"
dc = "eqdc10"
[clients]
data = [ ["gamma", "delta"], [1, 2] ]
# Line breaks are OK when inside arrays
hosts = [
"alpha",
"omega"
]
`
var notopkvdata = `
title = "test123"
age = 123
array = [1,2,3]
[clients]
data = "helo"
`
var nocommondata = `
version = "v1.1"
user = "nobody"
`
var noidentify = `
[identify]
xxx = 123
`
var noapp = `
[app]
xxx = 123
`

View File

@ -0,0 +1,100 @@
package tomllint
import (
"io"
"regexp"
"strconv"
"github.com/BurntSushi/toml"
"go-common/app/admin/main/config/pkg/lint"
)
var lineNumberRe *regexp.Regexp
const filetype = "toml"
type lintFn func(metadata toml.MetaData) []lint.LineErr
var lintFns []lintFn
type tomllint struct{}
// Lint toml file return lint.Error
func (tomllint) Lint(r io.Reader) lint.Error {
var v interface{}
var lintErr lint.Error
metadata, err := toml.DecodeReader(r, &v)
if err != nil {
line := -1
if match := lineNumberRe.FindStringSubmatch(err.Error()); len(match) == 2 {
line, _ = strconv.Atoi(match[1])
}
lintErr = append(lintErr, lint.LineErr{Line: line, Message: err.Error()})
return lintErr
}
for _, fn := range lintFns {
if lineErrs := fn(metadata); lineErrs != nil {
lintErr = append(lintErr, lineErrs...)
}
}
if len(lintErr) == 0 {
return nil
}
return lintErr
}
// not allowed defined kv that type is not Hash at top level
//func noTopKV(metadata toml.MetaData) []lint.LineErr {
// var lineErrs []lint.LineErr
// for _, keys := range metadata.Keys() {
// if len(keys) != 1 {
// continue
// }
// typeName := metadata.Type(keys...)
// if typeName != "Hash" {
// lineErrs = append(lineErrs, lint.LineErr{
// Line: -1,
// Message: fmt.Sprintf("top level value must be Object, key: %s type is %s", keys[0], typeName),
// })
// }
// }
// return lineErrs
//}
// noApp not allowed app section exists
func noApp(metadata toml.MetaData) []lint.LineErr {
if metadata.IsDefined("app") {
return []lint.LineErr{{Line: -1, Message: "请删除无用 App 配置 see: http://git.bilibili.co/platform/go-common/issues/310 (゜-゜)つロ"}}
}
return nil
}
// noIdentify not allowed identify config
func noIdentify(metadata toml.MetaData) []lint.LineErr {
if metadata.IsDefined("identify") {
return []lint.LineErr{{Line: -1, Message: "请删除无用 Identify 配置 see: http://git.bilibili.co/platform/go-common/issues/310 (゜-゜)つロ"}}
}
return nil
}
// noCommon not allowed common config
func noCommon(metadata toml.MetaData) []lint.LineErr {
count := 0
commonKey := []string{"version", "user", "pid", "dir", "perf"}
for _, key := range commonKey {
if metadata.IsDefined(key) {
count++
}
}
if count > 0 {
return []lint.LineErr{{Line: -1, Message: "请删除无用 Common 配置 see: http://git.bilibili.co/platform/go-common/issues/310 (゜-゜)つロ"}}
}
return nil
}
func init() {
lint.RegisterLinter(filetype, tomllint{})
lintFns = []lintFn{noApp, noIdentify, noCommon}
lineNumberRe = regexp.MustCompile("^Near line (\\d+)")
}

View File

@ -0,0 +1,67 @@
package tomllint
import (
"bytes"
"strings"
"testing"
)
func TestSyntaxError(t *testing.T) {
lint := &tomllint{}
r := bytes.NewBufferString(synataxerrordata)
lintErr := lint.Lint(r)
if lintErr == nil {
t.Fatalf("expect lintErr != nil")
}
if lintErr[0].Line == -1 {
t.Errorf("expect get line number")
}
}
func TestTomlLintOK(t *testing.T) {
lint := &tomllint{}
r := bytes.NewBufferString(normaldata)
lintErr := lint.Lint(r)
if lintErr != nil {
t.Errorf("error %v", lintErr)
}
}
func TestNoCommon(t *testing.T) {
lint := &tomllint{}
r := bytes.NewBufferString(nocommondata)
lintErr := lint.Lint(r)
if lintErr == nil {
t.Fatalf("expect lintErr != nil")
}
message := lintErr.Error()
if !strings.Contains(message, "Common") {
t.Errorf("expect error contains common")
}
}
func TestNoIdentify(t *testing.T) {
lint := &tomllint{}
r := bytes.NewBufferString(noidentify)
lintErr := lint.Lint(r)
if lintErr == nil {
t.Fatalf("expect lintErr != nil")
}
message := lintErr.Error()
if !strings.Contains(message, "Identify") {
t.Errorf("expect error Identify common")
}
}
func TestNoApp(t *testing.T) {
lint := &tomllint{}
r := bytes.NewBufferString(noapp)
lintErr := lint.Lint(r)
if lintErr == nil {
t.Fatalf("expect lintErr != nil")
}
message := lintErr.Error()
if !strings.Contains(message, "App") {
t.Errorf("expect error App common")
}
}

View File

@ -0,0 +1,74 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"app_test.go",
"build_test.go",
"common_test.go",
"conf_svr_test.go",
"config_test.go",
"tag_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/admin/main/config/conf:go_default_library",
"//app/admin/main/config/model:go_default_library",
"//vendor/github.com/BurntSushi/toml:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"apm.go",
"app.go",
"build.go",
"common.go",
"conf_svr.go",
"config.go",
"force.go",
"service.go",
"tag.go",
"team.go",
],
importpath = "go-common/app/admin/main/config/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/config/conf:go_default_library",
"//app/admin/main/config/dao:go_default_library",
"//app/admin/main/config/model:go_default_library",
"//app/admin/main/config/pkg/lint:go_default_library",
"//app/infra/config/model:go_default_library",
"//app/infra/config/rpc/client:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//vendor/github.com/jinzhu/gorm:go_default_library",
"//vendor/github.com/satori/go.uuid:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,159 @@
package service
import (
"fmt"
"strings"
"time"
"go-common/app/admin/main/config/model"
"go-common/library/ecode"
"go-common/library/log"
"github.com/jinzhu/gorm"
)
//Apm apm.
func (s *Service) Apm(treeID int64, name, apmname, username string) (err error) {
sns := []*model.ServiceName{}
if err = s.DBApm.Where("name=?", apmname).Find(&sns).Error; err != nil {
log.Error("svr.service.Apm name(%d) apmname(%d) error(%v)", name, apmname, err)
return
}
for _, val := range sns {
if err = s.ApmBuild(val, name, username, treeID); err != nil {
log.Error("svr.service.ApmBuild val(%d) apmname(%d) error(%v)", val, apmname, err)
}
}
return
}
//ApmBuild apmBuild.
func (s *Service) ApmBuild(val *model.ServiceName, name, username string, treeID int64) (err error) {
bvs := []*model.BuildVersion{}
mtime := time.Now().Unix() - (3600 * 24 * 60)
if err = s.DBApm.Where("service_id=? and mtime > ?", val.ID, mtime).Find(&bvs).Error; err != nil {
log.Error("svr.service.ApmBuild val(%v) id(%d) error(%v)", val, val.ID, err)
return
}
if len(bvs) <= 0 {
err = ecode.NothingFound
return
}
for _, v := range bvs {
var ver string
scvs := []*model.ServiceConfigValue{}
if err = s.DBApm.Where("config_id=?", v.ConfigID).Find(&scvs).Error; err != nil {
log.Error("svr.service.ServiceConfigValue val(%d) ConfigID(%d) error(%v)", val, v.ConfigID, err)
return
}
if len(scvs) <= 0 {
err = ecode.NothingFound
return
}
var env string
switch val.Environment {
case 10:
env = "dev"
case 11:
env = "fat1"
case 13:
env = "uat"
case 14:
env = "pre"
case 3:
env = "prod"
default:
continue
}
version := strings.Split(v.Version, "-")
if len(version) != 3 {
continue
}
ver = version[1] + "-" + version[2]
zone := version[0]
switch zone {
case "shylf":
zone = "sh001"
case "hzxs":
zone = "sh001"
case "shsb":
zone = "sh001"
default:
continue
}
app := &model.App{
Name: name,
TreeID: treeID,
Env: env,
Zone: zone,
Token: val.Token,
}
var tx *gorm.DB
if tx = s.DB.Begin(); err != nil {
log.Error("begin tran error(%v)", err)
return
}
if err = tx.Where("tree_id=? and env=? and zone=?", treeID, env, zone).Find(&app).Error; err != nil {
if err = tx.Create(&app).Error; err != nil {
log.Error("svr.service.addapp create error(%v)", err)
tx.Rollback()
return
}
}
configIds := ""
for _, vv := range scvs {
config := &model.Config{
AppID: app.ID,
Name: vv.Name,
Comment: vv.Config,
From: 0,
State: 2,
Mark: "一键迁移",
Operator: username,
}
if err = tx.Create(&config).Error; err != nil {
log.Error("svr.service.addconfig create error(%v)", err)
tx.Rollback()
return
}
if len(configIds) > 0 {
configIds += ","
}
configIds += fmt.Sprint(config.ID)
}
tag := &model.Tag{
AppID: app.ID,
BuildID: 0,
ConfigIDs: configIds,
Mark: v.Remark,
Operator: username,
}
if err = tx.Create(&tag).Error; err != nil {
log.Error("svr.service.addtag create error(%v)", err)
tx.Rollback()
return
}
buildNew := &model.Build{
AppID: app.ID,
Name: ver,
TagID: tag.ID,
Mark: v.Remark,
Operator: username,
}
if err = tx.Create(&buildNew).Error; err != nil {
log.Error("svr.service.addbuild create error(%v)", err)
tx.Rollback()
return
}
ups := map[string]interface{}{
"build_id": buildNew.ID,
}
if err = tx.Model(tag).Where("id = ?", tag.ID).Updates(ups).Error; err != nil {
log.Error("svr.service.edittag updates error(%v)", err)
tx.Rollback()
return
}
tx.Commit()
}
return
}

View File

@ -0,0 +1,533 @@
package service
import (
"bytes"
"context"
"crypto/md5"
"encoding/hex"
"encoding/json"
"strconv"
"strings"
"time"
"go-common/app/admin/main/config/model"
"go-common/library/database/sql"
"go-common/library/ecode"
"go-common/library/log"
"github.com/jinzhu/gorm"
"github.com/satori/go.uuid"
)
var (
rdsEnvs = []*model.Env{
{Name: "dev", NikeName: "开发环境"},
{Name: "fat1", NikeName: "功能环境1"},
{Name: "uat", NikeName: "集成环境"},
{Name: "pre", NikeName: "预发环境"},
{Name: "prod", NikeName: "线上环境"},
}
opsEnvs = []*model.Env{
{Name: "dev", NikeName: "开发环境"},
{Name: "fat1", NikeName: "功能环境1"},
{Name: "uat", NikeName: "集成环境"},
}
)
// CreateApp create App.
func (s *Service) CreateApp(name, env, zone string, treeID int64) error {
bytes := [16]byte(uuid.NewV1())
token := md5.Sum([]byte(hex.EncodeToString(bytes[:])))
app := &model.App{Name: name, Env: env, Zone: zone, Token: hex.EncodeToString(token[:]), TreeID: treeID, Status: model.StatusShow}
return s.dao.DB.Create(app).Error
}
// UpdateToken update token.
func (s *Service) UpdateToken(c context.Context, env, zone string, treeID int64) (err error) {
bytes := [16]byte(uuid.NewV1())
token := hex.EncodeToString(bytes[:])
if err = s.dao.DB.Model(&model.App{}).Where("tree_id =? AND env=? AND zone=?", treeID, env, zone).Update("token", token).Error; err != nil {
return
}
err = s.SetToken(c, treeID, env, zone, token)
return
}
// AppByTree get token by Name.
func (s *Service) AppByTree(treeID int64, env, zone string) (app *model.App, err error) {
app = &model.App{}
row := s.dao.DB.Select("id,token").Where("tree_id=? AND env=? AND zone=?", treeID, env, zone).Model(&model.App{}).Row()
if err = row.Scan(&app.ID, &app.Token); err != nil {
log.Error("AppByTree(%v) err(%v)", treeID, err)
if err == sql.ErrNoRows {
err = ecode.NothingFound
}
}
return
}
// AppsByTreeZone get token by Name and zone.
func (s *Service) AppsByTreeZone(treeID int64, zone string) (apps []*model.App, err error) {
if err = s.dao.DB.Select("id,env,token").Where("tree_id=? AND zone=?", treeID, zone).Find(&apps).Error; err != nil {
log.Error("AppsByTreezone(%d) error(%v)", treeID, err)
if err == sql.ErrNoRows {
err = ecode.NothingFound
}
}
return
}
// AppList get token by Name.
func (s *Service) AppList(ctx context.Context, bu, team, name, env, zone string, ps, pn int64, nodes *model.CacheData, status int8) (pager *model.AppPager, err error) {
var (
like string
apps []*model.App
total int64
ids []int64
statusIn []int8
)
like = "%"
if len(bu) != 0 {
like = bu + ".%"
}
if len(team) != 0 {
like = team + ".%"
}
if len(name) != 0 {
like = "%.%.%" + name + "%"
}
if len(name) != 0 && len(team) != 0 {
like = team + ".%" + name + "%"
} else if len(name) != 0 && len(bu) != 0 {
like = bu + ".%.%" + name + "%"
}
if status > 0 {
statusIn = append(statusIn, status)
} else {
statusIn = []int8{model.StatusShow, model.StatusHidden}
}
for _, node := range nodes.Data {
ids = append(ids, node.ID)
}
if err = s.dao.DB.Where("env=? AND zone=? AND name like ? AND tree_id in (?) And status in (?)", env, zone, like, ids, statusIn).
Offset((pn - 1) * ps).Limit(ps).Find(&apps).Error; err != nil {
log.Error("AppList() find page apps() error(%v)", err)
return
}
if err = s.dao.DB.Model(&model.App{}).Where("env=? AND zone=? AND name like ? AND tree_id in (?) And status in (?)", env, zone, like, ids, statusIn).
Count(&total).Error; err != nil {
log.Error("AppList() count page apps() error(%v)", err)
return
}
pager = &model.AppPager{Total: total, Pn: pn, Ps: ps, Items: apps}
return
}
// Tree get service tree.
func (s *Service) Tree(ctx context.Context, user string) (data interface{}, err error) {
var (
parme []byte
msg map[string]interface{}
tmp interface{}
token string
ok bool
)
if parme, err = json.Marshal(map[string]string{"user_name": user, "platform_id": s.c.Tree.Platform}); err != nil {
log.Error("json.Marshal() error(%v)", err)
return
}
if msg, err = s.dao.Token(ctx, string(parme)); err != nil {
return
}
if tmp, ok = msg["token"]; !ok {
err = ecode.NothingFound
return
}
if token, ok = tmp.(string); !ok {
err = ecode.NothingFound
return
}
return s.dao.Tree(ctx, token)
}
// Node node.
func (s *Service) Node(ctx context.Context, user, node, team, cookie string, nodes *model.CacheData) (res []*model.Node, err error) {
var nNodes *model.CacheData
//bu list.
if node == "" && team == "" {
if nNodes, err = s.SyncTree(ctx, user, cookie); err == nil {
nodes = nNodes
}
tmp := make(map[string]struct{})
for _, app := range nodes.Data {
idx := strings.Index(app.Path, ".")
bu := string([]byte(app.Path)[:idx])
if _, ok := tmp[bu]; ok {
continue
}
n := new(model.Node)
n.Name = bu
n.Path = bu
res = append(res, n)
tmp[bu] = struct{}{}
}
return
}
//team list.
if node != "" && team == "" {
tmp := make(map[string]struct{})
for _, app := range nodes.Data {
s := []byte(app.Path)
sep := []byte(".")
fidx := bytes.Index(s, sep)
lidx := bytes.LastIndex(s, sep)
team = string(s[:lidx])
if node == string(s[:fidx]) {
if _, ok := tmp[team]; ok {
continue
}
n := new(model.Node)
n.Name = string([]byte(app.Path)[fidx+1 : lidx])
n.Path = team
tmp[team] = struct{}{}
res = append(res, n)
}
}
return
}
//app list.
if team == "" {
return
}
for _, app := range nodes.Data {
s := []byte(app.Path)
sep := []byte(".")
lidx := bytes.LastIndex(s, sep)
t := string(s[:lidx])
if team != t {
continue
}
n := new(model.Node)
n.Name = string(s[lidx+1:])
n.Path = app.Path
n.TreeID = app.ID
res = append(res, n)
}
return
}
//Envs envs.
func (s *Service) Envs(ctx context.Context, user, appName, zone string, treeID int64, nodes *model.CacheData) (envs []*model.Env, err error) {
var (
ok bool
node *model.RoleNode
apps []*model.App
)
envs = rdsEnvs
if node, ok = nodes.Data[treeID]; !ok {
return
}
if node.Role == model.Ops {
envs = opsEnvs
}
apps, err = s.AppsByTreeZone(treeID, zone)
for _, env := range envs {
env.Token = ""
for _, app := range apps {
if app.Env == env.Name {
env.Token = app.Token
break
}
}
}
return
}
//EnvsByTeam envs.
func (s *Service) EnvsByTeam(ctx context.Context, appName, zone string, nodes *model.CacheData) (envs []*model.Env, err error) {
envs = rdsEnvs
return
}
//SyncTree syncTree.
func (s *Service) SyncTree(ctx context.Context, user string, cookie string) (nodes *model.CacheData, err error) {
var (
msg map[string]interface{}
tmp interface{}
token string
ok bool
)
if msg, err = s.dao.Auth(ctx, cookie); err != nil {
return
}
if tmp, ok = msg["token"]; !ok {
err = ecode.NothingFound
return
}
if token, ok = tmp.(string); !ok {
err = ecode.NothingFound
return
}
if nodes, err = s.dao.Role(ctx, user, token); err != nil {
return
}
s.cLock.Lock()
s.cache[user] = nodes
s.cLock.Unlock()
return
}
//AuthApps authApps.
func (s *Service) AuthApps(ctx context.Context, user, cookie string) (nodes *model.CacheData, err error) {
if len(user) == 0 {
err = ecode.NothingFound
return
}
var ok bool
s.cLock.RLock()
nodes, ok = s.cache[user]
s.cLock.RUnlock()
if !ok || (time.Since(nodes.CTime) > 60*time.Second) {
s.SyncTree(ctx, user, cookie)
s.cLock.RLock()
nodes, ok = s.cache[user]
s.cLock.RUnlock()
if !ok {
err = ecode.NothingFound
}
}
return
}
//AuthApp authApp.
func (s *Service) AuthApp(ctx context.Context, user, cookie string, treeID int64) (rule int8, err error) {
var (
ok bool
node *model.RoleNode
nodes *model.CacheData
)
if nodes, err = s.AuthApps(ctx, user, cookie); err != nil {
return
}
if node, ok = nodes.Data[treeID]; !ok {
err = ecode.AccessDenied
return
}
return node.Role, nil
}
//ConfigGetTreeID ...
func (s *Service) ConfigGetTreeID(configID int64) (TreeID int64, err error) {
conf := new(model.Config)
if err = s.dao.DB.First(&conf, configID).Error; err != nil {
log.Error("ConfigGetTreeID(%v) error(%v)", configID, err)
return
}
TreeID, err = s.AppIDGetTreeID(conf.AppID)
return
}
//AppIDGetTreeID ...
func (s *Service) AppIDGetTreeID(appID int64) (TreeID int64, err error) {
app := new(model.App)
if err = s.dao.DB.First(&app, appID).Error; err != nil {
log.Error("AppIDGetTreeID(%v) error(%v)", appID, err)
return
}
TreeID = app.TreeID
return
}
//BuildGetTreeID ...
func (s *Service) BuildGetTreeID(buildID int64) (TreeID int64, err error) {
build := new(model.Build)
if err = s.dao.DB.First(&build, buildID).Error; err != nil {
log.Error("BuildGetTreeID(%v) error(%v)", buildID, err)
return
}
TreeID, err = s.AppIDGetTreeID(build.AppID)
return
}
//TagGetTreeID ...
func (s *Service) TagGetTreeID(tagID int64) (TreeID int64, err error) {
tag := new(model.Tag)
if err = s.dao.DB.First(&tag, tagID).Error; err != nil {
log.Error("TagGetTreeID(%v) error(%v)", tagID, err)
return
}
TreeID, err = s.AppIDGetTreeID(tag.AppID)
return
}
//ZoneCopy ...
func (s *Service) ZoneCopy(ctx context.Context, AppName, From, To string, TreeID int64) (err error) {
apps := []*model.App{}
if err = s.dao.DB.Where("name = ? and tree_id = ? and zone = ?", AppName, TreeID, From).Find(&apps).Error; err != nil {
log.Error("ZoneCopy from apps error(%v)", err)
return
}
tx := s.dao.DB.Begin()
for _, v := range apps {
app := &model.App{}
if err = s.dao.DB.Where("name = ? and tree_id = ? and zone = ? and env = ?", AppName, TreeID, To, v.Env).First(app).Error; err != nil {
if err != gorm.ErrRecordNotFound {
log.Error("ZoneCopy to app error(%v)", err)
return
}
//add app
if err = s.CreateApp(AppName, v.Env, To, TreeID); err != nil {
log.Error("ZoneCopy add app error(%v)", err)
return
}
if err = s.dao.DB.Where("name = ? and tree_id = ? and zone = ? and env = ?", AppName, TreeID, To, v.Env).First(app).Error; err != nil {
log.Error("ZoneCopy first app error(%v)", err)
return
}
}
//
configs := []*model.Config{}
if err = tx.Where("app_id = ?", app.ID).Find(&configs).Error; err != nil {
log.Error("ZoneCopy find configs error(%v)", err)
tx.Rollback()
return
}
builds := []*model.Build{}
if err = tx.Where("app_id = ?", v.ID).Find(&builds).Error; err != nil {
log.Error("ZoneCopy find builds error(%v)", err)
tx.Rollback()
return
}
for _, val := range builds {
tag := &model.Tag{}
if err = tx.First(tag, val.TagID).Error; err != nil {
log.Error("ZoneCopy find tag error(%v)", err)
tx.Rollback()
return
}
configs = []*model.Config{}
in := strings.Split(tag.ConfigIDs, ",")
if err = tx.Where("id in (?)", in).Find(&configs).Error; err != nil {
log.Error("ZoneCopy find build configs error(%v)", err)
tx.Rollback()
return
}
config := &model.Config{}
var configIDS string
for _, vvv := range configs {
config = &model.Config{}
config.Operator = vvv.Operator
config.Name = vvv.Name
config.Mark = vvv.Mark
config.Comment = vvv.Comment
config.State = vvv.State
config.From = 0 //公共文件变私人文件
if err = s.CreateConf(config, TreeID, v.Env, To, true); err != nil {
log.Error("ZoneCopy config create error(%v)", err)
tx.Rollback()
return
}
if len(configIDS) > 0 {
configIDS += ","
}
configIDS += strconv.FormatInt(config.ID, 10)
}
newTag := &model.Tag{}
newTag.Operator = tag.Operator
newTag.Mark = tag.Mark
newTag.ConfigIDs = configIDS
s.UpdateTag(ctx, TreeID, v.Env, To, val.Name, newTag)
}
}
tx.Commit()
return
}
// CanalCheckToken ...
func (s *Service) CanalCheckToken(AppName, Env, Zone, Token string) (err error) {
app := &model.App{}
if err = s.dao.DB.Where("name = ? and env = ? and zone = ? and tree_id = ? and token = ?", AppName, Env, Zone, 3766, Token).First(app).Error; err != nil {
log.Error("canalCheckToken error(%v)", err)
}
return
}
// CasterEnvs ...
func (s *Service) CasterEnvs(zone string, treeID int64) (envs []*model.Env, err error) {
var (
apps []*model.App
)
envs = rdsEnvs
apps, err = s.AppsByTreeZone(treeID, zone)
for _, env := range envs {
env.Token = ""
for _, app := range apps {
if app.Env == env.Name {
env.Token = app.Token
break
}
}
}
return
}
// AppRename ...
func (s *Service) AppRename(treeID int64, user, cookie string) (err error) {
var (
ok bool
node *model.RoleNode
nodes *model.CacheData
)
s.cLock.RLock()
nodes, ok = s.cache[user]
s.cLock.RUnlock()
if !ok {
err = ecode.NothingFound
return
}
if node, ok = nodes.Data[treeID]; !ok {
err = ecode.AccessDenied
return
}
if len(node.Path) == 0 {
err = ecode.NothingFound
return
}
if err = s.dao.DB.Model(&model.App{}).Where("tree_id =?", treeID).Update("name", node.Path).Error; err != nil {
log.Error("AppRename update error(%v)", err)
return
}
return
}
// GetApps ...
func (s *Service) GetApps(env string) (apps []*model.App, err error) {
if err = s.dao.DB.Where("env = ?", env).Find(&apps).Error; err != nil {
log.Error("GetApps error(%v)", err)
}
return
}
// IdsGetApps ...
func (s *Service) IdsGetApps(ids []int64) (apps []*model.App, err error) {
if err = s.dao.DB.Where("id in (?)", ids).Find(&apps).Error; err != nil {
log.Error("IdsGetApps error(%v)", err)
}
return
}
// UpAppStatus edit status.
func (s *Service) UpAppStatus(ctx context.Context, status int8, treeID int64) (err error) {
var (
apps []*model.App
)
ups := map[string]interface{}{
"status": status,
}
if err = s.dao.DB.Model(apps).Where("tree_id = ?", treeID).Updates(ups).Error; err != nil {
log.Error("AppStatus error(%v) status(%v)", err, status)
}
return
}

View File

@ -0,0 +1,40 @@
package service
import (
"context"
"testing"
"go-common/app/admin/main/config/conf"
"github.com/BurntSushi/toml"
. "github.com/smartystreets/goconvey/convey"
)
func svr(t *testing.T) (svr *Service) {
var (
confPath = "../cmd/config-admin-example.toml"
conf *conf.Config
)
Convey("should decodeFile file", t, func() {
_, err := toml.DecodeFile(confPath, &conf)
So(err, ShouldBeNil)
})
return New(conf)
}
func TestService_UpdateToken(t *testing.T) {
svr := svr(t)
Convey("should update token", t, func() {
err := svr.UpdateToken(context.Background(), "dev", "sh001", 2888)
So(err, ShouldBeNil)
})
}
func TestService_AppByName(t *testing.T) {
svr := svr(t)
Convey("should get app by name", t, func() {
app, err := svr.AppByTree(2888, "dev", "sh001")
So(err, ShouldBeNil)
So(app, ShouldNotBeEmpty)
})
}

View File

@ -0,0 +1,215 @@
package service
import (
"context"
"database/sql"
"go-common/app/admin/main/config/model"
"go-common/library/ecode"
"go-common/library/log"
)
// CreateBuild create build.
func (s *Service) CreateBuild(build *model.Build, treeID int64, env, zone string) (err error) {
var app *model.App
if app, err = s.AppByTree(treeID, env, zone); err != nil {
return
}
build.AppID = app.ID
return s.dao.DB.Create(build).Error
}
//UpdateTag update tag.
func (s *Service) UpdateTag(ctx context.Context, treeID int64, env, zone, name string, tag *model.Tag) (err error) {
var (
app *model.App
build *model.Build
)
if app, err = s.AppByTree(treeID, env, zone); err != nil {
return
}
if build, err = s.BuildByName(app.ID, name); err != nil {
if err != ecode.NothingFound {
return
}
build = &model.Build{AppID: app.ID, Name: name, Mark: tag.Mark, Operator: tag.Operator}
if err = s.dao.DB.Create(build).Error; err != nil {
log.Error("CreateBuild(%s) error(%v)", build.Name, err)
return
}
}
tag.AppID = app.ID
tag.BuildID = build.ID
if err = s.dao.DB.Create(&tag).Error; err != nil {
log.Error("CreateTag(%s) error(%v)", tag.Mark, err)
return
}
if tag.Force == 1 {
//Clear stand-alone force
forces := []*model.Force{}
if err = s.dao.DB.Where("app_id = ?", app.ID).Find(&forces).Error; err != nil {
log.Error("select forces(%s) error(%v)", app.ID, err)
return
}
mHosts := model.MapHosts{}
for _, val := range forces {
mHosts[val.Hostname] = val.IP
}
if len(mHosts) > 0 {
if err = s.ClearForce(ctx, treeID, env, zone, name, mHosts); err != nil {
log.Error("clear forces(%s) error(%v)", app.ID, err)
return
}
}
}
tx := s.dao.DB.Begin()
if err = tx.Model(&model.Build{ID: build.ID}).Update(map[string]interface{}{
"tag_id": tag.ID,
"operator": tag.Operator,
}).Error; err != nil {
tx.Rollback()
log.Error("updateTagID(%d) error(%v)", tag.ID, err)
return
}
//push
if err = s.Push(ctx, treeID, env, zone, build.Name, tag.ID); err != nil {
tx.Rollback()
return
}
tx.Commit()
return
}
//UpdateTagID update tag.
func (s *Service) UpdateTagID(ctx context.Context, env, zone, bName string, tag, TreeID int64) (err error) {
build := new(model.Build)
build.Name = bName
build.TagID = tag
var app *model.App
if app, err = s.AppByTree(TreeID, env, zone); err != nil {
return
}
tx := s.dao.DB.Begin()
if err = tx.Model(&model.Build{}).Where("app_id = ? and name = ?", app.ID, build.Name).Update(map[string]interface{}{
"tag_id": build.TagID,
"operator": build.Operator,
}).Error; err != nil {
tx.Rollback()
log.Error("updateTagID(%d) error(%v)", build.TagID, err)
return
}
if err = s.Push(ctx, TreeID, env, zone, build.Name, build.TagID); err != nil {
tx.Rollback()
return
}
tx.Commit()
return
}
//Builds get builds by app id.
func (s *Service) Builds(treeID int64, appName, env, zone string) (builds []*model.Build, err error) {
var (
app *model.App
tag *model.Tag
)
if app, err = s.AppByTree(treeID, env, zone); err != nil {
if err == ecode.NothingFound {
if err = s.CreateApp(appName, env, zone, treeID); err == nil {
builds = make([]*model.Build, 0)
}
return
}
}
if builds, err = s.BuildsByApp(app.ID); err != nil {
return
}
for _, build := range builds {
if tag, err = s.Tag(build.TagID); err != nil {
if err == ecode.NothingFound {
err = nil
}
}
build.Mark = tag.Mark
build.Operator = tag.Operator
build.Mtime = tag.Mtime
}
return
}
//BuildsByApp buildsByApp.
func (s *Service) BuildsByApp(appID int64) (builds []*model.Build, err error) {
if err = s.dao.DB.Find(&builds, "app_id = ? ", appID).Error; err != nil {
log.Error("BuildsByApp(%s) error(%v)", appID, err)
if err == sql.ErrNoRows {
err = nil
}
}
return
}
//Build get Build by build ID.
func (s *Service) Build(ID int64) (build *model.Build, err error) {
build = new(model.Build)
if err = s.dao.DB.First(&build, ID).Error; err != nil {
log.Error("Build(%v) error(%v)", ID, err)
if err == sql.ErrNoRows {
err = ecode.NothingFound
}
}
return
}
//Delete delete Build by build ID.
func (s *Service) Delete(ID int64) (err error) {
if err = s.dao.DB.Delete(&model.Build{}, ID).Error; err != nil {
log.Error("Delete(%v) error(%v)", ID, err)
}
return
}
//BuildByName get Build by build ID.
func (s *Service) BuildByName(appID int64, name string) (build *model.Build, err error) {
build = new(model.Build)
if err = s.dao.DB.First(&build, "app_id = ? and name = ?", appID, name).Error; err != nil {
log.Error("BuildByName(%s) error(%v)", name, err)
if err == sql.ErrNoRows {
err = ecode.NothingFound
}
}
return
}
//GetDelInfos get delete info.
func (s *Service) GetDelInfos(c context.Context, BuildID int64) (err error) {
build := &model.Build{}
if err = s.dao.DB.Where("id = ?", BuildID).First(build).Error; err != nil {
log.Error("GetDelInfos BuildID(%v) error(%v)", BuildID, err)
return
}
app := &model.App{}
if err = s.dao.DB.Where("id = ?", build.AppID).First(app).Error; err != nil {
log.Error("GetDelInfos AppID(%v) error(%v)", build.AppID, err)
return
}
hosts, err := s.Hosts(c, app.TreeID, app.Name, app.Env, app.Zone)
if err != nil {
log.Error("GetDelInfos hosts(%v) error(%v)", hosts, err)
return
}
for _, v := range hosts {
if v.BuildVersion == build.Name {
err = ecode.NothingFound
return
}
}
return
}
// AllBuilds ...
func (s *Service) AllBuilds(appIDS []int64) (builds []*model.Build, err error) {
if err = s.dao.DB.Where("app_id in (?)", appIDS).Find(&builds).Error; err != nil {
log.Error("AllBuild error(%v)", err)
}
return
}

View File

@ -0,0 +1,25 @@
package service
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_BuildsByAppName(t *testing.T) {
svr := svr(t)
Convey("should app by name", t, func() {
res, err := svr.Builds(2888, "main.common-arch.msm-service", "dev", "sh001")
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
}
func TestService_BuildByID(t *testing.T) {
svr := svr(t)
Convey("should app by name", t, func() {
res, err := svr.Build(1)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
}

View File

@ -0,0 +1,311 @@
package service
import (
"context"
"database/sql"
"strconv"
"strings"
"go-common/app/admin/main/config/model"
"go-common/library/ecode"
"go-common/library/log"
)
// CreateComConf create config.
func (s *Service) CreateComConf(conf *model.CommonConf, name, env, zone string, skiplint bool) (err error) {
if !skiplint {
if err = lintConfig(conf.Name, conf.Comment); err != nil {
return
}
}
var team *model.Team
if team, err = s.TeamByName(name, env, zone); err != nil {
return
}
conf.TeamID = team.ID
return s.dao.DB.Create(conf).Error
}
// ComConfig get common config by id.
func (s *Service) ComConfig(id int64) (conf *model.CommonConf, err error) {
conf = new(model.CommonConf)
if err = s.dao.DB.First(&conf, "id = ?", id).Error; err != nil {
log.Error("ComConfig() error(%v)", err)
}
return
}
// ComConfigsByTeam common config by team.
func (s *Service) ComConfigsByTeam(name, env, zone string, ps, pn int64) (pager *model.CommonConfPager, err error) {
var (
team *model.Team
confs []*model.CommonConf
temp []*model.CommonTemp
counts model.CommonCounts
array []int64
)
if team, err = s.TeamByName(name, env, zone); err != nil {
return
}
if err = s.dao.DB.Raw("select max(id) as id,count(distinct name) as counts from common_config where team_id =? group by name order by id desc", team.ID).Scan(&temp).Error; err != nil {
log.Error("NamesByTeam(%v) error(%v)", team.ID, err)
if err == sql.ErrNoRows {
err = nil
}
}
if err = s.dao.DB.Raw("select count(distinct name) as counts from common_config where team_id = ?", team.ID).Scan(&counts).Error; err != nil {
if err == sql.ErrNoRows {
err = nil
}
return
}
for _, v := range temp {
array = append(array, v.ID)
}
if err = s.dao.DB.Raw("select id,team_id,name,state,mark,operator,ctime,mtime from common_config where id in (?) limit ?,?", array, (pn-1)*ps, ps).Scan(&confs).Error; err != nil {
log.Error("NamesByTeam(%v) temp(%v) error(%v)", team.ID, temp, err)
return
}
return &model.CommonConfPager{Total: counts.Counts, Pn: pn, Ps: ps, Items: confs}, nil
}
//ComConfigsByName get Config by Config name.
func (s *Service) ComConfigsByName(teamName, env, zone, name string) (confs []*model.CommonConf, err error) {
var team *model.Team
if team, err = s.TeamByName(teamName, env, zone); err != nil {
return
}
if err = s.dao.DB.Select("id,team_id,name,state,mark,operator,ctime,mtime").Where("name = ? and team_id = ?",
name, team.ID).Order("id desc").Limit(10).Find(&confs).Error; err != nil {
return
}
return
}
// UpdateComConfValue update config value.
func (s *Service) UpdateComConfValue(conf *model.CommonConf, skiplint bool) (err error) {
if !skiplint {
if err = lintConfig(conf.Name, conf.Comment); err != nil {
return
}
}
var confDB *model.CommonConf
if confDB, err = s.ComConfig(conf.ID); err != nil {
return
}
if confDB.State == model.ConfigIng { //judge config is configIng.
if conf.Mtime != confDB.Mtime {
err = ecode.TargetBlocked
return
}
conf.Mtime = 0
err = s.dao.DB.Model(&model.CommonConf{ID: confDB.ID}).Updates(conf).Error
return
}
if _, err = s.comConfigIng(confDB.Name, confDB.TeamID); err == nil { //judge have configing.
err = ecode.TargetBlocked
return
}
if err == sql.ErrNoRows || err == ecode.NothingFound {
conf.ID = 0
conf.TeamID = confDB.TeamID
conf.Name = confDB.Name
conf.Mtime = 0
return s.dao.DB.Create(conf).Error
}
return
}
func (s *Service) comConfigIng(name string, teamID int64) (conf *model.CommonConf, err error) {
conf = new(model.CommonConf)
if err = s.dao.DB.Select("id").Where("name = ? and team_id = ? and state=?", name, teamID, model.ConfigIng).First(&conf).Error; err != nil {
log.Error("configIng(%v) error(%v)", name, err)
if err == sql.ErrNoRows {
err = ecode.NothingFound
}
}
return
}
// NamesByTeam get configs by team name.
func (s *Service) NamesByTeam(teamName, env, zone string) (names []*model.CommonName, err error) {
var (
team *model.Team
confs []*model.CommonConf
)
if team, err = s.TeamByName(teamName, env, zone); err != nil {
if err == ecode.NothingFound {
err = s.CreateTeam(teamName, env, zone)
return
}
}
if err = s.dao.DB.Where("team_id = ? and state = 2", team.ID).Order("id desc").Find(&confs).Error; err != nil {
log.Error("NamesByTeam(%v) error(%v)", team.ID, err)
if err == sql.ErrNoRows {
err = nil
}
}
tmp := make(map[string]struct{})
for _, conf := range confs {
if _, ok := tmp[conf.Name]; !ok {
names = append(names, &model.CommonName{Name: conf.Name, ID: conf.ID})
tmp[conf.Name] = struct{}{}
}
}
return
}
//AppByTeam get tagMap
func (s *Service) AppByTeam(commonConfigID int64) (tagMap map[int64]*model.TagMap, err error) {
var commonConfig *model.CommonConf
if commonConfig, err = s.ComConfig(commonConfigID); err != nil {
return
}
team := &model.Team{}
if err = s.dao.DB.Where("id = ?", commonConfig.TeamID).First(team).Error; err != nil {
return
}
commonConf := []*model.CommonConf{}
if err = s.dao.DB.Select("id").Where("name = ? and team_id = ? and state = 2", commonConfig.Name, commonConfig.TeamID).Find(&commonConf).Error; err != nil {
log.Error("AppByTeam() common_config error(%v)", err)
}
var commonConfTmp []int64
for _, val := range commonConf {
commonConfTmp = append(commonConfTmp, val.ID)
}
app := []*model.App{}
if err = s.dao.DB.Where("name like ? and env = ? and zone = ?", team.Name+".%", team.Env, team.Zone).Find(&app).Error; err != nil {
log.Error("AppByTeam() app error(%v)", err)
}
var appTmp []int64
appMap := make(map[int64]*model.App)
for _, val := range app {
appMap[val.ID] = val
appTmp = append(appTmp, val.ID)
}
conf := []*model.Config{}
if err = s.dao.DB.Where("`from` in (?) and app_id in (?) and state = 2 and is_delete = 0", commonConfTmp, appTmp).Find(&conf).Error; err != nil {
log.Error("AppByTeam() config error(%v)", err)
}
confMap := make(map[int64]struct{})
for _, val := range conf {
confMap[val.ID] = struct{}{}
}
build := []*model.Build{}
if err = s.dao.DB.Where("app_id in (?)", appTmp).Find(&build).Error; err != nil {
log.Error("AppByTeam() build error(%v)", err)
}
var buildTmp []int64
buildMap := make(map[int64]string)
for _, val := range build {
buildMap[val.ID] = val.Name
buildTmp = append(buildTmp, val.TagID)
}
tagMap = make(map[int64]*model.TagMap)
tag := []*model.Tag{}
if err = s.dao.DB.Where("id in (?)", buildTmp).Find(&tag).Error; err != nil {
log.Error("AppByTeam() tag error(%v)", err)
}
for _, val := range tag {
tmp := strings.Split(val.ConfigIDs, ",")
for _, vv := range tmp {
vv, _ := strconv.ParseInt(vv, 10, 64)
if _, ok := confMap[vv]; !ok {
continue
}
tagMap[val.ID] = &model.TagMap{Tag: val}
if _, ok := appMap[val.AppID]; ok {
tagMap[val.ID].AppName = appMap[val.AppID].Name
tagMap[val.ID].TreeID = appMap[val.AppID].TreeID
}
if _, ok := buildMap[val.BuildID]; ok {
tagMap[val.ID].BuildName = buildMap[val.BuildID]
}
}
}
return
}
// CommonPush ...
func (s *Service) CommonPush(ctx context.Context, tagID, commonConfigID int64, user string) (err error) {
var tag *model.Tag
tag, err = s.Tag(tagID)
if err != nil {
log.Error("CommonPush() tagid(%v) error(%v)", tagID, err)
return
}
configIDS := strings.Split(tag.ConfigIDs, ",")
app := &model.App{}
if err = s.dao.DB.Where("id = ?", tag.AppID).First(app).Error; err != nil {
log.Error("CommonPush() app error(%v)", err)
return
}
build := &model.Build{}
if err = s.dao.DB.Where("id = ?", tag.BuildID).First(build).Error; err != nil {
log.Error("CommonPush() build error(%v)", err)
return
}
var commonConfig *model.CommonConf
if commonConfig, err = s.ComConfig(commonConfigID); err != nil {
return
}
team := &model.Team{}
if err = s.dao.DB.Where("id = ?", commonConfig.TeamID).First(team).Error; err != nil {
log.Error("CommonPush() team error(%v)", err)
return
}
commonConf := []*model.CommonConf{}
if err = s.dao.DB.Select("id").Where("name = ? and team_id = ? and state = 2", commonConfig.Name, commonConfig.TeamID).Find(&commonConf).Error; err != nil {
log.Error("CommonPush() common_config error(%v)", err)
return
}
var commonConfTmp []int64
for _, val := range commonConf {
commonConfTmp = append(commonConfTmp, val.ID)
}
conf := []*model.Config{}
if err = s.dao.DB.Where("id in (?) and `from` in (?)", configIDS, commonConfTmp).Find(&conf).Error; err != nil {
log.Error("CommonPush() config error(%v)", err)
return
}
if len(conf) != 1 {
log.Error("CommonPush() count config(%v) error(数据有误更新数据非1条)", conf)
return
}
var newConfigIDS string
for _, val := range conf {
newConf := &model.Config{}
newConf.AppID = val.AppID
newConf.Comment = commonConfig.Comment
newConf.Mark = commonConfig.Mark
newConf.Name = val.Name
newConf.State = 2
newConf.From = commonConfigID
newConf.Operator = user
if _, err = s.configIng(newConf.Name, app.ID); err == nil { // judge config is configIng
err = ecode.TargetBlocked
return
}
if err = s.dao.DB.Create(newConf).Error; err != nil {
log.Error("CommonPush() create newConf error(%v)", err)
return
}
newConfigIDS = strconv.FormatInt(newConf.ID, 10)
for _, vv := range configIDS {
if strconv.FormatInt(val.ID, 10) != vv {
if len(newConfigIDS) > 0 {
newConfigIDS += ","
}
newConfigIDS += vv
}
}
//tag发版
newTag := &model.Tag{}
newTag.Operator = user
newTag.Mark = tag.Mark
newTag.ConfigIDs = newConfigIDS
newTag.Force = 1
err = s.UpdateTag(ctx, app.TreeID, app.Env, app.Zone, build.Name, newTag)
}
return
}

View File

@ -0,0 +1,25 @@
package service
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_ComConfigsByTagID(t *testing.T) {
svr := svr(t)
Convey("should app by name", t, func() {
res, err := svr.ConfigsByTagID(1)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
}
func TestService_ComConfigsByTeam(t *testing.T) {
svr := svr(t)
Convey("should get common config by team", t, func() {
res, err := svr.ComConfigsByTeam("main.common-arch", "dev", "shd", 1, 1)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
}

View File

@ -0,0 +1,83 @@
package service
import (
"context"
"fmt"
"go-common/app/infra/config/model"
"go-common/library/log"
)
// Push push new ver to config-service.
func (s *Service) Push(c context.Context, treeID int64, env, zone, bver string, ver int64) (err error) {
svr := svrFmt(treeID, env, zone)
arg := &model.ArgConf{
App: svr,
BuildVer: bver,
Ver: ver,
}
if err = s.confSvr.PushV4(c, arg); err != nil {
log.Error("PushV4(%v) error(%v)", arg, err)
}
return
}
// SetToken set token to config-service.
func (s *Service) SetToken(c context.Context, treeID int64, env, zone, token string) (err error) {
svr := svrFmt(treeID, env, zone)
arg := &model.ArgToken{
App: svr,
Token: token,
}
if err = s.confSvr.SetTokenV4(c, arg); err != nil {
log.Error("SetToken(%v) error(%v)", arg, err)
}
return
}
// Hosts get hosts.
func (s *Service) Hosts(c context.Context, treeID int64, appName, env, zone string) (hosts []*model.Host, err error) {
svr := svrFmt(treeID, env, zone)
if hosts, err = s.confSvr.Hosts(c, svr); err != nil {
log.Error("Hosts(%v) error(%v)", svr, err)
return
}
if len(hosts) == 0 {
hosts = make([]*model.Host, 0)
return
}
for _, host := range hosts {
host.Service = appName
}
return
}
// ClearHost clear hosts.
func (s *Service) ClearHost(c context.Context, treeID int64, env, zone string) (err error) {
svr := svrFmt(treeID, env, zone)
if err = s.confSvr.ClearHost(c, svr); err != nil {
log.Error("Hosts(%v) error(%v)", svr, err)
}
return
}
func svrFmt(treeID int64, env, zone string) string {
return fmt.Sprintf("%d_%s_%s", treeID, env, zone)
}
// PushForce push new ver to config-service.
func (s *Service) PushForce(c context.Context, treeID int64, env, zone, bver string, ver int64, hosts map[string]string, sType int8) (err error) {
svr := svrFmt(treeID, env, zone)
arg := &model.ArgConf{
App: svr,
BuildVer: bver,
Ver: ver,
Env: env,
Hosts: hosts,
SType: sType,
}
if err = s.confSvr.Force(c, arg); err != nil {
log.Error("PushForce(%v) error(%v)", arg, err)
}
return
}

View File

@ -0,0 +1,40 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_Push(t *testing.T) {
svr := svr(t)
Convey("should push", t, func() {
err := svr.Push(context.Background(), 2888, "dev", "sh001", "server-1", 1)
So(err, ShouldBeNil)
})
}
func TestService_SetToken(t *testing.T) {
svr := svr(t)
Convey("should set token", t, func() {
err := svr.SetToken(context.Background(), 2888, "dev", "sh001", "84c0c277f13111e79d54522233017188")
So(err, ShouldBeNil)
})
}
func TestService_Hosts(t *testing.T) {
svr := svr(t)
Convey("should get hosts", t, func() {
_, err := svr.Hosts(context.Background(), 2888, "main.common-arch.msm-service", "dev", "sh001")
So(err, ShouldBeNil)
})
}
func TestService_ClearHost(t *testing.T) {
svr := svr(t)
Convey("should clear host", t, func() {
err := svr.ClearHost(context.Background(), 2888, "dev", "sh001")
So(err, ShouldBeNil)
})
}

View File

@ -0,0 +1,920 @@
package service
import (
"bufio"
"bytes"
"context"
"database/sql"
"path/filepath"
"strconv"
"strings"
"go-common/app/admin/main/config/model"
"go-common/app/admin/main/config/pkg/lint"
"go-common/library/ecode"
"go-common/library/log"
"github.com/jinzhu/gorm"
)
func lintConfig(filename, content string) error {
ext := strings.TrimLeft(filepath.Ext(filename), ".")
err := lint.Lint(ext, bytes.NewBufferString(content))
if err != nil && err != lint.ErrLintNotExists {
return ecode.Error(ecode.RequestErr, err.Error())
}
return nil
}
// CreateConf create config.
func (s *Service) CreateConf(conf *model.Config, treeID int64, env, zone string, skiplint bool) error {
// lint config
if !skiplint {
if err := lintConfig(conf.Name, conf.Comment); err != nil {
return err
}
}
app, err := s.AppByTree(treeID, env, zone)
if err != nil {
return err
}
conf.AppID = app.ID
if _, err := s.configIng(conf.Name, app.ID); err == nil { // judge config is configIng
return ecode.TargetBlocked
}
return s.dao.DB.Create(conf).Error
}
// LintConfig lint config file
func (s *Service) LintConfig(filename, content string) ([]lint.LineErr, error) {
ext := strings.TrimLeft(filepath.Ext(filename), ".")
err := lint.Lint(ext, bytes.NewBufferString(content))
if err == nil || err == lint.ErrLintNotExists {
return make([]lint.LineErr, 0), nil
}
lintErr, ok := err.(lint.Error)
if !ok {
return nil, lintErr
}
return []lint.LineErr(lintErr), nil
}
// UpdateConfValue update config state.
func (s *Service) UpdateConfValue(conf *model.Config, skiplint bool) (err error) {
// lint config
if !skiplint {
if err := lintConfig(conf.Name, conf.Comment); err != nil {
return err
}
}
var confDB *model.Config
if confDB, err = s.Config(conf.ID); err != nil {
return
}
if confDB.State == model.ConfigIng { //judge config is configIng.
if conf.Mtime != confDB.Mtime {
err = ecode.TargetBlocked
return
}
conf.Mtime = 0
err = s.dao.DB.Model(&model.Config{State: model.ConfigIng}).Updates(conf).Error
return
}
if _, err = s.configIng(confDB.Name, confDB.AppID); err == nil {
err = ecode.TargetBlocked
return
}
if err == sql.ErrNoRows || err == ecode.NothingFound {
conf.ID = 0
conf.AppID = confDB.AppID
conf.Name = confDB.Name
if conf.From == 0 {
conf.From = confDB.From
}
conf.Mtime = 0
return s.dao.DB.Create(conf).Error
}
return
}
// UpdateConfState update config state.
func (s *Service) UpdateConfState(ID int64) (err error) {
err = s.dao.DB.Model(&model.Config{ID: ID}).Update("state", model.ConfigEnd).Error
return
}
// ConfigsByIDs get Config by IDs.
func (s *Service) ConfigsByIDs(ids []int64) (confs []*model.Config, err error) {
if err = s.dao.DB.Select("id,app_id,name,`from`,state,mark,operator,ctime,mtime,is_delete").Where(ids).Find(&confs).Error; err != nil {
log.Error("ConfigsByIDs(%v) error(%v)", ids, err)
if err == sql.ErrNoRows {
err = nil
}
}
return
}
// ConfigsByAppName get configs by app name.
func (s *Service) ConfigsByAppName(appName, env, zone string, treeID int64, state int8) (confs []*model.Config, err error) {
var app *model.App
if app, err = s.AppByTree(treeID, env, zone); err != nil {
if err == ecode.NothingFound {
err = s.CreateApp(appName, env, zone, treeID)
return
}
}
if state != 0 {
err = s.dao.DB.Select("id,app_id,name,`from`,state,mark,operator,is_delete,ctime,mtime").Where("app_id = ? and state =?", app.ID, state).Order("id desc").Find(&confs).Error
} else {
err = s.dao.DB.Select("id,app_id,name,`from`,state,mark,operator,is_delete,ctime,mtime").Where("app_id = ? ", app.ID).Order("id desc").Find(&confs).Error
}
if err != nil {
if err == sql.ErrNoRows {
err = nil
}
}
return
}
// ConfigsByAppID configs by app ID.
func (s *Service) ConfigsByAppID(appID int64, state int8) (confs []*model.Config, err error) {
if state != 0 {
err = s.dao.DB.Select("id,app_id,name,`from`,state,mark,operator,is_delete,ctime,mtime").Where("app_id = ? and state =?", appID, state).Order("id desc").Find(&confs).Error
} else {
err = s.dao.DB.Select("id,app_id,name,`from`,state,mark,operator,is_delete,ctime,mtime").Where("app_id = ? ", appID).Order("id desc").Find(&confs).Error
}
if err != nil {
if err == sql.ErrNoRows {
err = nil
}
}
return
}
//ConfigSearchApp configSearchApp.
func (s *Service) ConfigSearchApp(ctx context.Context, appName, env, zone, like string, buildID, treeID int64) (searchs []*model.ConfigSearch, err error) {
var (
app *model.App
builds []*model.Build
tags []*model.Tag
confs []*model.Config
tagIDs []int64
confIDs []int64
)
if app, err = s.AppByTree(treeID, env, zone); err != nil {
return
}
if builds, err = s.BuildsByApp(app.ID); err != nil {
return
}
if len(builds) == 0 {
return
}
for _, build := range builds {
tagIDs = append(tagIDs, build.TagID)
}
if err = s.dao.DB.Where("id in(?)", tagIDs).Find(&tags).Error; err != nil {
log.Error("tagsByIDs(%v) error(%v)", tagIDs, err)
if err == sql.ErrNoRows {
err = nil
}
return
}
tmp := make(map[int64]struct{})
for _, tag := range tags {
tmpIDs := strings.Split(tag.ConfigIDs, ",")
for _, tmpID := range tmpIDs {
var id int64
if id, err = strconv.ParseInt(tmpID, 10, 64); err != nil {
log.Error("strconv.ParseInt() error(%v)", err)
return
}
if _, ok := tmp[id]; !ok {
tmp[id] = struct{}{}
confIDs = append(confIDs, id)
}
}
}
if err = s.dao.DB.Where("id in (?) AND comment like(?) ", confIDs, "%"+like+"%").Find(&confs).Error; err != nil {
log.Error("confsByIDs(%v) error(%v)", confIDs, err)
if err == sql.ErrNoRows {
err = nil
}
return
}
for _, conf := range confs {
search := new(model.ConfigSearch)
search.App = appName
for _, tag := range tags {
tmpIDs := strings.Split(tag.ConfigIDs, ",")
for _, tmpID := range tmpIDs {
var id int64
if id, err = strconv.ParseInt(tmpID, 10, 64); err != nil {
log.Error("strconv.ParseInt() error(%v)", err)
return
}
if id != conf.ID { //judge config is in build.
continue
}
for _, build := range builds {
if build.ID == tag.BuildID {
search.Builds = append(search.Builds, build.Name)
}
}
}
}
//generate comment.
search.ConfValues = genComments(conf.Comment, like)
search.ConfID = conf.ID
search.Mark = conf.Mark
search.ConfName = conf.Name
searchs = append(searchs, search)
}
return
}
//ConfigSearchAll configSearchAll.
func (s *Service) ConfigSearchAll(ctx context.Context, env, zone, like string, nodes *model.CacheData) (searchs []*model.ConfigSearch, err error) {
var (
apps []*model.App
builds []*model.Build
tags []*model.Tag
confs []*model.Config
names []string
appIDs []int64
tagIDs []int64
configIDs []int64
)
searchs = make([]*model.ConfigSearch, 0)
if len(nodes.Data) == 0 {
return
}
for _, node := range nodes.Data {
names = append(names, node.Path)
}
if err = s.dao.DB.Where("env =? and zone =? and name in(?)", env, zone, names).Find(&apps).Error; err != nil {
log.Error("AppList() find apps() error(%v)", err)
if err == sql.ErrNoRows {
err = nil
}
return
}
for _, app := range apps {
appIDs = append(appIDs, app.ID)
}
if err = s.dao.DB.Where("app_id in(?) ", appIDs).Find(&builds).Error; err != nil {
log.Error("BuildsByAppIDs(%v) error(%v)", appIDs, err)
if err == sql.ErrNoRows {
err = nil
}
return
}
for _, build := range builds {
tagIDs = append(tagIDs, build.TagID)
}
if err = s.dao.DB.Where("id in(?)", tagIDs).Find(&tags).Error; err != nil {
log.Error("tagsByIDs(%v) error(%v)", tagIDs, err)
if err == sql.ErrNoRows {
err = nil
}
return
}
tmp := make(map[int64]struct{})
for _, tag := range tags {
tmpIDs := strings.Split(tag.ConfigIDs, ",")
for _, tmpID := range tmpIDs {
var id int64
if id, err = strconv.ParseInt(tmpID, 10, 64); err != nil {
log.Error("strconv.ParseInt() error(%v)", err)
return
}
if _, ok := tmp[id]; !ok {
tmp[id] = struct{}{}
configIDs = append(configIDs, id)
}
}
}
if err = s.dao.DB.Where("id in (?) and comment like(?) ", configIDs, "%"+like+"%").Find(&confs).Error; err != nil {
log.Error("confsByIDs(%v) error(%v)", configIDs, err)
if err == sql.ErrNoRows {
err = nil
}
return
}
if len(confs) == 0 {
return
}
// convert confs to confSearch.
for _, conf := range confs {
search := new(model.ConfigSearch)
for _, app := range apps {
if app.ID == conf.AppID {
search.App = app.Name
search.TreeID = app.TreeID
}
}
for _, tag := range tags {
tmpIDs := strings.Split(tag.ConfigIDs, ",")
for _, tmpID := range tmpIDs {
var id int64
if id, err = strconv.ParseInt(tmpID, 10, 64); err != nil {
log.Error("strconv.ParseInt() error(%v)", err)
return
}
if id != conf.ID { //judge config is in build.
continue
}
for _, build := range builds {
if build.ID == tag.BuildID {
search.Builds = append(search.Builds, build.Name)
}
}
}
}
//generate comment.
search.ConfValues = genComments(conf.Comment, like)
search.ConfID = conf.ID
search.Mark = conf.Mark
search.ConfName = conf.Name
searchs = append(searchs, search)
}
return
}
func genComments(comment, like string) (comments []string) {
var (
line []byte
l, cur []byte
err error
)
wbuf := new(bytes.Buffer)
rbuf := bufio.NewReader(strings.NewReader(comment))
for {
l = line
if line, _, err = rbuf.ReadLine(); err != nil {
break
}
if bytes.Contains(line, []byte(like)) {
cur = line
wbuf.Write(l)
wbuf.WriteString("\n")
wbuf.Write(cur)
wbuf.WriteString("\n")
line, _, _ = rbuf.ReadLine()
wbuf.Write(line)
wbuf.WriteString("\n")
comments = append(comments, wbuf.String())
wbuf.Reset()
}
}
return
}
//Configs configs.
func (s *Service) Configs(appName, env, zone string, buildID, treeID int64) (res *model.ConfigRes, err error) {
var (
allConfs []*model.Config
buildConfs []*model.Config
lastConfs []*model.Config
app *model.App
build *model.Build
)
if app, err = s.AppByTree(treeID, env, zone); err != nil {
if err == ecode.NothingFound {
err = s.CreateApp(appName, env, zone, treeID)
return
}
}
if allConfs, err = s.ConfigsByAppID(app.ID, 0); err != nil {
return
}
if buildID != 0 {
if build, err = s.Build(buildID); err != nil {
return
}
if build.AppID != app.ID {
err = ecode.NothingFound
return
}
tagID := build.TagID
if tagID == 0 {
return
}
if buildConfs, err = s.ConfigsByTagID(tagID); err != nil {
return
}
if lastConfs, err = s.LastBuildConfigConfigs(build.AppID, buildID); err != nil {
if err != ecode.NothingFound {
return
}
err = nil
}
}
tmpMap := make(map[string]struct{})
res = new(model.ConfigRes)
for _, conf := range allConfs {
if _, ok := tmpMap[conf.Name]; ok {
continue
}
//new common
if conf.From > 0 {
conf.NewCommon, _ = s.NewCommon(conf.From)
}
tmpMap[conf.Name] = struct{}{}
var bool bool
for _, bconf := range buildConfs {
//new common
if bconf.From > 0 {
bconf.NewCommon, _ = s.NewCommon(bconf.From)
}
if bconf.Name == conf.Name {
if bconf.ID != conf.ID {
if conf.IsDelete != 1 {
res.BuildNewFile = append(res.BuildNewFile, conf)
}
}
bf := &model.BuildFile{Config: bconf}
if bf.IsDelete == 0 {
res.BuildFiles = append(res.BuildFiles, bf)
}
for _, lconf := range lastConfs {
if lconf.Name == bconf.Name {
if lconf.ID != bconf.ID {
bf.LastConf = lconf
}
}
}
bool = true
break
}
}
if !bool {
if conf.IsDelete != 1 {
res.Files = append(res.Files, conf)
}
continue
}
}
return
}
// NewCommon get new common id
func (s *Service) NewCommon(from int64) (new int64, err error) {
common := &model.CommonConf{}
newCommon := &model.CommonConf{}
if err = s.dao.DB.First(&common, from).Error; err != nil {
log.Error("NewCommon.First.from(%d) error(%v)", from, err)
return
}
if err = s.dao.DB.Where("team_id = ? and name = ? and state = 2", common.TeamID, common.Name).Order("id desc").First(&newCommon).Error; err != nil {
log.Error("NewCommon.Order.First.common(%v) error(%v)", common, err)
return
}
new = newCommon.ID
return
}
//ConfigRefs configRefs.
func (s *Service) ConfigRefs(appName, env, zone string, buildID, treeID int64) (res []*model.ConfigRefs, err error) {
var (
allConfs []*model.Config
buildConfs []*model.Config
num int
ok bool
ref *model.ConfigRefs
)
if allConfs, err = s.ConfigsByAppName(appName, env, zone, treeID, model.ConfigEnd); err != nil {
return
}
if buildID != 0 {
if buildConfs, err = s.ConfigsByBuildID(buildID); err != nil {
return
}
}
tmpMap := make(map[string]int)
refs := make(map[string]*model.ConfigRefs)
for _, conf := range allConfs {
if num, ok = tmpMap[conf.Name]; !ok {
ref = new(model.ConfigRefs)
refs[conf.Name] = ref
tmpMap[conf.Name] = num
} else {
ref = refs[conf.Name]
}
if num <= 5 {
ref.Configs = append(ref.Configs, &model.ConfigRef{ID: conf.ID, Mark: conf.Mark})
tmpMap[conf.Name] = num + 1
}
if ref.Ref != nil {
continue
}
for _, bconf := range buildConfs {
if bconf.Name == conf.Name {
ref.Ref = &model.ConfigRef{ID: bconf.ID, Mark: bconf.Mark}
break
}
}
}
for k, v := range refs {
v.Name = k
res = append(res, v)
}
return
}
// ConfigsByBuildID get configs by build ID.
func (s *Service) ConfigsByBuildID(buildID int64) (confs []*model.Config, err error) {
var (
build *model.Build
)
if build, err = s.Build(buildID); err != nil {
return
}
tagID := build.TagID
if tagID == 0 {
return
}
return s.ConfigsByTagID(tagID)
}
// LastBuildConfigs get configs by build ID.
func (s *Service) LastBuildConfigs(appID, buildID int64) (confs []*model.Config, err error) {
var (
tag *model.Tag
ids []int64
id int64
)
if tag, err = s.LastTagByAppBuild(appID, buildID); err != nil {
return
}
confIDs := tag.ConfigIDs
if len(confIDs) == 0 {
return
}
tmpIDs := strings.Split(confIDs, ",")
for _, tmpID := range tmpIDs {
if id, err = strconv.ParseInt(tmpID, 10, 64); err != nil {
log.Error("strconv.ParseInt(%s) error(%v)", tmpID, err)
return
}
ids = append(ids, id)
}
return s.ConfigsByIDs(ids)
}
// LastBuildConfigConfigs get configs by build ID.
func (s *Service) LastBuildConfigConfigs(appID, buildID int64) (confs []*model.Config, err error) {
var (
tag *model.Tag
ids []int64
id int64
tmps []*model.Config
cids []int64
lastIDS []int64
)
if tag, err = s.TagByAppBuild(appID, buildID); err != nil {
return
}
confIDs := tag.ConfigIDs
if len(confIDs) == 0 {
return
}
tmpIDs := strings.Split(confIDs, ",")
for _, tmpID := range tmpIDs {
if id, err = strconv.ParseInt(tmpID, 10, 64); err != nil {
log.Error("strconv.ParseInt(%s) error(%v)", tmpID, err)
return
}
ids = append(ids, id)
}
tmps, err = s.ConfigsByIDs(ids)
if err != nil {
log.Error("LastBuildConfigConfigs ids(%v) error(%v)", ids, err)
return
}
for _, val := range tmps {
cs, err := s.ConfigList(val.AppID, val.Name)
if err == nil {
cids = nil
csloop:
for _, vv := range cs {
for _, vvv := range ids {
if vvv == vv.ID {
continue csloop
}
}
cids = append(cids, vv.ID)
}
if configID, err := s.TagByAppBuildLastConfig(appID, buildID, tag.ID, cids); err == nil {
lastIDS = append(lastIDS, configID)
}
}
}
return s.ConfigsByIDs(lastIDS)
}
// ConfigList ...
func (s *Service) ConfigList(appID int64, name string) (confs []*model.Config, err error) {
if err = s.dao.DB.Where("app_id = ? and name = ?", appID, name).Order("id desc").Find(&confs).Error; err != nil {
log.Error("ConfigList appid(%v) name(%v) error(%v)", appID, name, err)
}
return
}
// ConfigsByTagID get configs by tag id.
func (s *Service) ConfigsByTagID(tagID int64) (confs []*model.Config, err error) {
var (
tag *model.Tag
ids []int64
id int64
)
if tag, err = s.Tag(tagID); err != nil {
return
}
confIDs := tag.ConfigIDs
if len(confIDs) == 0 {
err = ecode.NothingFound
return
}
tmpIDs := strings.Split(confIDs, ",")
for _, tmpID := range tmpIDs {
if id, err = strconv.ParseInt(tmpID, 10, 64); err != nil {
log.Error("strconv.ParseInt(%s) error(%v)", tmpID, err)
return
}
ids = append(ids, id)
}
return s.ConfigsByIDs(ids)
}
//Config get Config by Config ID.
func (s *Service) Config(ID int64) (conf *model.Config, err error) {
conf = new(model.Config)
err = s.dao.DB.First(&conf, ID).Error
return
}
func (s *Service) configIng(name string, appID int64) (conf *model.Config, err error) {
conf = new(model.Config)
if err = s.dao.DB.Select("id").Where("name = ? and app_id = ? and state=?", name, appID, model.ConfigIng).First(&conf).Error; err != nil {
log.Error("configIng(%v) error(%v)", name, err)
if err == sql.ErrNoRows {
err = ecode.NothingFound
}
}
return
}
//Value get value by Config ID.
func (s *Service) Value(ID int64) (conf *model.Config, err error) {
conf = new(model.Config)
if err = s.dao.DB.First(&conf, ID).Error; err != nil {
log.Error("Value() error(%v)", err)
}
return
}
//ConfigsByTree get Config by Config name.
func (s *Service) ConfigsByTree(treeID int64, env, zone, name string) (confs []*model.Config, err error) {
var app *model.App
if app, err = s.AppByTree(treeID, env, zone); err != nil {
return
}
if err = s.dao.DB.Order("id desc").Limit(10).Find(&confs, "name = ? and app_id = ?", name, app.ID).Error; err != nil {
if err == sql.ErrNoRows {
err = nil
}
return
}
return
}
// NamesByAppTree get configs by app name.
func (s *Service) NamesByAppTree(appName, env, zone string, treeID int64) (names []string, err error) {
var (
app *model.App
confs []*model.Config
)
if app, err = s.AppByTree(treeID, env, zone); err != nil {
if err == ecode.NothingFound {
err = s.CreateApp(appName, env, zone, treeID)
return
}
}
if err = s.dao.DB.Select("name").Where("app_id = ?", app.ID).Order("id desc").Group("name").Find(&confs).Error; err != nil {
log.Error("NamesByAppName(%v) error(%v)", app.ID, err)
if err == sql.ErrNoRows {
err = nil
}
return
}
for _, conf := range confs {
names = append(names, conf.Name)
}
return
}
//Diff get value by Config ID.
func (s *Service) Diff(ID, BuildID int64) (data *model.Config, err error) {
var tmpID int64
var idArr []string
conf := new(model.Config)
if err = s.dao.DB.First(&conf, ID).Error; err != nil {
log.Error("Diff() config_id(%v) error(%v)", ID, err)
return
}
config := []*model.Config{}
if err = s.dao.DB.Where("`app_id` = ? and `name` = ? and `state` = 2", conf.AppID, conf.Name).Order("id desc").Find(&config).Error; err != nil {
log.Error("Diff() app_id(%v) name(%v) error(%v)", conf.AppID, conf.Name, err)
return
}
build := &model.Build{}
if err = s.dao.DB.First(build, BuildID).Error; err != nil && err != gorm.ErrRecordNotFound {
log.Error("Diff() build_id(%v) error(%v)", BuildID, err)
return
}
err = nil
if build.ID > 0 {
tag := &model.Tag{}
if err = s.dao.DB.First(tag, build.TagID).Error; err != nil {
log.Error("Diff() tag_id(%v) error(%v)", build.TagID, err)
return
}
idArr = strings.Split(tag.ConfigIDs, ",")
}
if len(idArr) > 0 {
for _, val := range config {
for _, vv := range idArr {
tmpID, _ = strconv.ParseInt(vv, 10, 64)
if tmpID == val.ID {
data = val
return
}
}
}
}
for _, val2 := range config {
if val2.ID < ID {
data = val2
return
}
}
data = conf
return
}
//ConfigDel config is delete.
func (s *Service) ConfigDel(ID int64) (err error) {
conf := &model.Config{}
if err = s.dao.DB.First(conf, ID).Error; err != nil {
log.Error("ConfigDel first id(%v) error(%v)", ID, err)
return
}
confs := []*model.Config{}
if err = s.dao.DB.Where("app_id = ? and name = ?", conf.AppID, conf.Name).Find(&confs).Error; err != nil {
log.Error("ConfigDel find error(%v)", err)
return
}
build := []*model.Build{}
if err = s.dao.DB.Where("app_id = ?", conf.AppID).Find(&build).Error; err != nil {
log.Error("ConfigDel find app_id(%v) error(%v)", conf.AppID, err)
return
}
for _, val := range build {
tag := &model.Tag{}
if err = s.dao.DB.Where("id = ?", val.TagID).First(tag).Error; err != nil {
log.Error("ConfigDel first tag_id(%v) error(%v)", val.TagID, err)
return
}
arr := strings.Split(tag.ConfigIDs, ",")
for _, vv := range arr {
for _, vvv := range confs {
if vv == strconv.FormatInt(vvv.ID, 10) {
err = ecode.NothingFound
return
}
}
}
}
ups := map[string]interface{}{
"is_delete": 1,
"state": 2,
}
if err = s.dao.DB.Model(conf).Where("id = ?", ID).Updates(ups).Error; err != nil {
log.Error("ConfigDel updates error(%v)", err)
}
return
}
//BuildConfigInfos configRefs.
func (s *Service) BuildConfigInfos(appName, env, zone string, buildID, treeID int64) (res map[string][]*model.ConfigRefs, err error) {
var (
allConfs []*model.Config
buildConfs []*model.Config
num int
ok bool
ref *model.ConfigRefs
)
if allConfs, err = s.ConfigsByAppName(appName, env, zone, treeID, model.ConfigEnd); err != nil {
return
}
if buildID != 0 {
if buildConfs, err = s.ConfigsByBuildID(buildID); err != nil {
return
}
}
tmpMap := make(map[string]int)
tmpBuildConfs := make(map[string]map[int64]struct{})
refs := make(map[string]*model.ConfigRefs)
for _, conf := range allConfs {
if num, ok = tmpMap[conf.Name]; !ok {
ref = new(model.ConfigRefs)
refs[conf.Name] = ref
tmpMap[conf.Name] = num
} else {
ref = refs[conf.Name]
}
if num <= 20 {
ref.Configs = append(ref.Configs, &model.ConfigRef{ID: conf.ID, Mark: conf.Mark, IsDelete: conf.IsDelete})
tmpMap[conf.Name] = num + 1
if tmpBuildConfs[conf.Name] == nil {
tmpBuildConfs[conf.Name] = make(map[int64]struct{})
}
tmpBuildConfs[conf.Name][conf.ID] = struct{}{}
} else {
for _, bconf := range buildConfs {
if bconf.Name == conf.Name {
if _, ok = tmpBuildConfs[conf.Name][bconf.ID]; !ok {
tmpBuildConfs[conf.Name][bconf.ID] = struct{}{}
ref.Configs = append(ref.Configs, &model.ConfigRef{ID: bconf.ID, Mark: bconf.Mark, IsDelete: bconf.IsDelete})
}
break
}
}
}
if ref.Ref != nil {
continue
}
for _, bconf := range buildConfs {
if bconf.Name == conf.Name {
ref.Ref = &model.ConfigRef{ID: bconf.ID, Mark: bconf.Mark, IsDelete: bconf.IsDelete}
break
}
}
}
res = make(map[string][]*model.ConfigRefs)
var tp int64
var IsDelete int64
capacity := len(refs)
res["new"] = make([]*model.ConfigRefs, 0, capacity)
res["nothing"] = make([]*model.ConfigRefs, 0, capacity)
res["notused"] = make([]*model.ConfigRefs, 0, capacity)
for k, v := range refs {
v.Name = k
IsDelete = 0
for i, tv := range v.Configs {
if tv.IsDelete == 1 && tv.ID > IsDelete {
IsDelete = tv.ID
v.Configs = v.Configs[:i]
}
}
v.DeleteMAX = IsDelete
if len(v.Configs) == 0 {
continue
}
if v.Ref != nil {
tp = 0
for _, vv := range v.Configs {
if vv.ID > v.Ref.ID {
tp = vv.ID
}
}
if tp > 0 {
res["new"] = append(res["new"], v)
} else {
res["nothing"] = append(res["nothing"], v)
}
} else {
res["notused"] = append(res["notused"], v)
}
}
return
}
// GetConfigs ...
func (s *Service) GetConfigs(ids []int64, name string) (configs []*model.Config, err error) {
if err = s.dao.DB.Where("name = ? AND id in (?)", name, ids).Find(&configs).Error; err != nil {
log.Error("GetConfigs error(%v)", err)
}
return
}
// GetConfig ...
func (s *Service) GetConfig(ids []int64, name string) (config *model.Config, err error) {
config = new(model.Config)
if err = s.dao.DB.Where("name = ? AND id in (?)", name, ids).First(config).Error; err != nil {
log.Error("GetConfigs error(%v)", err)
}
return
}

View File

@ -0,0 +1,68 @@
package service
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_ConfigsByIDs(t *testing.T) {
svr := svr(t)
Convey("should configs by ids", t, func() {
res, err := svr.ConfigsByIDs([]int64{1, 2})
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
}
func TestService_UpdateConfState(t *testing.T) {
svr := svr(t)
Convey("should update state", t, func() {
err := svr.UpdateConfState(2)
So(err, ShouldBeNil)
})
}
func TestService_ConfigsByBuildID(t *testing.T) {
svr := svr(t)
Convey("should get config by build id", t, func() {
res, err := svr.ConfigsByBuildID(1)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
}
func TestService_ConfigsByAppName(t *testing.T) {
svr := svr(t)
Convey("should get configs by app name", t, func() {
res, err := svr.ConfigsByAppName("main.common-arch.msm-service", "dev", "shd", 2888, 0)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
}
func TestService_Configs(t *testing.T) {
svr := svr(t)
Convey("should configs", t, func() {
res, err := svr.Configs("main.account.open-svr-mng", "fat1", "shd", 0, 2888)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
}
func TestService_Diff(t *testing.T) {
svr := svr(t)
Convey("should configs", t, func() {
res, err := svr.Diff(1, 1)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
}
func TestService_Value(t *testing.T) {
svr := svr(t)
Convey("should configs", t, func() {
res, err := svr.Value(1)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
}

View File

@ -0,0 +1,89 @@
package service
import (
"context"
"go-common/app/admin/main/config/model"
"go-common/library/log"
"github.com/jinzhu/gorm"
)
//UpdateForce update force.
func (s *Service) UpdateForce(ctx context.Context, treeID, version int64, env, zone, build, username string, hosts map[string]string) (err error) {
var (
app *model.App
force *model.Force
ups map[string]interface{}
)
if app, err = s.AppByTree(treeID, env, zone); err != nil {
return
}
tx := s.dao.DB.Begin()
for key, val := range hosts {
force = &model.Force{}
force.Hostname = key
force.AppID = app.ID
force.IP = val
force.Operator = username
force.Version = version
if err = s.dao.DB.Where("app_id = ? and hostname = ? and ip = ?", app.ID, key, val).First(&model.Force{}).Error; err != nil {
if err != gorm.ErrRecordNotFound {
tx.Rollback()
log.Error("UpdateForce first error(%v)", err)
return
}
//create
if err = s.dao.DB.Create(force).Error; err != nil {
tx.Rollback()
log.Error("UpdateForce(%s) error(%v)", force, err)
return
}
} else {
//update
ups = map[string]interface{}{
"hostname": key,
"app_id": app.ID,
"ip": val,
"operator": username,
"version": version,
}
if err = s.dao.DB.Model(&model.Force{}).Where("app_id = ? and hostname = ? and ip = ?", app.ID, key, val).Updates(ups).Error; err != nil {
tx.Rollback()
log.Error("UpdateForce(%s) error(%v)", force, err)
return
}
}
}
if err = s.PushForce(ctx, treeID, env, zone, build, version, hosts, 1); err != nil {
tx.Rollback()
return
}
tx.Commit()
return
}
//ClearForce delete force.
func (s *Service) ClearForce(ctx context.Context, treeID int64, env, zone, build string, hosts map[string]string) (err error) {
var (
app *model.App
)
if app, err = s.AppByTree(treeID, env, zone); err != nil {
return
}
tx := s.dao.DB.Begin()
for key, val := range hosts {
if err = s.dao.DB.Where("app_id = ? and hostname = ?", app.ID, key).Delete(model.Force{}).Error; err != nil {
tx.Rollback()
log.Error("ClearForce hostname(%s) ip(%v) error(%v)", key, val, err)
return
}
}
if err = s.PushForce(ctx, treeID, env, zone, build, 0, hosts, 0); err != nil {
tx.Rollback()
return
}
tx.Commit()
return
}

View File

@ -0,0 +1,52 @@
package service
import (
"sync"
"go-common/app/admin/main/config/conf"
"go-common/app/admin/main/config/dao"
confrpc "go-common/app/infra/config/rpc/client"
"go-common/app/admin/main/config/model"
"github.com/jinzhu/gorm"
)
// Service service
type Service struct {
c *conf.Config
// rpcconf config service Rpc
confSvr *confrpc.Service2
dao *dao.Dao
cLock sync.RWMutex
cache map[string]*model.CacheData
//apm gorm
DBApm *gorm.DB
//db gorm
DB *gorm.DB
}
// New new a service
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
confSvr: confrpc.New2(c.ConfSvr),
dao: dao.New(c),
}
s.cache = make(map[string]*model.CacheData)
s.DBApm = s.dao.DBApm
s.DB = s.dao.DB
return
}
// Ping check server ok.
func (s *Service) Ping() (err error) {
return
}
// Close close resource
func (s *Service) Close() {
s.dao.Close()
}

View File

@ -0,0 +1,222 @@
package service
import (
"database/sql"
"strconv"
"strings"
"go-common/app/admin/main/config/model"
"go-common/library/ecode"
"go-common/library/log"
)
// CreateTag create App.
func (s *Service) CreateTag(tag *model.Tag, treeID int64, env, zone string) (err error) {
var app *model.App
if app, err = s.AppByTree(treeID, env, zone); err != nil {
return
}
tag.AppID = app.ID
return s.dao.DB.Create(tag).Error
}
//LastTags get tags by app name.
func (s *Service) LastTags(treeID int64, env, zone, bName string) (tags []*model.Tag, err error) {
var (
app *model.App
build *model.Build
)
if app, err = s.AppByTree(treeID, env, zone); err != nil {
return
}
if build, err = s.BuildByName(app.ID, bName); err != nil {
return
}
if err = s.dao.DB.Where("app_id = ? and build_id = ?", app.ID, build.ID).Order("id desc").Limit(10).Find(&tags).Error; err != nil {
log.Error("Tags(%v) error(%v)", app.ID, err)
if err == sql.ErrNoRows {
err = nil
}
}
return
}
//TagsByBuild get tags by app name.
func (s *Service) TagsByBuild(appName, env, zone, name string, ps, pn, treeID int64) (tagPager *model.TagConfigPager, err error) {
var (
app *model.App
build *model.Build
tags []*model.Tag
confIDs []int64
confs []*model.Config
total int64
)
tagConfigs := make([]*model.TagConfig, 0)
if app, err = s.AppByTree(treeID, env, zone); err != nil {
if err == ecode.NothingFound {
err = s.CreateApp(appName, env, zone, treeID)
return
}
}
if build, err = s.BuildByName(app.ID, name); err != nil {
if err == ecode.NothingFound {
err = nil
}
return
}
if err = s.dao.DB.Where("app_id = ? and build_id =?", app.ID, build.ID).Order("id desc").Offset((pn - 1) * ps).Limit(ps).Find(&tags).Error; err != nil {
log.Error("TagsByBuild() findTags() error(%v)", err)
if err == sql.ErrNoRows {
err = nil
}
return
}
tmp := make(map[int64]struct{})
for _, tag := range tags {
tmpIDs := strings.Split(tag.ConfigIDs, ",")
for _, tmpID := range tmpIDs {
var id int64
if id, err = strconv.ParseInt(tmpID, 10, 64); err != nil {
log.Error("strconv.ParseInt() error(%v)", err)
return
}
if _, ok := tmp[id]; !ok {
tmp[id] = struct{}{}
confIDs = append(confIDs, id)
}
}
}
if confs, err = s.ConfigsByIDs(confIDs); err != nil {
return
}
for _, tag := range tags {
tagConfig := new(model.TagConfig)
tagConfig.Tag = tag
tagConfigs = append(tagConfigs, tagConfig)
tmpIDs := strings.Split(tag.ConfigIDs, ",")
for _, tmpID := range tmpIDs {
var id int64
if id, err = strconv.ParseInt(tmpID, 10, 64); err != nil {
log.Error("strconv.ParseInt() error(%v)", err)
return
}
for _, conf := range confs {
if id != conf.ID { //judge config is in build.
continue
}
tagConfig.Confs = append(tagConfig.Confs, conf)
}
}
}
if err = s.dao.DB.Where("app_id = ? and build_id =?", app.ID, build.ID).Model(&model.Tag{}).Count(&total).Error; err != nil {
log.Error("TagsByBuild() count() error(%v)", err)
return
}
tagPager = &model.TagConfigPager{Ps: ps, Pn: pn, Total: total, Items: tagConfigs}
return
}
//LastTagByAppBuild get tags by app and build.
func (s *Service) LastTagByAppBuild(appID, buildID int64) (tag *model.Tag, err error) {
var (
tags []*model.Tag
)
if err = s.dao.DB.Where("app_id = ? and build_id =?", appID, buildID).Order("id desc").Limit(2).Find(&tags).Error; err != nil {
log.Error("LastTagByAppBuild() error(%v)", err)
if err == sql.ErrNoRows {
err = nil
}
return
}
if len(tags) != 2 {
err = ecode.NothingFound
return
}
return tags[1], nil
}
//Tag get tag by id.
func (s *Service) Tag(ID int64) (tag *model.Tag, err error) {
tag = new(model.Tag)
if err = s.dao.DB.First(&tag, ID).Error; err != nil {
log.Error("Tag(%v) error(%v)", ID, err)
if err == sql.ErrNoRows {
err = ecode.NothingFound
}
}
return
}
//TagByAppBuild ...
func (s *Service) TagByAppBuild(appID, buildID int64) (tag *model.Tag, err error) {
tag = new(model.Tag)
if err = s.dao.DB.Where("app_id = ? and build_id =?", appID, buildID).Order("id desc").First(&tag).Error; err != nil {
log.Error("TagByAppBuild() error(%v)", err)
if err == sql.ErrNoRows {
err = nil
}
return
}
return
}
// TagByAppBuildLastConfig ...
func (s *Service) TagByAppBuildLastConfig(appID, buildID, tagID int64, cids []int64) (configID int64, err error) {
tags := []*model.Tag{}
if err = s.dao.DB.Where("app_id = ? and build_id = ? and id != ?", appID, buildID, tagID).Order("id desc").Find(&tags).Error; err != nil {
log.Error("TagByAppBuildLastConfig() error(%v)", err)
return
}
var id int64
for _, v := range tags {
tmpIDs := strings.Split(v.ConfigIDs, ",")
for _, tmpID := range tmpIDs {
id, err = strconv.ParseInt(tmpID, 10, 64)
if err != nil {
log.Error("strconv.ParseInt(%s) error(%v)", tmpID, err)
continue
}
for _, vv := range cids {
if vv == id {
configID = id
return
}
}
}
}
return
}
//RollBackTag ...
func (s *Service) RollBackTag(tagID int64) (tag *model.Tag, err error) {
tag = &model.Tag{}
row := s.dao.DB.Select("`app_id`,`build_id`,`config_ids`,`force`,`mark`,`operator`").Where("id=?", tagID).Model(&model.Tag{}).Row()
if err = row.Scan(&tag.AppID, &tag.BuildID, &tag.ConfigIDs, &tag.Force, &tag.Mark, &tag.Operator); err != nil {
log.Error("RollBackTag(%v) err(%v)", tagID, err)
if err == sql.ErrNoRows {
err = ecode.NothingFound
}
}
return
}
// GetConfigIDS ...
func (s *Service) GetConfigIDS(tagIDS []int64) (tags []*model.Tag, err error) {
if err = s.dao.DB.Where("id in (?)", tagIDS).Find(&tags).Error; err != nil {
log.Error("GetConfigIDS err(%v)", err)
}
return
}
// LastTasConfigDiff ...
func (s *Service) LastTasConfigDiff(tagID, appID, buildID int64) (tag *model.Tag, err error) {
tag = new(model.Tag)
if err = s.dao.DB.Where("id < ? and app_id = ? and build_id = ?", tagID, appID, buildID).Order("id desc").First(tag).Error; err != nil {
log.Error("LastTasConfigDiff() error(%v)", err)
if err == sql.ErrNoRows {
err = nil
}
return
}
return
}

View File

@ -0,0 +1,35 @@
package service
import (
"context"
"go-common/app/admin/main/config/model"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_TagByID(t *testing.T) {
svr := svr(t)
Convey("should tag by id", t, func() {
res, err := svr.Tag(2)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
}
func TestService_TagsByAppID(t *testing.T) {
svr := svr(t)
Convey("should get tags by app id", t, func() {
res, err := svr.TagsByBuild("main.common-arch.msm-service", "dev", "shd", "server-1", 2, 1, 2888)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
}
func TestService_UpdateTag(t *testing.T) {
svr := svr(t)
Convey("should update tag", t, func() {
err := svr.UpdateTag(context.Background(), 2888, "dev", "shd", "server-1", &model.Tag{ConfigIDs: "212,260", Mark: "test", Operator: "zjx"})
So(err, ShouldBeNil)
})
}

View File

@ -0,0 +1,21 @@
package service
import (
"go-common/app/admin/main/config/model"
"go-common/library/log"
)
// CreateTeam create App.
func (s *Service) CreateTeam(name, env, zone string) error {
app := &model.Team{Name: name, Env: env, Zone: zone}
return s.dao.DB.Create(app).Error
}
//TeamByName get team by Name.
func (s *Service) TeamByName(name, env, zone string) (team *model.Team, err error) {
team = &model.Team{}
if err = s.dao.DB.FirstOrCreate(&team, &model.Team{Name: name, Env: env, Zone: zone}).Error; err != nil {
log.Error("TeamByName() error(%v)", err)
}
return
}