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

21
app/admin/main/bfs/BUILD Normal file
View File

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

View File

@@ -0,0 +1,10 @@
# bfs-admin
## v1.0.2
1. 新增add volume,add free volume,set group status api
## v1.0.1
1. group增加统计信息
## v1.0.0
1. 集群统计信息查询

View File

@@ -0,0 +1,15 @@
# Owner
haoguanwei
liangkai
zhapuyu
# Author
haoguanwei
liangkai
zhapuyu
# Reviewer
haoguanwei
liangkai
zhapuyu
guhao

17
app/admin/main/bfs/OWNERS Normal file
View File

@@ -0,0 +1,17 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- haoguanwei
- liangkai
- zhapuyu
labels:
- admin
- admin/main/bfs
- main
options:
no_parent_owners: true
reviewers:
- guhao
- haoguanwei
- liangkai
- zhapuyu

View File

@@ -0,0 +1,13 @@
# bfs
# 项目简介
1.
# 编译环境
# 依赖包
# 编译执行

View File

@@ -0,0 +1,40 @@
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 = ["test.toml"],
importpath = "go-common/app/admin/main/bfs/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/bfs/conf:go_default_library",
"//app/admin/main/bfs/http:go_default_library",
"//app/admin/main/bfs/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,41 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"go-common/app/admin/main/bfs/conf"
"go-common/app/admin/main/bfs/http"
"go-common/app/admin/main/bfs/service"
"go-common/library/log"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
defer log.Close()
log.Info("bfs admin start")
c := make(chan os.Signal, 1)
srv := service.New(conf.Conf)
http.Init(conf.Conf, srv)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
log.Info("bfs admin singal notify complete")
for {
s := <-c
log.Info("bfs admin get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
srv.Close()
log.Info("bfs admin exit")
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,33 @@
[log]
stdout = true
[zookeepers]
[zookeepers.uat]
rackRoot = "/rack"
volumeRoot = "/volume"
groupRoot = "/group"
pitchRoot = "/pitchfork"
addrs = [
"172.18.33.120:2181",
"172.18.33.121:2181",
"172.18.33.122:2181",
]
timeout = "30s"
[host]
pitchfork = "http://172.22.33.114:2233"
[httpClient]
key = "f6433799dbd88751"
secret = "36f8ddb1806207fe07013ab6a77a3935"
dial = "1s"
timeout = "2s"
keepAlive = "60s"
timer = 1000
[httpClient.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100

View File

@@ -0,0 +1,35 @@
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/bfs/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/conf:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/time: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,96 @@
package conf
import (
"errors"
"flag"
"go-common/library/conf"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
xtime "go-common/library/time"
"github.com/BurntSushi/toml"
)
var (
confPath string
client *conf.Client
// Conf config
Conf = &Config{}
)
// Config .
type Config struct {
// log
Log *log.Config
BM *bm.ServerConfig
Zookeepers map[string]*Zookeeper
Host *Host
HTTPClient *bm.ClientConfig
}
// Host http host
type Host struct {
Pitchfork string
}
// Zookeeper Server&Client settings.
type Zookeeper struct {
RackRoot string
VolumeRoot string
GroupRoot string
PitchRoot string
Addrs []string
Timeout xtime.Duration
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init init conf
func Init() 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 load() != 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,56 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"http.go",
"zk.go",
],
importpath = "go-common/app/admin/main/bfs/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/bfs/conf:go_default_library",
"//app/admin/main/bfs/model:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/metadata:go_default_library",
"//vendor/github.com/samuel/go-zookeeper/zk: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"],
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"http_test.go",
"zk_test.go",
],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/admin/main/bfs/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,48 @@
package dao
import (
"context"
"time"
"go-common/app/admin/main/bfs/conf"
bm "go-common/library/net/http/blademaster"
"github.com/samuel/go-zookeeper/zk"
)
// Dao dao
type Dao struct {
c *conf.Config
zkcs map[string]*zk.Conn
httpCli *bm.Client
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
zkcs := make(map[string]*zk.Conn)
for name, zkCfg := range c.Zookeepers {
zkc, _, err := zk.Connect(zkCfg.Addrs, time.Duration(zkCfg.Timeout))
if err != nil {
panic(err)
}
zkcs[name] = zkc
}
dao = &Dao{
c: c,
zkcs: zkcs,
httpCli: bm.NewClient(c.HTTPClient),
}
return
}
// Ping dao ping
func (d *Dao) Ping(c context.Context) error {
return nil
}
// Close close the resource.
func (d *Dao) Close() {
for _, zkc := range d.zkcs {
zkc.Close()
}
}

View File

@@ -0,0 +1,36 @@
package dao
import (
"flag"
"os"
"testing"
"go-common/app/admin/main/bfs/conf"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("conf_appid", "main.common-arch.bfs-admin")
flag.Set("conf_token", "117c7ca29fdb846f73d96122491bb75d")
flag.Set("conf_env", "uat")
flag.Set("tree_id", "73143")
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/test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
os.Exit(m.Run())
}

View File

@@ -0,0 +1,97 @@
package dao
import (
"context"
"fmt"
"net/url"
"go-common/library/log"
"go-common/library/net/metadata"
)
const (
_addVolume = "/pitchfork/group/add_volume"
_addFreeVolume = "/pitchfork/group/add_free_volume"
_compact = "/pitchfork/group/compact"
_groupStatus = "/pitchfork/group/status"
)
func (d *Dao) addVolumeURI() string {
return d.c.Host.Pitchfork + _addVolume
}
func (d *Dao) addFreeVolumeURI() string {
return d.c.Host.Pitchfork + _addFreeVolume
}
func (d *Dao) compactURI() string {
return d.c.Host.Pitchfork + _compact
}
func (d *Dao) groupStatusURI() string {
return d.c.Host.Pitchfork + _groupStatus
}
// AddVolume add volumes.
func (d *Dao) AddVolume(c context.Context, group string, num int64) (err error) {
var (
params = url.Values{}
uri = d.addVolumeURI()
ip = metadata.String(c, metadata.RemoteIP)
)
params.Set("group", group)
params.Set("num", fmt.Sprint(num))
if err = d.httpCli.Post(c, uri, ip, params, nil); err != nil {
log.Error("add volume error(%v)", err)
}
return
}
// AddFreeVolume add free volume.
func (d *Dao) AddFreeVolume(c context.Context, group, dir string, num int64) (err error) {
var (
params = url.Values{}
uri = d.addFreeVolumeURI()
ip = metadata.String(c, metadata.RemoteIP)
)
params.Set("group", group)
params.Set("idir", dir)
params.Set("bdir", dir)
params.Set("num", fmt.Sprint(num))
if err = d.httpCli.Post(c, uri, ip, params, nil); err != nil {
log.Error("add free volume error(%v)", err)
}
return
}
// Compact compact store disk by group.
func (d *Dao) Compact(c context.Context, group string, vid int64) (err error) {
var (
params = url.Values{}
uri = d.compactURI()
ip = metadata.String(c, metadata.RemoteIP)
)
params.Set("group", group)
if vid > 0 {
params.Set("vid", fmt.Sprint(vid))
}
if err = d.httpCli.Post(c, uri, ip, params, nil); err != nil {
log.Error("compact group error(%v)", err)
}
return
}
// SetGroupStatus set store status by group id.
func (d *Dao) SetGroupStatus(c context.Context, group, status string) (err error) {
var (
params = url.Values{}
uri = d.groupStatusURI()
ip = metadata.String(c, metadata.RemoteIP)
)
params.Set("group", group)
params.Set("status", status)
if err = d.httpCli.Post(c, uri, ip, params, nil); err != nil {
log.Error("set group status error(%v)", err)
}
return
}

View File

@@ -0,0 +1,121 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoaddVolumeURI(t *testing.T) {
convey.Convey("addVolumeURI", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := d.addVolumeURI()
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoaddFreeVolumeURI(t *testing.T) {
convey.Convey("addFreeVolumeURI", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := d.addFreeVolumeURI()
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaocompactURI(t *testing.T) {
convey.Convey("compactURI", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := d.compactURI()
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaogroupStatusURI(t *testing.T) {
convey.Convey("groupStatusURI", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := d.groupStatusURI()
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
// func TestDaoAddVolume(t *testing.T) {
// convey.Convey("AddVolume", t, func(ctx convey.C) {
// var (
// c = context.Background()
// group = "1"
// num = int64(1)
// )
// ctx.Convey("add one volume to group 1", func(ctx convey.C) {
// err := d.AddVolume(c, group, num)
// if strings.Contains(err.Error(), "store response status code:7001") {
// t.Log("store have no free volume")
// err = nil // NOTE ignore error
// }
// ctx.Convey("Then err should be nil.", func(ctx convey.C) {
// ctx.So(err, convey.ShouldBeNil)
// })
// })
// })
// }
// func TestDaoAddFreeVolume(t *testing.T) {
// convey.Convey("AddFreeVolume", t, func(ctx convey.C) {
// var (
// c = context.Background()
// group = "1"
// dir = "/mnt/storage00/bfsdata"
// num = int64(1)
// )
// ctx.Convey("When everything goes positive", func(ctx convey.C) {
// err := d.AddFreeVolume(c, group, dir, num)
// ctx.Convey("Then err should be nil.", func(ctx convey.C) {
// ctx.So(err, convey.ShouldBeNil)
// })
// })
// })
// }
func TestDaoCompact(t *testing.T) {
convey.Convey("Compact", t, func(ctx convey.C) {
var (
c = context.Background()
group = "1"
vid = int64(1)
)
ctx.Convey("compact group:1 vid:1", func(ctx convey.C) {
err := d.Compact(c, group, vid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoSetGroupStatus(t *testing.T) {
convey.Convey("SetGroupStatus", t, func(ctx convey.C) {
var (
c = context.Background()
group = "1"
status = "health"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.SetGroupStatus(c, group, status)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,127 @@
package dao
import (
"encoding/json"
"fmt"
"path"
"go-common/app/admin/main/bfs/model"
"go-common/library/log"
)
// Racks get rack infos.
func (d *Dao) Racks(cluster string) (racks map[string]*model.Rack, err error) {
zkConn, ok := d.zkcs[cluster]
if !ok {
err = fmt.Errorf("not support cluster:%s", cluster)
return
}
root := d.c.Zookeepers[cluster].RackRoot
// get all rocks
rackNames, _, err := zkConn.Children(root)
if err != nil {
log.Error("get from:%s children error(%v)", root, err)
return
}
racks = make(map[string]*model.Rack)
for _, rackName := range rackNames {
// get all the store
rackPath := path.Join(root, rackName)
storeNames, _, err := zkConn.Children(rackPath)
if err != nil {
log.Error("cannot get /rack/%s info error(%v)", rackName, err)
continue
}
log.Info("rack:%s got store:%v", rackName, storeNames)
rack := &model.Rack{Stores: make(map[string]*model.Store)}
racks[rackName] = rack
// get the volume of store
for _, storeName := range storeNames {
storePath := path.Join(rackPath, storeName)
storeMeta, _, err := zkConn.Get(storePath)
if err != nil {
log.Error("cannot get from:%s info error(%v)", storePath, err)
continue
}
var data model.Store
if err = json.Unmarshal(storeMeta, &data); err != nil {
log.Error("cannot Unmarshal %s info get from:%s error(%v)", storeMeta, storePath, err)
continue
}
volumes, _, err := zkConn.Children(storePath)
if err != nil {
log.Error("cannot list %s info error(%v)", storePath, err)
continue
}
data.Volumes = volumes
log.Info("rack:%s store:%s got volume:%v", rackName, storeName, volumes)
rack.Stores[storeName] = &data
}
}
return
}
// Volumes get volume infos.
func (d *Dao) Volumes(cluster string) (volumes map[string]*model.VolumeState, err error) {
zkConn, ok := d.zkcs[cluster]
if !ok {
err = fmt.Errorf("not support cluster:%s", cluster)
return
}
root := d.c.Zookeepers[cluster].VolumeRoot
// get all volumes
volumeIDs, _, err := zkConn.Children(root)
if err != nil {
log.Error("cannot get from:%s info error(%v)", root, err)
return
}
log.Info("got volumes: %s", volumeIDs)
volumes = make(map[string]*model.VolumeState)
for _, id := range volumeIDs {
// get all the volumes
volumePath := path.Join(root, id)
volumeState, _, err := zkConn.Get(volumePath)
if err != nil {
log.Error("cannot get %s info error(%v)", volumePath, err)
continue
}
var data model.VolumeState
if err := json.Unmarshal(volumeState, &data); err != nil {
log.Error("cannot Unmarshal %s info get from:%s error(%v)", volumeState, volumePath, err)
continue
}
volumes[id] = &data
}
return
}
// Groups get group infos.
func (d *Dao) Groups(cluster string) (groups map[string]*model.Group, err error) {
zkConn, ok := d.zkcs[cluster]
if !ok {
err = fmt.Errorf("not support cluster:%s", cluster)
return
}
root := d.c.Zookeepers[cluster].GroupRoot
// get all groups
groupNames, _, err := zkConn.Children(root)
if err != nil {
log.Error("cannot get from:%s info error(%v)", root, err)
return
}
log.Info("got groups: %s", groupNames)
groups = make(map[string]*model.Group)
for _, groupName := range groupNames {
// get all the volumes
groupPath := path.Join(root, groupName)
storeNames, _, err := zkConn.Children(groupPath)
if err != nil {
log.Error("cannot get from:%s info error(%v)", groupPath, err)
continue
}
groups[groupName] = &model.Group{
Stores: storeNames,
}
}
return
}

View File

@@ -0,0 +1,52 @@
package dao
import (
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoRacks(t *testing.T) {
convey.Convey("Racks", t, func(ctx convey.C) {
var (
cluster = "uat"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
racks, err := d.Racks(cluster)
ctx.Convey("Then err should be nil.racks should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(racks, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoVolumes(t *testing.T) {
convey.Convey("Volumes", t, func(ctx convey.C) {
var (
cluster = "uat"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
volumes, err := d.Volumes(cluster)
ctx.Convey("Then err should be nil.volumes should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(volumes, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoGroups(t *testing.T) {
convey.Convey("Groups", t, func(ctx convey.C) {
var (
cluster = "uat"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
groups, err := d.Groups(cluster)
ctx.Convey("Then err should be nil.groups should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(groups, convey.ShouldNotBeNil)
})
})
})
}

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 = [
"bfs.go",
"http.go",
],
importpath = "go-common/app/admin/main/bfs/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/bfs/conf:go_default_library",
"//app/admin/main/bfs/model:go_default_library",
"//app/admin/main/bfs/service:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster: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,75 @@
package http
import (
"go-common/app/admin/main/bfs/model"
bm "go-common/library/net/http/blademaster"
)
func clusters(c *bm.Context) {
clusters := srv.Clusters(c)
c.JSON(clusters, nil)
}
func bfsTotal(c *bm.Context) {
arg := &model.ArgCluster{}
if err := c.Bind(arg); err != nil {
return
}
c.JSON(srv.Total(c, arg))
}
func rackMeta(c *bm.Context) {
arg := &model.ArgCluster{}
if err := c.Bind(arg); err != nil {
return
}
c.JSON(srv.Racks(c, arg))
}
func groupMeta(c *bm.Context) {
arg := &model.ArgCluster{}
if err := c.Bind(arg); err != nil {
return
}
c.JSON(srv.Groups(c, arg))
}
func volumeMeta(c *bm.Context) {
arg := &model.ArgCluster{}
if err := c.Bind(arg); err != nil {
return
}
c.JSON(srv.Volumes(c, arg))
}
func addVolume(c *bm.Context) {
arg := new(model.ArgAddVolume)
if err := c.Bind(arg); err != nil {
return
}
c.JSON(nil, srv.AddVolume(c, arg))
}
func addFreeVolume(c *bm.Context) {
arg := new(model.ArgAddFreeVolume)
if err := c.Bind(arg); err != nil {
return
}
c.JSON(nil, srv.AddFreeVolume(c, arg))
}
func compact(c *bm.Context) {
arg := new(model.ArgCompact)
if err := c.Bind(arg); err != nil {
return
}
c.JSON(nil, srv.Compact(c, arg))
}
func setGroupStatus(c *bm.Context) {
arg := new(model.ArgGroupStatus)
if err := c.Bind(arg); err != nil {
return
}
c.JSON(nil, srv.SetGroupStatus(c, arg))
}

View File

@@ -0,0 +1,54 @@
package http
import (
"net/http"
"go-common/app/admin/main/bfs/conf"
"go-common/app/admin/main/bfs/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
var (
srv *service.Service
)
// Init init
func Init(c *conf.Config, s *service.Service) {
srv = s
engine := bm.DefaultServer(c.BM)
router(engine)
if err := engine.Start(); err != nil {
log.Error("engine.Start error(%v)", err)
panic(err)
}
}
func router(e *bm.Engine) {
e.Ping(ping)
e.Register(register)
group := e.Group("/x/admin/bfs")
{
group.GET("/clusters", clusters)
group.GET("/total", bfsTotal)
group.GET("/rack", rackMeta)
group.GET("/volume", volumeMeta)
group.GET("/group", groupMeta)
group.POST("/group/compact", compact)
group.POST("/group/status", setGroupStatus)
group.POST("/group/add_volume", addVolume)
group.POST("/group/add_free_volume", addFreeVolume)
}
}
func ping(c *bm.Context) {
if err := srv.Ping(c); err != nil {
log.Error("bfs ping error(%v)", err)
c.Error = err
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}
func register(c *bm.Context) {
c.JSON(map[string]interface{}{}, nil)
}

View File

@@ -0,0 +1,33 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"arg.go",
"group.go",
"store.go",
"volume.go",
],
importpath = "go-common/app/admin/main/bfs/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
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,55 @@
package model
// ArgCluster .
type ArgCluster struct {
Cluster string `form:"cluster" validate:"required"`
}
// ArgAddVolume add volume
type ArgAddVolume struct {
Group string `form:"group" validate:"required"`
Num int64 `form:"num" validate:"required"`
}
// ArgAddFreeVolume add free volume
type ArgAddFreeVolume struct {
Group string `form:"group" validate:"required"`
Dir string `form:"dir" validate:"required"`
Num int64 `form:"num" validate:"required"`
}
// ArgCompact group compact
type ArgCompact struct {
Group string `form:"group" validate:"required"`
Vid int64 `form:"vid"`
}
// ArgGroupStatus group status
type ArgGroupStatus struct {
Group string `form:"group" validate:"required"`
Status string `form:"status" validate:"required"`
}
// RespRack .
type RespRack struct {
Racks map[string]*Rack `json:"racks"`
}
// RespGroup .
type RespGroup struct {
Groups map[string]*Group `json:"groups"`
}
// RespVolume .
type RespVolume struct {
Volumes map[string]*VolumeState `json:"volumes"`
}
// RespTotal .
type RespTotal struct {
Space int64 `json:"space"`
FreeSpace int64 `json:"free_space"`
Groups int64 `json:"groups"`
Stores int64 `json:"stores"`
Volumes int64 `json:"volumes"`
}

View File

@@ -0,0 +1,12 @@
package model
// Group .
type Group struct {
Stores []string `json:"stores"`
StoreDatas map[string]*Store `json:"store_datas"`
Total struct {
Space int64 `json:"space"`
FreeSpace int64 `json:"free_space"`
Volumes int64 `json:"volumes"`
} `json:"total"`
}

View File

@@ -0,0 +1,64 @@
package model
// zookeeper save the store meta data.
//
// /rack -- rack root path
// |
// /rack-a -------- --------- /rack-b -- rack node path
// |
// /store-a -------- /store-b -- store node path (data: {"stat":"localhost:6061","admin":"localhost:6063","api":"localhost:6062","status":0})
// | |
// /volume-1 - - /volume-4 volume node path (data: /tmp/block_1,/tmp/block_1.idx,1)
// /volume-2 - - /volume-5
// /volume-3 - - /volume-6
// Store status const.
const (
// bit
StoreStatusEnableBit = 31
StoreStatusReadBit = 0
StoreStatusWriteBit = 1
StoreStatusSyncBit = 2
// status
StoreStatusInit = 0 // 0
StoreStatusEnable = (1 << StoreStatusEnableBit) // 2147483648
StoreStatusRead = StoreStatusEnable | (1 << StoreStatusReadBit) // 2147483649
StoreStatusWrite = StoreStatusEnable | (1 << StoreStatusWriteBit) // 2147483650
StoreStatusHealth = StoreStatusRead | StoreStatusWrite // 2147483651
StoreStatusSync = StoreStatusEnable | (1 << StoreStatusSyncBit) // 2147483652
StoreStatusFail = StoreStatusEnable // 2147483648
)
// Rack get all store and volume.
type Rack struct {
Stores map[string]*Store `json:"stores"`
}
// Store meta data.
type Store struct {
Stat string `json:"stat"`
Admin string `json:"admin"`
API string `json:"api"`
ID string `json:"id"`
Rack string `json:"rack"`
Status int `json:"status"`
States struct {
Init bool `json:"init"`
Enable bool `json:"enable"`
Read bool `json:"read"`
Write bool `json:"write"`
Sync bool `json:"sync"`
Fail bool `json:"fail"`
} `json:"states"`
Volumes []string `json:"volumes"`
}
// ParseStates parse states.
func (s *Store) ParseStates() {
s.States.Init = s.Status == StoreStatusInit
s.States.Enable = s.Status&StoreStatusEnable == StoreStatusEnable
s.States.Read = s.Status&StoreStatusRead == StoreStatusRead
s.States.Write = s.Status&StoreStatusWrite == StoreStatusWrite
s.States.Sync = s.Status&StoreStatusSync == StoreStatusSync
s.States.Fail = s.Status == StoreStatusFail
}

View File

@@ -0,0 +1,21 @@
package model
// type Volumes struct {
// Vol map[string]*VolumeState
// }
// VolumeState for zk /volume stat
type VolumeState struct {
TotalWriteProcessed uint64 `json:"total_write_processed"`
TotalWriteDelay uint64 `json:"total_write_delay"`
FreeSpace uint32 `json:"free_space"`
Dir string `json:"dir"`
}
// func (v *Volumes) GetVolumeState(id string) *VolumeState {
// vs, ok := v.Vol[id]
// if !ok {
// return nil
// }
// return vs
// }

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 = [
"bfs.go",
"service.go",
],
importpath = "go-common/app/admin/main/bfs/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/bfs/conf:go_default_library",
"//app/admin/main/bfs/dao:go_default_library",
"//app/admin/main/bfs/model:go_default_library",
"//library/ecode: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,135 @@
package service
import (
"context"
"go-common/app/admin/main/bfs/model"
"go-common/library/ecode"
)
// Total .
func (s *Service) Total(c context.Context, arg *model.ArgCluster) (resp *model.RespTotal, err error) {
volumes, err := s.Volumes(c, arg)
if err != nil {
return
}
num := int64(len(volumes.Volumes))
var fs int64
for _, volume := range volumes.Volumes {
fs += int64(volume.FreeSpace)
}
fs = (fs * 8) / 1024 / 1024 / 1024 // GB
// groups
groups, err := s.d.Groups(arg.Cluster)
if err != nil {
return
}
// stores
racks, err := s.d.Racks(arg.Cluster)
if err != nil {
return
}
var stores int64
for _, rack := range racks {
stores += int64(len(rack.Stores))
}
resp = &model.RespTotal{
Space: 32 * num,
FreeSpace: fs,
Groups: int64(len(groups)),
Stores: stores,
Volumes: num,
}
return
}
// Racks .
func (s *Service) Racks(c context.Context, arg *model.ArgCluster) (resp *model.RespRack, err error) {
racks, err := s.d.Racks(arg.Cluster)
if err != nil {
return
}
for _, rack := range racks {
for _, store := range rack.Stores {
store.ParseStates()
}
}
resp = &model.RespRack{Racks: racks}
return
}
// Groups .
func (s *Service) Groups(c context.Context, arg *model.ArgCluster) (resp *model.RespGroup, err error) {
groups, err := s.d.Groups(arg.Cluster)
if err != nil {
return
}
racks, err := s.Racks(c, arg)
if err != nil {
return
}
volumes, err := s.Volumes(c, arg)
if err != nil {
return
}
for _, group := range groups {
group.StoreDatas = make(map[string]*model.Store)
for _, rack := range racks.Racks {
for sname, store := range rack.Stores {
for _, name := range group.Stores {
if sname == name {
group.StoreDatas[name] = store
}
}
}
}
for _, store := range group.StoreDatas {
num := int64(len(store.Volumes))
var fs int64
for _, volume := range store.Volumes {
fs += int64(volumes.Volumes[volume].FreeSpace)
}
fs = (fs * 8) / 1024 / 1024 / 1024 // GB
group.Total.Space = 32 * num
group.Total.FreeSpace = fs
group.Total.Volumes = num
break
}
}
resp = &model.RespGroup{Groups: groups}
return
}
// Volumes .
func (s *Service) Volumes(c context.Context, arg *model.ArgCluster) (resp *model.RespVolume, err error) {
volumes, err := s.d.Volumes(arg.Cluster)
if err != nil {
return
}
resp = &model.RespVolume{Volumes: volumes}
return
}
// AddVolume add volume.
func (s *Service) AddVolume(c context.Context, arg *model.ArgAddVolume) (err error) {
return s.d.AddVolume(c, arg.Group, arg.Num)
}
// AddFreeVolume add free volume.
func (s *Service) AddFreeVolume(c context.Context, arg *model.ArgAddFreeVolume) (err error) {
return s.d.AddFreeVolume(c, arg.Group, arg.Dir, arg.Num)
}
// Compact compact store.
func (s *Service) Compact(c context.Context, arg *model.ArgCompact) (err error) {
return s.d.Compact(c, arg.Group, arg.Vid)
}
// SetGroupStatus set group status(read,write,sync,health).
func (s *Service) SetGroupStatus(c context.Context, arg *model.ArgGroupStatus) (err error) {
if arg.Status != "read" && arg.Status != "write" && arg.Status != "sync" && arg.Status != "health" {
err = ecode.RequestErr
return
}
return s.d.SetGroupStatus(c, arg.Group, arg.Status)
}

View File

@@ -0,0 +1,41 @@
package service
import (
"context"
"go-common/app/admin/main/bfs/conf"
"go-common/app/admin/main/bfs/dao"
)
// Service struct
type Service struct {
c *conf.Config
d *dao.Dao
}
// New init
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
d: dao.New(c),
}
return s
}
// Clusters .
func (s *Service) Clusters(c context.Context) (clusters []string) {
for name := range s.c.Zookeepers {
clusters = append(clusters, name)
}
return
}
// Ping .
func (s *Service) Ping(c context.Context) (err error) {
return s.d.Ping(c)
}
// Close .
func (s *Service) Close() {
s.d.Close()
}