強化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命令的絕對路徑,進行運行。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM