项目需要,需要一个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有区别,小心使用