写此小程序的原因是,研究小米的open-falcon的时候用他们的插件管理感觉不适合我们公司,就自动动手写了个基于服务端的版本控制的,命令下载时基于http的所以也比较方便.
代码写的比较紧急有点乱,先这样吧,回头用起来再调优一下.
先发下执行的结果:
开始解析cfg.Json配置文件.解析配置文件成功: {gyc D:/code/20151117/src/ssh true27.0.0.1:2789 http://127.0.0.1:1789/pkg/ :1789 true 60}开始初始化本地命令...初始化本地命令完成...[{clIEnt.go D:\code151117\src\ssh\clIEnt.go 256034f7168a3937b124ad89227f0ea9 {sshd D:\code151117\src\ssh\sshd af7ec72582c33ecd97dc5abf0e747e92}]D:/code/20151117/src/ssh2015-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.exetmp/Test01.exe D:/code/20151117/src/ssh/Test01.exetmp/fmt.exe D:/code/20151117/src/ssh/fmt.exe2015-11-18 17:46:29 开始执行Test01.exe2015-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 CST2015-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 mainimport ( "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",""}} //这些内容命令版本多的时候可以用数据库来控制,不多就随便自己搞搞吧,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 newimport ( "enCoding/Json" "fmt" "io/IoUtil" "net" "os" "time")func GetVersion(group string) []RemoteVersionInfo { var List []RemoteVersionInfoThis: 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",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",err) time.Sleep(60e9) goto This } return List}init_var.go
package newimport ( "enCoding/Json" "fmt" "io/IoUtil" "os" "path/filepath" "strings" "sync")var Cmdpath stringvar config ConfigJsonvar Lock *sync.RWMutex = new(sync.RWMutex)var CmdFuncMap *FuncMapfunc 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",err) os.Exit(1) } fmt.Println("初始化本地命令完成...")}run.go
package newimport ( "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",v.Path) { return } var g chan bool = make(chan bool,1) E := &ExecCmdInfo{r.name,g} CmdFuncMap.Map[r.name] = E go E.Run()}func (this *ExecCmdInfo) Run() { fmt.Printf("%s 开始执行%s\n",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",string(b)) } time.Sleep(time.Second * time.Duration(this.Interval)) } fmt.Printf("%s 退出执行%s\n",this.name)}
type.go
package newimport "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 newimport ( "crypto/md5" "fmt" "io" "net/http" "os" "strings" "time")var LocalCmdList []LoadCmdBaseInfofunc 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",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",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",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",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 mainimport ( "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}总结
以上是内存溢出为你收集整理的分享一个小东西,自动到指定的地方下载动态版本的命令,然后根据配置循环执行调用.全部内容,希望文章能够帮你解决分享一个小东西,自动到指定的地方下载动态版本的命令,然后根据配置循环执行调用.所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)