Go1.9幫同事寫個備份上傳小程序,帶推告警到open-falcon功能

package main

import (
    "archive/zip"
    "encoding/json"
    "flag"
    "io/ioutil"
    "log"
    "net/http"
    "os"
    "strings"
    "time"

    "github.com/jlaffaye/ftp"
)

type Config struct {
    Endpoint  string `json:"endpoint"`
    UserName  string `json:"username"`
    PassWord  string `json:"password"`
    FtpAddr   string `json:"ftpaddr"`
    RootDir   string `json:"rootdir"`
    PushAddr  string `json:"pushaddr"`
    CreateDir bool   `json:"createdir"`
    ZipCheck  bool   `json:"zipcheck"`
}

var (
    config   Config
    cfgpath  string
    filepath string
)

func init() {
    flag.StringVar(&cfgpath, "cfg", "", "-cfg cfg.json 從文件讀取配置")
    flag.StringVar(&filepath, "f", "", "-f backup.zip 指定要上傳的文件")
    flag.StringVar(&config.UserName, "u", "", "-u root 指定ftp登錄名稱")
    flag.StringVar(&config.PassWord, "p", "", "-p root 指定ftp登錄密碼")
    flag.StringVar(&config.FtpAddr, "a", "", "-a 192.168.0.1:21 指定ftp登錄地址")
    flag.StringVar(&config.PushAddr, "P", "", "-P 127.0.0.1:1988 指定ftp登錄密碼")
    flag.StringVar(&config.Endpoint, "e", "", "-e endpoint 指定當前Endpoint名稱")
    flag.StringVar(&config.RootDir, "r", "", "-r /backup 指定登錄的根目錄")
    flag.BoolVar(&config.CreateDir, "c", false, "-c 按日期創建目錄")
    flag.BoolVar(&config.ZipCheck, "z", false, "-z 檢查是否有效的zip文件")
    example := flag.Bool("example", false, "-example 生成配置文件")
    flag.Parse()
    if *example {
        File, err := os.Create("cfg.json")
        if err == nil {
            File.Write([]byte(`{
    "endpoint":"",
    "username":"user",
    "password":"password",
    "ftpaddr":"127.0.0.1:21",
    "rootdir":"/backup",
    "pushaddr":"",
    "createdir":true,
    "zipcheck":true
}`))
            File.Close()
        } else {
            log.Fatalf("Create example file error:%s\n", err.Error())
        }
        os.Exit(0)
    }
}

type result struct {
    Path  string `json:"path"`
    Reult bool   `json:"result"`
}

type MetricValue struct {
    Endpoint  string `json:"endpoint"`
    Metric    string `json:"metric"`
    Value     int    `json:"value"`
    Step      int64  `json:"step"`
    Type      string `json:"counterType"`
    Tags      string `json:"tags"`
    Timestamp int64  `json:"timestamp"`
}

func main() {
    //創建日誌文件,以增加模式打開
    logFile, err := os.OpenFile("run.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644)
    if err == nil {
        log.SetOutput(logFile)
    }

    var res result

    //設置程序結束執行的函數
    defer func() {
        //判斷Push地址是不是爲空,如果不爲空則發一條監控數據到指定的接口
        if config.PushAddr != "" {
            var Met = []MetricValue{{Endpoint: config.Endpoint, Metric: "sqlserver.backupload", Value: 0, Step: 86400, Type: "GAUGE", Timestamp: time.Now().Unix()}}
            if res.Reult {
                Met[0].Value = 1
            }
            buf, _ := json.Marshal(Met)
            resp, err := http.Post(config.PushAddr, "application/json", strings.NewReader(string(buf)))
            if err == nil {
                if resp.StatusCode != 200 {
                    log.Printf("Post return status code %d\n", resp.StatusCode)
                }
            } else {
                log.Printf("Post warnning error:%s\n", err.Error())
            }
        }

        //將執行的結果以標準的json格式寫入文件,
        File, err := os.OpenFile(time.Now().Format("20060102")+"_reult.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644)
        if err != nil {
            log.Fatalf("Open result file error:%s\n", err.Error())
        }
        buf, _ := json.Marshal(res)
        File.Write(buf)
        File.Write([]byte("\r\n"))
        File.Close()
    }()

    res.Path = filepath

    //處理要發送的文件路徑,用','分割
    files := strings.Split(strings.TrimSpace(filepath), ",")
    if len(files) == 0 {
        log.Println("Upload file can't empty")
        return
    }

    //解析json配置文件
    if cfgpath != "" {
        if err := parsrconfig(cfgpath, &config); err != nil {
            log.Printf("Parse config error:%s\n", err.Error())
            return
        }
    }

    //檢測一下配置是否正確
    if checkconfig(config) {
        log.Println("Invalid config")
        return
    }

    //遍歷待上傳的文件路徑檢測是否爲有效的zip
    if config.ZipCheck {
        for _, path := range files {
            rc, err := zip.OpenReader(path)
            if err != nil {
                log.Printf("Invalid zip file:%s\n", err.Error())
                return
            }
            rc.Close()
        }
    }

    //上傳文件
    err = upload(config, files)
    if err == nil {
        res.Reult = true
    } else {
        log.Printf("Upload file error:%s\n", err.Error())
    }
}

func parsrconfig(cfgpath string, cfg *Config) error {
    buf, err := ioutil.ReadFile(cfgpath)
    if err == nil {
        err = json.Unmarshal(buf, cfg)
    }
    return err
}

func checkconfig(cfg Config) bool {
    if cfg.PushAddr != "" {
        if cfg.Endpoint == "" {
            return true
        }
    }
    return cfg.FtpAddr == "" || cfg.UserName == "" || cfg.PassWord == ""
}

func upload(cfg Config, paths []string) error {
    //連接遠程地址
    remote, err := ftp.Dial(cfg.FtpAddr)
    if err != nil {
        return err
    }
    defer remote.Quit()

    //開始登錄認證
    err = remote.Login(cfg.UserName, cfg.PassWord)
    if err != nil {
        return err
    }

    var rootpath string = "/"

    if cfg.RootDir != "" {
        rootpath = cfg.RootDir
    }

    if rootpath[len(rootpath)-1] != '/' {
        rootpath += "/"
    }

    //按當天的日期創建目錄
    if cfg.CreateDir {
        rootpath += time.Now().Format("20060102") + "/"
        remote.MakeDir(rootpath)
    }

    //切換到目錄
    err = remote.ChangeDir(rootpath)
    if err != nil {
        return err
    }

    //遍歷待上傳的文件開始上傳
    for _, path := range paths {
        //打開文件
        File, err := os.Open(path)
        if err != nil {
            return err
        }
        //開始上傳
        err = remote.Stor(rootpath+path, File)
        File.Close()
        if err != nil {
            return err
        }
    }
    return nil
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章