You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
514 lines
14 KiB
514 lines
14 KiB
package service |
|
|
|
import ( |
|
"bytes" |
|
"context" |
|
"fmt" |
|
"strconv" |
|
|
|
"go-common/app/admin/main/cache/model" |
|
"go-common/library/ecode" |
|
|
|
"github.com/BurntSushi/toml" |
|
) |
|
|
|
// OpsClusterNames . |
|
func (s *Service) OpsClusterNames(c context.Context, arg *model.OverlordReq) (resp *model.OverlordResp, err error) { |
|
resp = &model.OverlordResp{} |
|
if arg.Type == "memcache" { |
|
for _, opsmc := range s.opsMcs { |
|
resp.Names = append(resp.Names, opsmc.Labels.Name) |
|
} |
|
} else if arg.Type == "redis" { |
|
for _, opsrd := range s.opsRds { |
|
if opsrd.Type == "redis_standalone" { |
|
resp.Names = append(resp.Names, opsrd.Labels.Name) |
|
} |
|
} |
|
} else if arg.Type == "redis_cluster" { |
|
for _, opsrd := range s.opsRds { |
|
if opsrd.Type == "redis_cluster" { |
|
resp.Names = append(resp.Names, opsrd.Labels.Name) |
|
} |
|
} |
|
} else { |
|
err = fmt.Errorf("unsupport type:%s", arg.Type) |
|
} |
|
return |
|
} |
|
|
|
// OpsClusterNodes . |
|
func (s *Service) OpsClusterNodes(c context.Context, arg *model.OverlordReq) (resp *model.OverlordResp, err error) { |
|
resp = &model.OverlordResp{} |
|
if arg.Type == "memcache" { |
|
for _, opsmc := range s.opsMcs { |
|
if arg.Name == opsmc.Labels.Name { |
|
resp.Addrs = opsmc.Targets |
|
return |
|
} |
|
} |
|
} else if arg.Type == "redis" { |
|
for _, opsrd := range s.opsRds { |
|
if opsrd.Type == "redis_standalone" && arg.Name == opsrd.Labels.Name { |
|
resp.Addrs = opsrd.Targets |
|
return |
|
} |
|
} |
|
} else if arg.Type == "redis_cluster" { |
|
for _, opsrd := range s.opsRds { |
|
if opsrd.Type == "redis_cluster" && arg.Name == opsrd.Labels.Name { |
|
resp.Addrs = opsrd.Targets |
|
return |
|
} |
|
} |
|
} else { |
|
err = fmt.Errorf("unsupport type:%s", arg.Type) |
|
} |
|
return |
|
} |
|
|
|
// ImportOpsCluster . |
|
func (s *Service) ImportOpsCluster(c context.Context, arg *model.OverlordReq) (resp *model.EmpResp, err error) { |
|
exist := 0 |
|
if err = s.dao.DB.Model(&model.OverlordCluster{}).Where("name=?", arg.Name).Count(&exist).Error; err != nil { |
|
return |
|
} |
|
if exist > 0 { |
|
return |
|
} |
|
var targets []string |
|
if arg.Type == "memcache" { |
|
for _, opsmc := range s.opsMcs { |
|
if arg.Name == opsmc.Labels.Name { |
|
targets = opsmc.Targets |
|
break |
|
} |
|
} |
|
} else if arg.Type == "redis" { |
|
for _, opsrd := range s.opsRds { |
|
if opsrd.Type == "redis_standalone" && arg.Name == opsrd.Labels.Name { |
|
targets = opsrd.Targets |
|
break |
|
} |
|
} |
|
} else if arg.Type == "redis_cluster" { |
|
for _, opsrd := range s.opsRds { |
|
if opsrd.Type == "redis_cluster" && arg.Name == opsrd.Labels.Name { |
|
targets = opsrd.Targets |
|
break |
|
} |
|
} |
|
} else { |
|
err = fmt.Errorf("unsupport type:%s", arg.Type) |
|
return |
|
} |
|
port := 0 |
|
if err = s.dao.DB.Model(&model.OverlordCluster{}).Where("type=?", arg.Type).Count(&port).Error; err != nil { |
|
return |
|
} |
|
if arg.Type == "memcache" { |
|
port += 11211 |
|
} else { |
|
port += 26379 |
|
} |
|
tranDB := s.dao.DB.Begin() |
|
oc := &model.OverlordCluster{ |
|
Name: arg.Name, |
|
Type: arg.Type, |
|
Zone: arg.Zone, |
|
HashMethod: "fnv1a_64", |
|
HashDistribution: "ketama", |
|
HashTag: "", |
|
ListenProto: "tcp", |
|
ListenAddr: "0.0.0.0:" + strconv.Itoa(port), |
|
DailTimeout: 1000, |
|
ReadTimeout: 1000, |
|
WriteTimeout: 1000, |
|
NodeConn: 2, |
|
PingFailLimit: 3, |
|
PingAutoEject: true, |
|
} |
|
if err = tranDB.Create(oc).Error; err != nil { |
|
tranDB.Rollback() |
|
return |
|
} |
|
for i, target := range targets { |
|
ocn := &model.OverlordNode{ |
|
Cid: oc.ID, |
|
Alias: arg.Name + strconv.Itoa(i+1), |
|
Addr: target, |
|
Weight: 1, |
|
} |
|
if err = tranDB.Create(ocn).Error; err != nil { |
|
tranDB.Rollback() |
|
return |
|
} |
|
} |
|
err = tranDB.Commit().Error |
|
return |
|
} |
|
|
|
// OverlordClusters . |
|
func (s *Service) OverlordClusters(c context.Context, arg *model.OverlordReq) (resp *model.OverlordResp, err error) { |
|
resp = &model.OverlordResp{} |
|
if arg.Name != "" { |
|
err = s.dao.DB.Where("zone=? AND type=? AND name like ?", arg.Zone, arg.Type, "%"+arg.Name+"%").Order("id desc").Offset((arg.PN - 1) * arg.PS).Limit(arg.PS).Find(&resp.Clusters).Error |
|
s.dao.DB.Model(&model.OverlordCluster{}).Where("zone=? AND type=? AND name like ?", arg.Zone, arg.Type, arg.Name).Count(&resp.Total) |
|
} else { |
|
err = s.dao.DB.Where("zone=? AND type=?", arg.Zone, arg.Type).Order("id desc").Offset((arg.PN - 1) * arg.PS).Limit(arg.PS).Find(&resp.Clusters).Error |
|
s.dao.DB.Model(&model.OverlordCluster{}).Where("zone=? AND type=?", arg.Zone, arg.Type).Count(&resp.Total) |
|
} |
|
if err != nil { |
|
return |
|
} |
|
for _, cluster := range resp.Clusters { |
|
var ens *model.OverlordResp |
|
if ens, err = s.ExistOverlordNodes(c, &model.OverlordReq{Name: cluster.Name}); err != nil { |
|
return |
|
} |
|
cluster.Nodes = ens.Nodes |
|
} |
|
return |
|
} |
|
|
|
// ExistOverlordNodes . |
|
func (s *Service) ExistOverlordNodes(c context.Context, arg *model.OverlordReq) (resp *model.OverlordResp, err error) { |
|
cluster := &model.OverlordCluster{} |
|
if err = s.dao.DB.Model(cluster).Where("name=?", arg.Name).First(cluster).Error; err != nil { |
|
fmt.Printf("get cluster err %v\n", err) |
|
return |
|
} |
|
if cluster.ID == 0 { |
|
err = fmt.Errorf("cluster not exist:%s", arg.Name) |
|
return |
|
} |
|
var exists []*model.OverlordNode |
|
if err = s.dao.DB.Where("cid=?", cluster.ID).Order("id").Find(&exists).Error; err != nil { |
|
return |
|
} |
|
resp = &model.OverlordResp{} |
|
resp.Cluster = cluster |
|
resp.Nodes = exists |
|
return |
|
} |
|
|
|
// NotExistOverlordAddrs . |
|
func (s *Service) NotExistOverlordAddrs(c context.Context, arg *model.OverlordReq) (resp *model.OverlordResp, err error) { |
|
cluster := &model.OverlordCluster{} |
|
if err = s.dao.DB.Model(cluster).Where("name=?", arg.Name).First(cluster).Error; err != nil { |
|
return |
|
} |
|
if cluster.ID == 0 { |
|
err = fmt.Errorf("cluster not exist:%s", arg.Name) |
|
return |
|
} |
|
var targets []string |
|
tp := arg.Type |
|
if tp == "memcache" { |
|
for _, opsmc := range s.opsMcs { |
|
if arg.Name == opsmc.Labels.Name { |
|
targets = opsmc.Targets |
|
break |
|
} |
|
} |
|
} else if tp == "redis" { |
|
for _, opsrd := range s.opsRds { |
|
if arg.Name == opsrd.Labels.Name { |
|
targets = opsrd.Targets |
|
if opsrd.Type == "redis_cluster" { |
|
tp = "redis_cluster" |
|
} |
|
break |
|
} |
|
} |
|
} else { |
|
err = fmt.Errorf("unsupport type:%s", arg.Type) |
|
return |
|
} |
|
var exists []*model.OverlordNode |
|
if err = s.dao.DB.Where("cid=?", cluster.ID).Order("id").Find(&exists).Error; err != nil { |
|
return |
|
} |
|
resp = &model.OverlordResp{} |
|
NEXT: |
|
for _, target := range targets { |
|
for _, exist := range exists { |
|
if target == exist.Addr { |
|
continue NEXT |
|
} |
|
} |
|
resp.Addrs = append(resp.Addrs, target) |
|
} |
|
return |
|
} |
|
|
|
// ImportOpsNode . |
|
func (s *Service) ImportOpsNode(c context.Context, arg *model.OverlordReq) (resp *model.EmpResp, err error) { |
|
nen, err := s.NotExistOverlordAddrs(c, arg) |
|
if err != nil { |
|
return |
|
} |
|
en, err := s.ExistOverlordNodes(c, arg) |
|
if err != nil { |
|
return |
|
} |
|
i := len(en.Nodes) |
|
tranDB := s.dao.DB.Begin() |
|
for _, target := range nen.Addrs { |
|
ocn := &model.OverlordNode{ |
|
Cid: en.Cluster.ID, |
|
Alias: arg.Name + strconv.Itoa(i+1), |
|
Addr: target, |
|
Weight: 1, |
|
} |
|
if err = tranDB.Create(ocn).Error; err != nil { |
|
tranDB.Rollback() |
|
return |
|
} |
|
i++ |
|
} |
|
err = tranDB.Commit().Error |
|
return |
|
} |
|
|
|
// ReplaceOpsNode . |
|
func (s *Service) ReplaceOpsNode(c context.Context, arg *model.OverlordReq) (resp *model.EmpResp, err error) { |
|
nen, err := s.NotExistOverlordAddrs(c, arg) |
|
if err != nil { |
|
return |
|
} |
|
if len(nen.Addrs) == 0 { |
|
err = fmt.Errorf("cluster have not new node:%s", arg.Name) |
|
return |
|
} |
|
en, err := s.ExistOverlordNodes(c, arg) |
|
if err != nil { |
|
return |
|
} |
|
for _, n := range en.Nodes { |
|
if n.Alias != arg.Alias && n.Addr == arg.Addr { |
|
err = fmt.Errorf("cluster:%s node:%s used by other node:%s ", arg.Name, arg.Addr, n.Alias) |
|
return |
|
} |
|
} |
|
node := &model.OverlordNode{} |
|
if err = s.dao.DB.Model(node).Where("cid=? AND alias=?", en.Cluster.ID, arg.Alias).First(node).Error; err != nil { |
|
return |
|
} |
|
if node.Addr == arg.Addr { |
|
return |
|
} |
|
err = s.dao.DB.Model(node).Where("alias=? AND addr=?", node.Alias, node.Addr).Update("addr", arg.Addr).Error |
|
return |
|
} |
|
|
|
// DelOverlordCluster . |
|
func (s *Service) DelOverlordCluster(c context.Context, arg *model.OverlordReq) (resp *model.EmpResp, err error) { |
|
en, err := s.ExistOverlordNodes(c, arg) |
|
if err != nil { |
|
return |
|
} |
|
if err = s.dao.DB.Delete(en.Cluster).Error; err != nil { |
|
return |
|
} |
|
err = s.dao.DB.Delete(&model.OverlordNode{}, "cid=?", en.Cluster.ID).Error |
|
return |
|
} |
|
|
|
// DelOverlordNode . |
|
func (s *Service) DelOverlordNode(c context.Context, arg *model.OverlordReq) (resp *model.EmpResp, err error) { |
|
en, err := s.ExistOverlordNodes(c, arg) |
|
if err != nil { |
|
return |
|
} |
|
err = s.dao.DB.Delete(&model.OverlordNode{}, "cid=? AND alias=? AND addr=?", en.Cluster.ID, arg.Alias, arg.Addr).Error |
|
return |
|
} |
|
|
|
// OverlordAppClusters . |
|
func (s *Service) OverlordAppClusters(c context.Context, arg *model.OverlordReq) (resp *model.OverlordResp, err error) { |
|
appids, err := s.appids(c, arg.Cookie, arg.AppID) |
|
if err != nil { |
|
err = ecode.AccessDenied |
|
return |
|
} |
|
resp = &model.OverlordResp{} |
|
if len(appids) <= 1 { |
|
err = s.dao.DB.Where("app_id like ?", "%"+arg.AppID+"%").Order("id desc").Offset((arg.PN - 1) * arg.PS).Limit(arg.PS).Find(&resp.Apps).Error |
|
s.dao.DB.Model(&model.OverlordApp{}).Where("app_id like ?", arg.AppID).Count(&resp.Total) |
|
} else if len(appids) > 1 { |
|
err = s.dao.DB.Where("app_id in (?)", appids).Order("id desc").Offset((arg.PN - 1) * arg.PS).Limit(arg.PS).Find(&resp.Apps).Error |
|
s.dao.DB.Model(&model.OverlordApp{}).Where("app_id in (?)", appids).Count(&resp.Total) |
|
} |
|
if err != nil || len(resp.Apps) == 0 { |
|
return |
|
} |
|
var cids []int64 |
|
for _, app := range resp.Apps { |
|
cids = append(cids, app.Cid) |
|
} |
|
var clusters []*model.OverlordCluster |
|
if err = s.dao.DB.Find(&clusters, "id in (?)", cids).Error; err != nil { |
|
return |
|
} |
|
for _, cluster := range clusters { |
|
var ens *model.OverlordResp |
|
if ens, err = s.ExistOverlordNodes(c, &model.OverlordReq{Name: cluster.Name}); err != nil { |
|
return |
|
} |
|
cluster.Nodes = ens.Nodes |
|
for _, app := range resp.Apps { |
|
if cluster.ID == app.Cid { |
|
app.Cluster = cluster |
|
} |
|
} |
|
} |
|
if len(appids) <= 1 { |
|
// 当使用appid查询时,填充overlord-mesos的数据 |
|
if ocs, err := s.dao.OverlordClusters(c, "", arg.AppID); err == nil { |
|
clusters = append(clusters, ocs...) |
|
} |
|
} |
|
return |
|
} |
|
|
|
// OverlordAppCanBindClusters . |
|
func (s *Service) OverlordAppCanBindClusters(c context.Context, arg *model.OverlordReq) (resp *model.OverlordResp, err error) { |
|
resp = &model.OverlordResp{} |
|
err = s.dao.DB.Where("zone=? AND type=?", arg.Zone, arg.Type).Find(&resp.Clusters).Error |
|
if err != nil { |
|
return |
|
} |
|
for _, cluster := range resp.Clusters { |
|
resp.Names = append(resp.Names, cluster.Name) |
|
} |
|
resp.Clusters = nil |
|
return |
|
} |
|
|
|
// OverlordAppClusterBind . |
|
func (s *Service) OverlordAppClusterBind(c context.Context, arg *model.OverlordReq) (resp *model.EmpResp, err error) { |
|
treeid, err := s.treeid(c, arg.Cookie, arg.AppID) |
|
if err != nil || treeid == 0 { |
|
err = ecode.AccessDenied |
|
return |
|
} |
|
cluster := &model.OverlordCluster{} |
|
if err = s.dao.DB.Model(cluster).Where("zone=? AND type=? AND name=?", arg.Zone, arg.Type, arg.Name).First(cluster).Error; err != nil { |
|
return |
|
} |
|
app := &model.OverlordApp{ |
|
TreeID: treeid, |
|
AppID: arg.AppID, |
|
Cid: cluster.ID, |
|
} |
|
err = s.dao.DB.Create(app).Error |
|
return |
|
} |
|
|
|
// OverlordAppClusterDel . |
|
func (s *Service) OverlordAppClusterDel(c context.Context, arg *model.OverlordReq) (resp *model.EmpResp, err error) { |
|
treeid, err := s.treeid(c, arg.Cookie, arg.AppID) |
|
if err != nil || treeid == 0 { |
|
err = ecode.AccessDenied |
|
return |
|
} |
|
cluster := &model.OverlordCluster{} |
|
if err = s.dao.DB.Model(cluster).Where("zone=? AND type=? AND name=?", arg.Zone, arg.Type, arg.Name).First(cluster).Error; err != nil { |
|
return |
|
} |
|
app := &model.OverlordApp{} |
|
if err = s.dao.DB.Model(app).Where("app_id=? AND cid=?", arg.AppID, cluster.ID).First(app).Error; err != nil { |
|
return |
|
} |
|
err = s.dao.DB.Table(app.TableName()).Delete(app).Error |
|
return |
|
} |
|
|
|
// OverlordAppAppIDs . |
|
func (s *Service) OverlordAppAppIDs(c context.Context, arg *model.OverlordReq) (resp *model.OverlordResp, err error) { |
|
appids, err := s.appids(c, arg.Cookie, "") |
|
if err != nil { |
|
err = ecode.AccessDenied |
|
return |
|
} |
|
resp = &model.OverlordResp{} |
|
resp.AppIDs = appids |
|
return |
|
} |
|
|
|
// OverlordToml return a toml file of cluster infos. |
|
func (s *Service) OverlordToml(c context.Context, arg *model.OverlordReq) (resp []byte, err error) { |
|
var apps []*model.OverlordApp |
|
if err = s.dao.DB.Where("app_id=?", arg.AppID).Find(&apps).Error; err != nil { |
|
return |
|
} |
|
var cids []int64 |
|
for _, app := range apps { |
|
cids = append(cids, app.Cid) |
|
} |
|
var clusters []*model.OverlordCluster |
|
// TODO(felix): 待都走overlord-mesos后干掉 |
|
if err = s.dao.DB.Where("zone=? AND id in (?)", arg.Zone, cids).Find(&clusters).Error; err != nil { |
|
return |
|
} |
|
if len(clusters) == 0 { |
|
// TODO(felix): 待都走overlord-mesos后干掉 |
|
if err = s.dao.DB.Where("zone='sh001' AND id in (?)", cids).Find(&clusters).Error; err != nil { |
|
return |
|
} |
|
} |
|
var ocs []*model.OverlordCluster |
|
if ocs, err = s.dao.OverlordClusters(c, arg.Zone, arg.AppID); err == nil { |
|
if len(ocs) == 0 { |
|
ocs, err = s.dao.OverlordClusters(c, "sh001", arg.AppID) |
|
} |
|
if len(ocs) > 0 { |
|
clusters = append(clusters, ocs...) |
|
} |
|
} |
|
t := struct { |
|
Clusters []*model.OverlordToml `toml:"clusters"` |
|
}{} |
|
for _, cluster := range clusters { |
|
ot := &model.OverlordToml{ |
|
Name: cluster.Name, |
|
Type: cluster.Type, |
|
HashMethod: cluster.HashMethod, |
|
HashDistribution: cluster.HashDistribution, |
|
HashTag: cluster.HashTag, |
|
ListenProto: cluster.ListenProto, |
|
ListenAddr: cluster.ListenAddr, |
|
DailTimeout: cluster.DailTimeout, |
|
ReadTimeout: cluster.ReadTimeout, |
|
WriteTimeout: cluster.WriteTimeout, |
|
NodeConn: cluster.NodeConn, |
|
PingFailLimit: cluster.PingFailLimit, |
|
PingAutoEject: cluster.PingAutoEject, |
|
} |
|
var nodes []*model.OverlordNode |
|
if len(cluster.Nodes) == 0 { |
|
if err = s.dao.DB.Where("cid=?", cluster.ID).Order("id").Find(&nodes).Error; err != nil { |
|
return |
|
} |
|
} else { |
|
nodes = cluster.Nodes |
|
} |
|
var servers []string |
|
for _, node := range nodes { |
|
var server string |
|
if cluster.Type == "redis_cluster" { |
|
server = node.Addr |
|
} else { |
|
server = fmt.Sprintf("%s:%d %s", node.Addr, node.Weight, node.Alias) |
|
} |
|
servers = append(servers, server) |
|
} |
|
ot.Servers = servers |
|
t.Clusters = append(t.Clusters, ot) |
|
} |
|
buf := bytes.NewBuffer(resp) |
|
err = toml.NewEncoder(buf).Encode(t) |
|
resp = buf.Bytes() |
|
return |
|
}
|
|
|