123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615 |
- package main
- import (
- "bytes"
- "crypto/md5"
- "encoding/json"
- "flag"
- "fmt"
- "io/ioutil"
- "log"
- "net"
- "net/http"
- "os"
- "os/exec"
- "time"
- "github.com/mitchellh/go-homedir"
- "golang.org/x/crypto/ssh"
- gossh "golang.org/x/crypto/ssh"
- "gopkg.in/yaml.v2"
- )
- //声明变量
- var (
- err error
- f []byte
- logFile *os.File
- Config_dir string
- Conf Config
- Loger *log.Logger
- TaskCache []Task
- resp *http.Response
- content []byte
- )
- type Config struct {
- Url string
- User string
- Password string
- Logdir string
- Cmdb_url string
- DingDing_webHook string
- SshKeyPath string
- Type_cmd struct {
- N1 []string
- N2 []string
- N8 []string
- }
- Cmdb_Token string
- }
- type Hostinfo struct {
- Id int //id
- Ip string //ip地址
- Status int //节点状态
- Hostname string //主机名
- Node_type float64 //节点类型
- Server_room_name string //机房
- ServerId int //服务器id
- Idc_id int //idc id
- Sup_id int //供应商id
- Node_id float64 //node类型id
- }
- type Task struct {
- Id int
- Hostnumber int
- Hostgroup string
- Describe string
- Status string
- Name string
- ExecResult string
- Starttime int64
- Stoptime int64
- Createtime int64
- }
- type TaskResult struct {
- Ip string //ip地址
- Status int //节点状态
- Hostname string //主机名
- Node_type float64 //节点类型
- Server_room_name string //机房
- Result struct {
- Cmdb_api_result string //cmdb结果
- Cmd_result string //命令结果
- }
- }
- //声明变量 end
- //钉钉发消息
- func SendDingMsg(msg string) {
- //请求地址模板
- webHook := Conf.DingDing_webHook
- // content := `{'msgtype': 'text',
- // 'text': {'content': '` + msg + `'}
- // }`
- content := make(map[string]interface{})
- text := make(map[string]string)
- text["content"] = msg
- content["msgtype"] = "text"
- content["text"] = text
- fmt.Println(content)
- ddd, err := json.Marshal(content)
- fmt.Println("钉钉发消息", string(ddd), err)
- //创建一个请求
- req, err := http.NewRequest("POST", webHook, bytes.NewReader(ddd))
- if err != nil {
- Loger.Println("钉钉发消息失败", err)
- }
- client := &http.Client{}
- //设置请求头
- req.Header.Set("Content-Type", "application/json; charset=utf-8")
- //发送请求
- resp, err := client.Do(req)
- //关闭请求
- defer resp.Body.Close()
- if err != nil {
- Loger.Println("钉钉发消息失败", err)
- }
- }
- //不实时执行linux命令
- func Cmd(command string) string {
- cmd := exec.Command("/bin/bash", "-c", command)
- bytes, err := cmd.Output()
- if err != nil {
- return fmt.Sprintln("执行命令:", command+"\n", err)
- }
- resp := string(bytes)
- return "执行命令:" + command + "\n" + resp
- }
- //检测任务并执行
- func TimeCheck() {
- fmt.Println("1")
- t := TaskCache
- d := time.Now().Unix()
- for _, v := range t {
- if v.Status == "false" {
- // 开始任务
- if d == v.Starttime {
- r, err := TaskStart(v.Hostgroup, v.Describe, v.Name, v.Starttime, v.Stoptime, v.Hostnumber)
- fmt.Println("开始任务", err)
- SendDingMsg(r)
- }
- //结束任务
- if d == v.Stoptime {
- r, err := TaskStop(v.Hostgroup)
- fmt.Println("结束任务", err)
- SendDingMsg(r)
- }
- }
- }
- }
- //更新任务缓存
- func TaskUpcache() {
- for {
- content, s := CmdbApi("get_task", nil)
- if s == true {
- if err = json.Unmarshal(content, &TaskCache); err != nil {
- fmt.Println(err, string(content))
- }
- }
- time.Sleep(1 * time.Second)
- }
- }
- type Cli struct {
- user string
- pwd string
- addr string
- client *gossh.Client
- session *gossh.Session
- LastResult string
- sshKeyPath string
- }
- func (c *Cli) Connect() (*Cli, error) {
- config := &gossh.ClientConfig{}
- config.SetDefaults()
- config.User = c.user
- // config.Auth = []gossh.AuthMethod{gossh.Password(c.pwd)}
- config.Auth = []ssh.AuthMethod{publicKeyAuthFunc(c.sshKeyPath)}
- config.HostKeyCallback = func(hostname string, remote net.Addr, key gossh.PublicKey) error { return nil }
- client, err := gossh.Dial("tcp", c.addr, config)
- if nil != err {
- return c, err
- }
- c.client = client
- return c, nil
- }
- func (c Cli) Run(shell string) (string, error) {
- if c.client == nil {
- if _, err := c.Connect(); err != nil {
- return "", err
- }
- }
- session, err := c.client.NewSession()
- if err != nil {
- return "", err
- }
- defer session.Close()
- buf, err := session.CombinedOutput(shell)
- c.LastResult = string(buf)
- return c.LastResult, err
- }
- //cmdb api
- func CmdbApi(action string, data interface{}) ([]byte, bool) {
- now := time.Now().Unix()
- u := make(map[string]string)
- m := md5.Sum([]byte(Conf.User + Conf.Password + fmt.Sprintln(now)))
- client := http.Client{Timeout: 5 * time.Second}
- u["action"] = "get_task"
- u["user"] = Conf.User
- u["time"] = fmt.Sprintln(now)
- u["sign"] = fmt.Sprintf("%x", m)
- d, err1 := json.Marshal(data)
- if err1 != nil {
- fmt.Println(err1)
- }
- u["data"] = string(d)
- _u, err2 := json.Marshal(u)
- if err2 != nil {
- fmt.Println(err2)
- }
- resp, err3 := client.Post(Conf.Url, "application/json;charset=utf-8", bytes.NewBuffer(_u))
- if err2 != nil {
- fmt.Println("1", err3)
- }
- defer resp.Body.Close()
- content, err4 := ioutil.ReadAll(resp.Body)
- if err4 != nil {
- fmt.Println("Read failed:", err4)
- return []byte(""), false
- }
- return content, true
- }
- //http请求
- func Httprequest(url, method, data string) ([]byte, error) {
- var (
- req *http.Request
- resp *http.Response
- body []byte
- err error
- )
- d := []byte(data)
- if data != "" {
- if req, err = http.NewRequest(method, url, bytes.NewReader(d)); err != nil {
- return body, err
- }
- } else {
- if req, err = http.NewRequest(method, url, nil); err != nil {
- return body, err
- }
- }
- req.Header.Set("Content-Type", "application/json;charset=UTF-8")
- req.Header.Set("Authorization", "Token "+Conf.Cmdb_Token)
- if resp, err = http.DefaultClient.Do(req); err != nil {
- return body, err
- }
- defer resp.Body.Close()
- if body, err = ioutil.ReadAll(resp.Body); err != nil {
- return body, err
- }
- return body, err
- }
- func publicKeyAuthFunc(kPath string) ssh.AuthMethod {
- //交叉编译打开文件
- keyPath, err := homedir.Expand(kPath)
- if err != nil {
- log.Fatal("find key's home dir failed", err)
- }
- //读文件
- key, err := ioutil.ReadFile(keyPath)
- if err != nil {
- log.Fatal("ssh key file read failed", err)
- }
- //解析为一个对象
- // Create the Signer for this private key.
- signer, err := ssh.ParsePrivateKey(key)
- if err != nil {
- log.Fatal("ssh key signer failed", err)
- }
- //放入key对象 生成一个指针
- return ssh.PublicKeys(signer)
- }
- //开始任务
- func TaskStart(hostgroup string, desc string, name string, starttime int64, stoptime int64, hostnumber int) (string, error) {
- //关节点
- var (
- h []Hostinfo
- v []byte
- taskResult []TaskResult
- )
- if err = json.Unmarshal([]byte(hostgroup), &h); err != nil {
- return "", err
- }
- for index := range h {
- switch h[index].Node_type {
- case 16:
- t := TaskResult{}
- if v, err = Httprequest(Conf.Cmdb_url+"nodes/"+fmt.Sprintln(h[index].Node_id), "PUT", `{"status":1,"node_type":`+fmt.Sprintln(h[index].Node_type)+`}`); err != nil {
- continue
- }
- c := ""
- for cmd_index := range Conf.Type_cmd.N8 {
- c += Cmd(fmt.Sprintln("ssh root@127.0.0.1 '%s' -p 7721 ", Conf.Type_cmd.N8[cmd_index]))
- }
- t.Server_room_name = h[index].Server_room_name
- t.Node_type = h[index].Node_type
- t.Ip = h[index].Ip
- t.Hostname = h[index].Hostname
- t.Status = h[index].Status
- t.Result.Cmd_result = c
- t.Result.Cmdb_api_result = string(v)
- taskResult = append(taskResult, t)
- case 32:
- t := TaskResult{}
- if v, err = Httprequest(Conf.Cmdb_url+"nodes/"+fmt.Sprintln(h[index].Node_id), "PUT", `{"status":1,"node_type":`+fmt.Sprintln(h[index].Node_type)+`}`); err != nil {
- continue
- }
- c := ""
- for cmd_index := range Conf.Type_cmd.N8 {
- c += Cmd(Conf.Type_cmd.N8[cmd_index])
- }
- t.Server_room_name = h[index].Server_room_name
- t.Node_type = h[index].Node_type
- t.Ip = h[index].Ip
- t.Hostname = h[index].Hostname
- t.Status = h[index].Status
- t.Result.Cmd_result = c
- t.Result.Cmdb_api_result = string(v)
- taskResult = append(taskResult, t)
- case 64:
- t := TaskResult{}
- if v, err = Httprequest(Conf.Cmdb_url+"nodes/"+fmt.Sprintln(h[index].Node_id), "PUT", `{"status":1,"node_type":`+fmt.Sprintln(h[index].Node_type)+`}`); err != nil {
- continue
- }
- c := ""
- for cmd_index := range Conf.Type_cmd.N8 {
- c += Cmd(Conf.Type_cmd.N8[cmd_index])
- }
- t.Server_room_name = h[index].Server_room_name
- t.Node_type = h[index].Node_type
- t.Ip = h[index].Ip
- t.Hostname = h[index].Hostname
- t.Status = h[index].Status
- t.Result.Cmd_result = c
- t.Result.Cmdb_api_result = string(v)
- taskResult = append(taskResult, t)
- case 8:
- t := TaskResult{}
- if v, err = Httprequest(Conf.Cmdb_url+"nodes/"+fmt.Sprintln(h[index].Node_id), "PUT", `{"status":1,"node_type":`+fmt.Sprintln(h[index].Node_type)+`}`); err != nil {
- continue
- }
- c := ""
- for cmd_index := range Conf.Type_cmd.N8 {
- cli := Cli{
- user: "root",
- pwd: "",
- addr: h[index].Ip + ":7721",
- sshKeyPath: Conf.SshKeyPath,
- }
- fmt.Println(cli)
- output, err := cli.Run(Conf.Type_cmd.N8[cmd_index])
- if err != nil {
- c += fmt.Sprintln(err)
- }
- c += fmt.Sprintln(output)
- }
- t.Server_room_name = h[index].Server_room_name
- t.Node_type = h[index].Node_type
- t.Ip = h[index].Ip
- t.Hostname = h[index].Hostname
- t.Status = h[index].Status
- t.Result.Cmd_result = c
- t.Result.Cmdb_api_result = string(v)
- taskResult = append(taskResult, t)
- default:
- t := TaskResult{}
- t.Server_room_name = h[index].Server_room_name
- t.Node_type = h[index].Node_type
- t.Ip = h[index].Ip
- t.Hostname = h[index].Hostname
- t.Status = h[index].Status
- taskResult = append(taskResult, t)
- }
- }
- m, err := UpVersion()
- t := struct {
- Title string
- Hostlength int
- TaskResult []TaskResult
- VersionInfo string
- Describe string
- Name string
- Startime string
- Stoptime string
- }{
- Title: "开始任务",
- Hostlength: hostnumber,
- TaskResult: taskResult,
- VersionInfo: m,
- Describe: desc,
- Name: name,
- Startime: time.Unix(starttime, 0).Format("2006-01-02 15:04:05"),
- Stoptime: time.Unix(stoptime, 0).Format("2006-01-02 15:04:05"),
- }
- d, err := yaml.Marshal(t)
- return string(d), err
- }
- //结束任务
- func TaskStop(hostgroup string) (string, error) {
- //开节点
- var (
- title string
- msg string
- h []Hostinfo
- v []byte
- )
- if err = json.Unmarshal([]byte(hostgroup), &h); err != nil {
- return "", err
- }
- msg += "结束任务" + "\n"
- msg += fmt.Sprintln("执行主机长度", len(h))
- for index := range h {
- switch h[index].Node_type {
- case 16:
- msg += fmt.Sprintln(h[index].Ip, "执行汇集节点命令")
- case 32:
- msg += fmt.Sprintln(h[index].Ip, "执行普通几点")
- case 64:
- msg += fmt.Sprintln(h[index].Ip, "执行普通64")
- case 8:
- if v, err = Httprequest(Conf.Cmdb_url+"nodes/"+fmt.Sprintln(h[index].Node_id), "PUT", `{"status":1,"node_type":`+fmt.Sprintln(h[index].Node_type)+`}`); err != nil {
- return msg, err
- }
- c := ""
- for cmd_index := range Conf.Type_cmd.N8 {
- c += Cmd(Conf.Type_cmd.N8[cmd_index])
- }
- title = fmt.Sprintln("主机", h[index].Ip, "类型", h[index].Node_type, "状态", h[index].Status, "机房", h[index].Server_room_name, "---------主机执行")
- msg += fmt.Sprintln(title, "执行cmdb接口"+string(v)+"\n", "------执行shells\n", c, "\n------执行shell结束")
- msg += fmt.Sprintln("主机", h[index].Ip, "类型", h[index].Node_type, "状态", h[index].Status, "机房", h[index].Server_room_name, "---------主机执行结束")
- case 2:
- //关闭节点
- msg += fmt.Sprintln(h[index].Ip, "执行普通64")
- default:
- msg += fmt.Sprintln(index, "无节点类型", h[index], "类型", h[index].Node_type, "节点状态", h[index].Status)
- }
- }
- m, err := UpVersion()
- msg += m
- return msg, err
- }
- //更新版本号+1
- func UpVersion() (string, error) {
- var (
- err error
- msg string
- v []byte
- )
- version := make(map[string]int)
- if v, err = Httprequest(Conf.Cmdb_url+"node-version/1", "GET", ""); err != nil {
- return "", err
- }
- if err = json.Unmarshal(v, &version); err != nil {
- return "", err
- }
- msg += fmt.Sprintln("version执行前版本", version["version"])
- version["version"] = version["version"] + 1
- if v, err = json.Marshal(version); err != nil {
- return "", err
- }
- if v, err = Httprequest(Conf.Cmdb_url+"node-version/1", "PUT", string(v)); err != nil {
- return "", err
- }
- msg += fmt.Sprintln("当前版本号", string(v))
- return msg, err
- }
- //初始化
- func init() {
- flag.StringVar(&Config_dir, "taskConfig", "./taskConfig.json", "配置文件默认地址")
- flag.Parse()
- currentTime := time.Now()
- //加载配置文件
- if f, err = ioutil.ReadFile(Config_dir); err != nil {
- fmt.Println("读取错误", err)
- os.Exit(255)
- }
- if err = json.Unmarshal(f, &Conf); err != nil {
- fmt.Println("配置文件加载错误", err)
- os.Exit(255)
- }
- // dddd, _ := json.MarshalIndent(Conf, "", " ")
- // fmt.Println("初始化配置文件内容如下\n", string(dddd))
- if logFile, err = os.OpenFile(currentTime.Format(Conf.Logdir+"/2006-01-02.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0766); err != nil {
- if err != nil {
- fmt.Println("创建日志失败", err)
- os.Exit(255)
- }
- }
- Loger = log.New(logFile, "[LOG]", log.Ldate|log.Lshortfile|log.Ltime)
- }
- func main() {
- go TaskUpcache()
- content, s := CmdbApi("get_task", nil)
- if s == true {
- if err = json.Unmarshal(content, &TaskCache); err != nil {
- fmt.Println(err, string(content))
- }
- }
- r, err := TaskStart(TaskCache[0].Hostgroup, TaskCache[0].Describe, TaskCache[0].Name, TaskCache[0].Starttime, TaskCache[0].Stoptime, TaskCache[0].Hostnumber)
- fmt.Println("开始任务", err)
- fmt.Println(r)
- SendDingMsg(r)
- // for {
- // if len(TaskCache) == 0 {
- // fmt.Println(111)
- // return
- // }
- // TimeCheck()
- // time.Sleep(1 * time.Second)
- // }
- }
|