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
}

猜你喜欢

转载自blog.csdn.net/fyxichen/article/details/78366975