强化go get命令

强化go get命令

  • 利用ssh包,编写一个再window上类试运行go get的命令,将项目同时拉取到远程服务器的小项目

  • 大概思路
    • 读取配置文件,获取能够连接远程服务器的配置信息
    • 创建远程服务器的session
    • 解析命令,通过不同的信息,拉取不同的包
  • 源代码

// conf.go
package main


import (
	"log"
	"os"
	"path/filepath"
	"gopkg.in/gcfg.v1"
	valid "github.com/asaskevich/govalidator"
)

// Config 配置信息
type Config struct{
	// Servers 多台服务器
	Servers map[string]*Server
}

// Server 服务器
type Server struct{
	User string
	Port int
	Host string
	Password string
	GoAbPath string    // (利用which go 执行golang命令绝对路径获取)
}

var (
	// Conf 全局配置变量
	Conf = new(Config)
	// HomePath 项目位置
	HomePath string 
)

func init(){
	log.SetFlags(log.Ldate | log.Lshortfile)
	var err error
	HomePath,err = filepath.Abs(filepath.Dir(os.Args[0]))
	if err!=nil{
		log.Fatal(err)
	}
}

// ReadConf 读取配置文件 
func ReadConf(){

	confPath := HomePath + "/conf.ini"

	err := gcfg.ReadFileInto(Conf,confPath)
	if err!=nil{
		log.Fatal(err)
	}

	if Conf == nil {
		log.Fatal("conf is nil")
	}

	for _,value := range Conf.Servers{
		if !valid.IsIPv4(value.Host){
			log.Fatal("请输入正确的IPv4类地址,错误的IP地址:",value.Host)
		}
	}

}


// main
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"os"

	// "os"
	"os/exec"
	"sync"
	"time"

	"golang.org/x/crypto/ssh"
)

// 设计思路
// 多台服务器同时go get 包,保证多台服务器上有go,并且能够FQ

// SHost session and host
type SHost struct {
	Session  *ssh.Session
	Host     string
	GoAbPath string
}

// flagGit 命令
var flagGit = flag.String("goget", "", "completely package go get,example goget github.com/gpmgo/gopm")

// sessions 对话组
var sHosts = make([]*SHost, 0)

// wg 线程组
var wg sync.WaitGroup

func init() {
	// 读取配置文件
	ReadConf()
	// 创建对话组
	for _, value := range Conf.Servers {
		sHost, err := Connect(value)
		if err != nil {
			log.Println(err)
			return
		}
		sHosts = append(sHosts, sHost)
	}
}

// Connect 创建服务器连接
func Connect(server *Server) (*SHost, error) {

	if server == nil {
		err := fmt.Errorf("server is nil")
		log.Println(err)
		return nil, nil
	}

	// get auth method
	auth := make([]ssh.AuthMethod, 0)
	auth = append(auth, ssh.Password(server.Password))

	clientConfig := &ssh.ClientConfig{
		User:    server.User,
		Auth:    auth,
		Timeout: 30 * time.Second, // 连接超时时间
		// 验证服务器的主机密钥 HostKeyCallback:ssh.InsecureIgnoreHostKey(),也可以
		HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
			return nil
		},
	}

	addr := fmt.Sprintf("%s:%d", server.Host, server.Port)

	client, err := ssh.Dial("tcp", addr, clientConfig)
	if err != nil {
		log.Println(err)
		return nil, err
	}

	session, err := client.NewSession()
	if err != nil {
		log.Println(err)
		return nil, err
	}

	return &SHost{Session: session, Host: server.Host, GoAbPath: server.GoAbPath}, nil
}

func main() {

	flag.Parse()
	switch *flagGit {
	case "-h":
		fmt.Println("completely package go get,example goget github.com/gpmgo/gopm")
		return
	case "":
		return
	default:
		// 是否已经错误
		var isErr bool
		// 先在本机下载
		cmd := exec.Command("cmd", "/C", "go get "+*flagGit)
		log.Println(cmd.Args)
		stdout, err := cmd.StdoutPipe()
		if err != nil {
			log.Println(err)
		}
		stderr, err := cmd.StderrPipe()
		if err != nil {
			log.Println(err)
			isErr = true
		}
		if err := cmd.Start(); err != nil {
			log.Println(err)
			isErr = true
		}
		outBytes, err := ioutil.ReadAll(stdout)
		if err != nil {
			log.Println(err)
			isErr = true
		} else {
			log.Println(string(outBytes))
		}
		errBytes, err := ioutil.ReadAll(stderr)
		if err != nil {
			log.Println(err)
			isErr = true
		} else {
			log.Println(string(errBytes))
		}
		// 后再服务器上运行
		for i := 0; i < len(sHosts); i++ {
			sHosts[i].Session.Stderr = os.Stderr
			sHosts[i].Session.Stdout = os.Stdout
			Shell := fmt.Sprintf(" get -u %s", *flagGit)
			log.Println(Shell)
			err = sHosts[i].Session.Run("sudo " + sHosts[i].GoAbPath + Shell)
			if err != nil {
				log.Println(err, "出现错误的服务器的IP地址", sHosts[i].Host)
				isErr = true
			}
		}
		if isErr {
			log.Println("拉取失败")
		}
	}
}

;配置文件写入方法 利用配置文件的分组规则写
[servers "A"]

User = 用户名

port = 开放端口号

host = ip

password = 密码

goAbPath = /usr/local/go/bin/go
  • 曾经遇到的问题
    • go get 下来发现gopath路径下的src文件,没有拉取下来的文件,因为我开了module,即set GO111MODULE=on。所以来下来的代码放到gopath路径下的pkg文件夹下
    • 远程调用go命令的时候,他会说不具备go命令。但是自己远程服务器下是有配置的。最后只能通过利用which go获取go命令的绝对路径,进行运行。
posted @ 2020-06-15 20:19  Myuniverse  阅读(675)  评论(0编辑  收藏  举报