项目需要,需要一个agent客户端,调用shell脚本以实现自动化部署,写博客备忘

1.go语言开发客户端,调用本地指定脚本

package main

 

import (

. "agent"

"agent/conf"

"encoding/json"

"io/ioutil"

"log"

"net/http"

"net/url"

"os"

"redis"

. "time"

)

 

var logfile, _ = os.OpenFile("agent.log", os.O_RDWR|os.O_CREATE, 0777)

var logger *log.Logger = log.New(logfile, "", log.LstdFlags|log.Lshortfile)

 

var latest_frequency int = Config.Heartbeat_frequency

 

type Task struct {

Taskid      string

Script      string

ScriptParam string

}

 

type Redis_Instance struct {

Port     string

Password string

Path     string

}

 

type Heart_message struct {

Frequency int

Tasks     []Task

Instances []Redis_Instance

}

 

func main() {

for {

latest_frequency, tasks, instances := get_msg()

 

go handle_task(tasks)

go sync_config(instances)

 

Sleep(Duration(latest_frequency) * Minute)

}

}

 

func get_msg() (int, []Task, []Redis_Instance) {

var msg Heart_message

logger.Println("Config.Heartbeat_service=" + Config.Heartbeat_service)

if resp, err := http.Get(Config.Heartbeat_service + "/heartbeat"); err == nil && resp.StatusCode == http.StatusOK {

defer resp.Body.Close()

if data, err := ioutil.ReadAll(resp.Body); err == nil {

json.Unmarshal(data, &msg)

logger.Print(msg)

json.Unmarshal(data, &msg)

return msg.Frequency, msg.Tasks, msg.Instances

}

}else {

logger.Println("when get msg : do Nothing and return ..")

}

 

return latest_frequency, nil, nil

}

 

func handle_task(tasks []Task) {

for _, t := range tasks {

var success string = "0"

cmd := Command{

Cmd:  t.Script + ".sh",

Args: t.ScriptParam,

}

 

if _, err := cmd.Execute(); err == nil { //result, err

success = "1"

logger.Println("task_id=" + t.Taskid + ",t.Script=" + t.Script + ",success=" + success)

}else {

logger.Println("task_id=" + t.Taskid + ",t.Script=" + t.Script + ",success=" + success)

}

i := 0

para := url.Values{

"taskId": {t.Taskid},

"status": {success},

}

for _, err := http.PostForm(Config.Heartbeat_service+"/callback", para); i < Config.Callback_retry && err != nil; i++ {

_, err = http.PostForm(Config.Heartbeat_service+"/callback", para)

}

}

}

 

func sync_config(instances []Redis_Instance) {

for _, instance := range instances {

if c, err := redis.Dial("tcp", "127.0.0.1:"+instance.Port); err != nil {

log.Println(err)

} else {

defer c.Close()

if configs, err := redis.Strings(c.Do("config", "get", "*")); err == nil {

if c, err := conf.ParseFile(instance.Path); err != nil {

log.Println(err)

} else {

for i := 0; i < len(configs); i += 2 {

if v, err := c.Get(configs[i]); v != configs[i+1] && err == nil {

c.Set(configs[i], configs[i+1])

}

}

}

}

}

}

}

 

2.主要是下面这个类

 

package agent

 

import (

"os/exec"

"strings"

)

 

type Command struct {

Cmd  string

Args string

}

 

func (cmd *Command) Execute() ([]byte, error) {

var argArray []string

if cmd.Args != "" {

argArray = strings.Split(cmd.Cmd + " " + cmd.Args, " ")

} else {

argArray = make([]string, 0)

}

//如果是执行shell脚本  必须是这么写,如果是win下面执行bat文件,不指定/bin/sh,直接以cmd开头即可

//当然注意脚本的路径了

_cmd := exec.Command("/bin/sh", argArray...)

return _cmd.Output()

}

 

windows下面安装go和eclipse引入go插件比较简单,网上搜的

linux下也是一样的

go run agent.go直接编译后执行,没有生成可执行文件

go build -o goagent.sh 生成可执行文件

go build与go install有区别,小心使用