分享一个小东西,自动到指定的地方下载动态版本的命令,然后根据配置循环执行调用.
2015-11-18 17:37
806 查看
写此小程序的原因是,研究小米的open-falcon的时候用他们的插件管理感觉不适合我们公司,就自动动手写了个基于服务端的版本控制的,命令下载时基于http的所以也比较方便.
代码写的比较紧急有点乱,先这样吧,回头用起来再调优一下.
先发下执行的结果:
废话不多说直接上源码:
服务端简单的代码小例子:
server.go
下面是每个实例的代码.
我得用目录是:new
getServerVersion.go
type.go
usefunc.go
下面是入口函数:
main.go
代码写的比较紧急有点乱,先这样吧,回头用起来再调优一下.
先发下执行的结果:
开始解析cfg.json配置文件.解析配置文件成功: {gyc D:/code/20151117/src/ssh true 27.0.0.1:2789 http://127.0.0.1:1789/pkg/ :1789 true 60} 开始初始化本地命令... 初始化本地命令完成... [{client.go D:\code\20151117\src\ssh\client.go 256034f7168a3937b124ad89227f0ea9 {sshd D:\code\20151117\src\ssh\sshd af7ec72582c33ecd97dc5abf0e747e92}] D:/code/20151117/src/ssh 2015-11-18 17:46:29获取服务端版本! {fmt.exe fe117de8dbf1a460e66d2a799bde17cf 30 } 2015-11-18 17:46:29开始验证本地! {Test01.exe e6a54c6f478d93828cb635e97d710ba6 30 } 2015-11-18 17:46:29开始验证本地! 开始下载:http://127.0.0.1:1789/pkg/fmt.exe 开始下载:http://127.0.0.1:1789/pkg/Test01.exe tmp/Test01.exe D:/code/20151117/src/ssh/Test01.exe tmp/fmt.exe D:/code/20151117/src/ssh/fmt.exe 2015-11-18 17:46:29 开始执行Test01.exe 2015-11-18 17:46:29 开始执行fmt.exe 命令Test01.exe结果:This is Test01 命令fmt.exe结果:2015-11-18 17:46:29.3219182 +0800 CST 命令Test01.exe结果:This is Test01 命令fmt.exe结果:2015-11-18 17:46:59.3536359 +0800 CST 2015-11-18 17:47:29获取服务端版本! 清除过期的命令:Test01.exe. {fmt.exe fe117de8dbf1a460e66d2a799bde17cf 30 } 2015-11-18 17:47:29 退出执行Test01.exe 命令fmt.exe结果:2015-11-18 17:47:29.3933541 +0800 CST
废话不多说直接上源码:
服务端简单的代码小例子:
server.go
package main import ( "encoding/json" "fmt" "net" ) type versionInfo struct { Name string `json:name` Md5 string `json:md5` Interval int `json:interval` Args string `json:args` } //测试代码.服务端可以自己按需求定义. func main() { var list []versionInfo list = []versionInfo{{"fmt.exe", "fe117de8dbf1a460e66d2a799bde17cf", 30, ""}, {"Test01.exe", "e6a54c6f478d93828cb635e97d710ba6", 30, ""}} //这些内容命令版本多的时候可以用数据库来控制,不多就随便自己搞搞吧, b, err := json.Marshal(list) if err != nil { fmt.Printf("初始话数据失败:%s\n", err) return } lis, err := net.Listen("tcp", ":2789") if err != nil { fmt.Printf("初始化服务端失败:%s\n", err) return } defer lis.Close() for { con, err := lis.Accept() if err != nil { fmt.Println(err) continue } go func(con net.Conn) { defer con.Close() buf := make([]byte, 512) n, err := con.Read(buf) if err != nil { fmt.Println(err) return } if string(buf[:n]) != "gyc" { //这里的值需要根据自己来控制,比如每次收到的请求到数据库查询来取版本返回. con.Write([]byte("No this group!")) return } con.Write(b) }(con) } }
下面是每个实例的代码.
我得用目录是:new
getServerVersion.go
package new import ( "encoding/json" "fmt" "io/ioutil" "net" "os" "time" ) func GetVersion(group string) []RemoteVersionInfo { var list []RemoteVersionInfo This: con, err := net.Dial("tcp", Getconfig().GetVersionServer) if err != nil { fmt.Printf("%s 从%s获取命令版本信息错误: %s\n", GetNowTime(), Getconfig().GetVersionServer, err) time.Sleep(60e9) goto This } defer con.Close() _, err = con.Write([]byte(group)) if err != nil { fmt.Printf("发送%s的version请求失败:%s\n", group, err) time.Sleep(60e9) goto This } buf, err := ioutil.ReadAll(con) if err != nil { fmt.Printf("%s 获取命令版本信息错误: %s\n", GetNowTime(), err) time.Sleep(60e9) goto This } if string(buf) == "No this group!" { fmt.Printf("版本库找不到此分组:%s\n", group) os.Exit(1) } err = json.Unmarshal(buf, &list) if err != nil { fmt.Printf("%s 解析获取的版本消息错误: %s\n", GetNowTime(), err) time.Sleep(60e9) goto This } return list }init_var.go
package new import ( "encoding/json" "fmt" "io/ioutil" "os" "path/filepath" "strings" "sync" ) var CmdPath string var config ConfigJson var Lock *sync.RWMutex = new(sync.RWMutex) var CmdFuncMap *FuncMap func Getconfig() *ConfigJson { Lock.RLock() defer Lock.RUnlock() return &config } func init() { err := parseConfig("cfg.json") if err != nil { os.Exit(1) } info, err := os.Lstat(Getconfig().CmdDirPath) CmdPath = Getconfig().CmdDirPath if err != nil || !info.IsDir() { fmt.Printf("校验目录失败: %s \n", err) err := initDir() if err != nil { os.Exit(1) } fmt.Printf("使用默认配置做根目录: %s\n", CmdPath) } initBaseCmdInfo(CmdPath) CmdFuncMap = &FuncMap{make(map[string]*ExecCmdInfo), new(sync.RWMutex)} } func parseConfig(configPath string) error { fmt.Printf("开始解析%s配置文件.", configPath) b, err := ioutil.ReadFile(configPath) if err != nil { fmt.Printf("读取配置文件出错: %s\n", err) return err } err = json.Unmarshal(b, &config) if err != nil { fmt.Printf("解析配置出错: %s\n", err) return err } fmt.Println("解析配置文件成功: ", config) return nil } func initDir() error { fmt.Println("初始化默认路径.") p, err := os.Getwd() if err != nil { fmt.Printf("获取当前目录错误: %s\n", err) return err } info, err := os.Lstat("cmd") if err == nil && info.IsDir() { CmdPath = strings.Replace(p, `\`, `/`, 20) + `/cmd` return nil } err = os.Mkdir("cmd", 0644) if err != nil { fmt.Printf("初始化文件夹失败: %s\n", err) return err } CmdPath = strings.Replace(p, `\`, `/`, 20) + `/cmd` return nil } func initBaseCmdInfo(path string) { fmt.Println("开始初始化本地命令...") err := filepath.Walk(path, run) if err != nil { fmt.Printf("%s 初始化命令列表出错: %s", GetNowTime(), err) os.Exit(1) } fmt.Println("初始化本地命令完成...") }run.go
package new import ( "fmt" "os/exec" "strings" "time" ) func R() { if Getconfig().Debug { fmt.Printf("%s获取服务端版本!\n", GetNowTime()) } list := GetVersion(Getconfig().Group) CmdFuncMap.Lock.Lock() for k, m := range CmdFuncMap.Map { if !Contain(k, list) { fmt.Printf("清除过期的命令:%s.\n", k) m.Exit <- true delete(CmdFuncMap.Map, k) } } CmdFuncMap.Lock.Unlock() for _, cmdVersion := range list { fmt.Println(cmdVersion) CmdFuncMap.Lock.RLock() k, ok := CmdFuncMap.Map[cmdVersion.Name] CmdFuncMap.Lock.RUnlock() if ok { if k.M5 == cmdVersion.Md5 { continue } loadcmdbaseinfo := LoadCmdBaseInfo{k.Name, k.Path, k.M5} go Update(loadcmdbaseinfo, cmdVersion) continue } cmd := index(cmdVersion) if cmd != nil { CmdFuncMap.Lock.Lock() CmdFuncMap.Map[cmd.Name] = cmd go cmd.Run() CmdFuncMap.Lock.Unlock() } } } func index(r RemoteVersionInfo) *ExecCmdInfo { if Getconfig().Debug { fmt.Printf("%s开始验证本地!\n", GetNowTime()) } var g chan bool = make(chan bool, 1) for _, v := range LocalCmdList { if v.Name == r.Name && v.Md5 == r.Md5 { return &ExecCmdInfo{r.Name, v.Path, r.Md5, r.Interval, split(r.Args), g} } } v := LoadCmdBaseInfo{r.Name, fmt.Sprintf("%s/%s", CmdPath, r.Name), r.Md5} go Update(v, r) return nil } func Update(v LoadCmdBaseInfo, r RemoteVersionInfo) { var url string = Getconfig().GetCmdAddr if !strings.HasSuffix(url, "/") { url = url + "/" } url = url + r.Name str := Download(r.Name, url) if str != strings.ToLower(r.Md5) { return } CmdFuncMap.Lock.Lock() defer CmdFuncMap.Lock.Unlock() k, ok := CmdFuncMap.Map[r.Name] if ok { k.Exit <- true time.Sleep(1e9) } if !MoveFile(fmt.Sprintf("%s/%s", "tmp", r.Name), v.Path) { return } var g chan bool = make(chan bool, 1) E := &ExecCmdInfo{r.Name, v.Path, r.Md5, r.Interval, split(r.Args), g} CmdFuncMap.Map[r.Name] = E go E.Run() } func (this *ExecCmdInfo) Run() { fmt.Printf("%s 开始执行%s\n", GetNowTime(), this.Name) var exit bool = false go func() { b := <-this.Exit if b { exit = b } }() for { if exit { break } cmd := exec.Command(this.Path, this.Args...) //err := cmd.Run() b, err := cmd.Output() if err != nil { fmt.Printf("执行%s出错:%s\n", this.Name, err) } if Getconfig().Debug { fmt.Printf("命令%s结果:%s", this.Name, string(b)) } time.Sleep(time.Second * time.Duration(this.Interval)) } fmt.Printf("%s 退出执行%s\n", GetNowTime(), this.Name) }
type.go
package new import "sync" type ConfigJson struct { Group string `json:group` CmdDirPath string `json:cmddirpath` AutoUpdate bool `json:autoupdate` GetVersionServer string `json:vetversionserver` GetCmdAddr string `json:getcmdaddr` Listen string `json:listen` Debug bool `json:debug` Update int `json:update` } type RemoteVersionInfo struct { Name string `json:name` Md5 string `json:md5` Interval int `json:interval` Args string `json:args` } type ExecCmdInfo struct { Name string Path string M5 string Interval int Args []string Exit chan bool } type LoadCmdBaseInfo struct { Name string Path string Md5 string } type FuncMap struct { Map map[string]*ExecCmdInfo Lock *sync.RWMutex }
usefunc.go
package new import ( "crypto/md5" "fmt" "io" "net/http" "os" "strings" "time" ) var LocalCmdList []LoadCmdBaseInfo func run(path string, info os.FileInfo, err error) error { if err != nil { return err } if info.IsDir() { return nil } m5 := Md5(path) if m5 != "" { LocalCmdList = append(LocalCmdList, LoadCmdBaseInfo{info.Name(), path, m5}) } return nil } func Md5(path string) string { File, err := os.Open(path) if err != nil { fmt.Printf("%s 校验%s的md5出错:%s\n", GetNowTime(), path, err) return "" } M := md5.New() io.Copy(M, File) b := M.Sum([]byte{}) return fmt.Sprintf("%x", b) } func GetNowTime() string { return time.Now().Format("2006-01-02 15:04:05") } func Download(name, url string) string { resp, err := http.Get(url) fmt.Printf("开始下载:%s\n", url) if err != nil || resp.StatusCode != 200 { fmt.Printf("%s 下载%s出错: %s\n", GetNowTime(), url, err) return "" } os.Mkdir("tmp", 0644) defer resp.Body.Close() name = "tmp/" + name File, err := os.Create(name) if err != nil { fmt.Printf("%s 创建文件%s错误: %s\n", GetNowTime(), name, err) return "" } io.Copy(File, resp.Body) File.Close() return Md5(name) } func split(str string) []string { var l []string list := strings.Split(str, " ") for _, v := range list { if len(v) == 0 { continue } if strings.Contains(v, " ") { list := strings.Split(v, " ") for _, v := range list { if len(v) == 0 { continue } l = append(l, v) } continue } l = append(l, v) } return l } func MoveFile(s, d string) bool { fmt.Println(s, d) sFile, err := os.Open(s) if err != nil { fmt.Printf("移动文件%s出错:%s\n", s, err) return false } defer sFile.Close() dFile, err := os.Create(d) if err != nil { fmt.Printf(" 新建文件%s出错:%s\n", s, err) return false } defer dFile.Close() io.Copy(dFile, sFile) return true } func Contain(k string, list []RemoteVersionInfo) bool { for _, v := range list { if k == v.Name { return true } } return false }
下面是入口函数:
main.go
package main import ( "fmt" "new" "time" ) func main() { j := new.Getconfig() go func() { for { new.R() time.Sleep(time.Second * time.Duration(j.Update)) } }() select {} }下面是:实例的配置文件:cfg.json
{"Group":"gyc",
"CmdDirPath":"D:/code/201508221",
"AutoUpdate":true,
"GetVersionServer":"127.0.0.1:2789",
"GetCmdAddr":"http://127.0.0.1:1789/pkg/",
"Listen":":1789",
"Debug":true,
"Update":60}
相关文章推荐
- Go 语言 Channel 实现原理精要
- Go语言将支持Android
- SQLSERVER 中GO的作用详解
- Golang实现的聊天程序服务端和客户端代码分享
- Go语言入门教程之Arrays、Slices、Maps、Range操作简明总结
- 在Go语言程序中使用gojson来解析JSON格式文件
- 举例详解Go语言中os库的常用函数用法
- Go语言中函数的参数传递与调用的基本方法
- GO语言异常处理机制panic和recover分析
- 深入解析Go语言的io.ioutil标准库使用
- GO语言的IO方法实例小结
- Go语言的os包中常用函数初步归纳
- go语言执行windows下命令行的方法
- Go语言计算两个经度和纬度之间距离的方法
- Go语言排序与接口实例分析
- Go语言导出内容到Excel的方法
- go语言实现sqrt的方法
- Go语言中数组的基本用法演示
- Go语言MessageBox用法实例
- Go语言判断指定文件是否存在的方法