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,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
}