昨天项目组中的一个兄弟,问我我们远程发布是怎么做的,说现在他在维护好几个项目,每个项目需要部署的时候,要把编译好的文件拖过去,然后重启tomcat,本来很简单的事情,但是很浪费时间,问我有没有办法脚本化
他自己的机器是windows的,scp命令可以通过安装解决,但是要远程关闭、开启tomcat,却不是脚本解决的事情,应该通过ssh解决,然后又需要放在其他机器上拿过去用,我就直接给提用golang实现了一个,代码如下:
package mainimport ( "bufio" "flag" "fmt" "io" "io/ioutil" "log" "net" "os" "path/filepath" "strings" "golang.org/x/crypto/ssh")var ( auth string publicKey string passwd string user string ip_port string dpath string spath string tomcatPath string killName string)func main() { log.SetFlags(log.Lshortfile | log.Ltime | log.Ldate) flag.Parse() //read config file myConfig := new(Config) myConfig.InitConfig("./config.conf") auth = myConfig.Read("test", "auth") publicKey = myConfig.Read("test", "publicKey") passwd = myConfig.Read("test", "passwd") user = myConfig.Read("test", "user") ip_port = myConfig.Read("test", "ip_port") dpath = myConfig.Read("test", "dpath") spath = myConfig.Read("test", "spath") tomcatPath = myConfig.Read("test", "tomcatPath") killName = myConfig.Read("test", "killName") //目标文件 // File, err := os.Open(spath) // if err != nil { // fmt.Println("打开文件失败:", err) // os.Exit(1) // } // info, _ := File.Stat() // defer File.Close() var Client *ssh.Client var err error if strings.EqualFold(auth, "password") { Client, err = dail(user, passwd, ip_port) } else { Client, err = dailPublic(user, publicKey, ip_port) } if err != nil { fmt.Printf("连接%s失败.\n", err) } defer Client.Close() // scp(Client, File, info.Size(), dpath) session, err := Client.NewSession() defer session.Close() if err != nil { fmt.Println("创建Session失败:", err) return } //遍历并复制 err = filepath.Walk(spath, func(path string, f os.FileInfo, err error) error { if f == nil { return err } if f.IsDir() { newpath := strings.Replace(path, spath, dpath, len(spath)) dname := strings.Replace(newpath, "\\", "/", -1) mkdir(Client, dname) return nil } //不是路径的,就复制文件 File, err := os.Open(path) if err != nil { fmt.Println("打开文件失败:", err) os.Exit(1) } info, _ := File.Stat() defer File.Close() newpath := strings.Replace(path, spath, dpath, len(spath)) dname := strings.Replace(newpath, "\\", "/", -1) fmt.Printf("dname %s\n", dname) scp(Client, File, info.Size(), dname) return nil }) //停止tomcat kill(Client, killName) //启动tomcat start(Client, tomcatPath)}func scp(client *ssh.Client, File io.Reader, size int64, path string) { filename := filepath.Base(path) dirname := strings.Replace(filepath.Dir(path), "\\", "/", -1) session, err := client.NewSession() if err != nil { fmt.Println("创建Session失败:", err) return } go func() { w, _ := session.StdinPipe() fmt.Fprintln(w, "C0644", size, filename) io.CopyN(w, File, size) fmt.Fprint(w, "\x00") w.Close() }() fmt.Println("dir name is %s", dirname) if err := session.Run(fmt.Sprintf("/usr/bin/scp -qrt %s/", dirname)); err != nil { fmt.Println("执行scp命令失败:", err) if err != nil { session.Close() return } } else { fmt.Printf("%s 发送成功.\n") session.Close() } if session, err = client.NewSession(); err == nil { defer session.Close() buf, err := session.Output(fmt.Sprintf("/usr/bin/md5sum %s", path)) if err != nil { fmt.Println("检查md5失败:", err) return } fmt.Printf("MD5:\n%s\n", string(buf)) }}func mkdir(client *ssh.Client, path string) { fmt.Printf("create path %s\n", path) session, err := client.NewSession() if err != nil { fmt.Println("创建Session失败:", err) return } session.Run(fmt.Sprintf("[ ! -d %s ] && mkdir %s", path, path)) defer session.Close()}func kill(client *ssh.Client, path string) { fmt.Printf("kill tomcat path is %s\n", path) session, err := client.NewSession() if err != nil { fmt.Println("创建Session失败:", err) return } session.Run(fmt.Sprintf("kill -9 `ps -ef|grep %s|grep -v 'grep'|awk '{print $2}'`", path)) defer session.Close()}func start(client *ssh.Client, path string) { fmt.Printf("start tomcat path is %s\n", path) session, err := client.NewSession() if err != nil { fmt.Println("创建Session失败:", err) return } mt := fmt.Sprintf("source /etc/profile && %s/startup.sh", path) fmt.Println(mt) session.Stdout = os.Stdout session.Stderr = os.Stderr err = session.Run(mt) if err != nil { fmt.Println(err) } defer session.Close()}func dail(user, password, ip_port string) (*ssh.Client, error) { PassWd := []ssh.AuthMethod{ssh.Password(password)} Conf := ssh.ClientConfig{User: user, Auth: PassWd, HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil }, } return ssh.Dial("tcp", ip_port, &Conf)}func dailPublic(user, publicKey, ip_port string) (*ssh.Client, error) { if strings.HasSuffix(publicKey, ".pub") { publicKey = strings.TrimSuffix(publicKey, ".pub") } signer, err := readPrivateKey(publicKey) if err != nil { fmt.Println(err) } PassWd := []ssh.AuthMethod{ssh.PublicKeys(signer)} Conf := ssh.ClientConfig{User: user, Auth: PassWd, HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil }, } return ssh.Dial("tcp", ip_port, &Conf)}func readPrivateKey(path string) (ssh.Signer, error) { f, err := os.Open(path) if err != nil { return nil, err } defer f.Close() b, err := ioutil.ReadAll(f) if err != nil { return nil, err } return ssh.ParsePrivateKey(b)}//配置type Config struct { Mymap map[string]string strcet string}func (c *Config) InitConfig(path string) { c.Mymap = make(map[string]string) f, err := os.Open(path) if err != nil { panic(err) } defer f.Close() r := bufio.NewReader(f) for { b, _, err := r.ReadLine() if err != nil { if err == io.EOF { break } panic(err) } s := strings.TrimSpace(string(b)) //fmt.Println(s) if strings.Index(s, "#") == 0 { continue } n1 := strings.Index(s, "[") n2 := strings.LastIndex(s, "]") if n1 > -1 && n2 > -1 && n2 > n1+1 { c.strcet = strings.TrimSpace(s[n1+1 : n2]) continue } if len(c.strcet) == 0 { continue } index := strings.Index(s, "=") if index < 0 { continue } frist := strings.TrimSpace(s[:index]) if len(frist) == 0 { continue } second := strings.TrimSpace(s[index+1:]) pos := strings.Index(second, "\t#") if pos > -1 { second = second[0:pos] } pos = strings.Index(second, " #") if pos > -1 { second = second[0:pos] } pos = strings.Index(second, "\t//") if pos > -1 { second = second[0:pos] } pos = strings.Index(second, " //") if pos > -1 { second = second[0:pos] } if len(second) == 0 { continue } key := c.strcet + "." + frist c.Mymap[key] = strings.TrimSpace(second) }}func (c Config) Read(node, key string) string { key = node + "." + key v, found := c.Mymap[key] if !found { return "" } return v}
使用配置文件指定参数:
[test]auth = key #password or key,现在只做了password和rsa公钥publicKey = C:\Users\issuser\Desktop\key\id_rsapasswd = xxxxuser = xxxxip_port = xx.xx.xx.xx:22dpath = /work/ovuems/dapingAgent/webapps/dapingAgent/WEB-INF/classes/com #目标路径spath = D:\ideaSpace\dapingAgent\target\classes\com #本地路径killName = /work/ovuems/dapingAgent/bin #和下面的tomcat路径一致,防止需要杀掉多个进程的时候,用于灵活处理tomcatPath = /work/ovuems/dapingAgent/bin #tomcat路径,到bin这一级
说明:
该项目只做了4件事
1、连接ssh
2、复制本地编译好的class文件到远端(递归方式)
3、kill掉tomcat
4、启动tomcat
发现问题,启动tomcat的时候,启动不了,打印出来的消息为:
Neither the JAVA_HOME nor the JRE_HOME environment variable is defined At least one of these environment variable is needed to run this program
但是在机器上面查找,发现环境变量已经配置,没有办法,执行之前加上了 source /etc/profile予以解决