调用 ansible 执行自动化任务.
使用介绍
作为一名运维,日常操作经常会用到 ansible 来批量执行任务。如果我们想在编程语言里面调用它,对 Python 来说相对比较简单,但是对于 golang 就比较麻烦了。一种方法是自己封装,一种是使用第三方库。
自己封装
自己封装的原理是通过 exec 标准库,调用系统上的 ansible 来执行任务。
简单封装示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
package ansible
import (
"bytes"
"os/exec"
)
type Ansible struct {
inventoryFile string
user string
privateKey string
}
// 构造函数,构造 ansible 运行所需参数
func NewAnsible(inventoryFile, user, privateKey string) *Ansible {
return &Ansible{
inventoryFile: inventoryFile,
user: user,
privateKey: privateKey,
}
}
// 运行接口
func (a *Ansible) RunPlaybook(playbookPath string) (string, error) {
var stdout bytes.Buffer
var stderr bytes.Buffer
cmd := exec.Command("ansible-playbook",
"-i", a.inventoryFile,
"-u", a.user,
"--private-key="+a.privateKey,
playbookPath)
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
// 返回结果
return stdout.String() + stderr.String(), err
}
|
但是自己封装耗时耗力,还可能有潜在的 bug 。
第三方库
在 github 上面,我找到了go-ansible这个库,别人已经封装好了的。用起来还挺顺手的。他的原理也是通过 exec 标准库,调用系统上的 ansible 来执行任务的。
我们拿其中一个场景出来看看,详情注释部分写得很清楚了,不再赘述。如果有兴趣可以通上面的超链接直接到官方 github 查看其他各种示例。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
package main
import (
"context"
"flag"
"fmt"
"time"
"bytes"
"io"
"github.com/apenella/go-ansible/pkg/execute"
"github.com/apenella/go-ansible/pkg/execute/measure"
"github.com/apenella/go-ansible/pkg/options"
"github.com/apenella/go-ansible/pkg/playbook"
"github.com/apenella/go-ansible/pkg/stdoutcallback/results"
)
func main() {
var res *results.AnsiblePlaybookJSONResults
var timeout int
flag.IntVar(&timeout, "timeout", 32400, "Timeout in seconds")
flag.Parse()
buff := new(bytes.Buffer)
fmt.Printf("Timeout: %d seconds\n", timeout)
// 配置超时时间
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
defer cancel()
// 配置连接方式, "local" 表示,无论你后面 Inventory 选项怎么配,都是在执行 ansible 的本地执行
// 要真正连接到 Inventory 配置的机器,注释掉 Connection 选项或者使用 "smart" 或 "ssh" 作为参数值
ansiblePlaybookConnectionOptions := &options.AnsibleConnectionOptions{
Connection: "local",
// User: "apenella",
}
// 资产清单和变量文件,也可以是一个 map 类型来作为变量,就无需引入文件
ansiblePlaybookOptions := &playbook.AnsiblePlaybookOptions{
Inventory: "192.168.21.101,",
ExtraVarsFile: []string{
"@vars-file1.yml",
},
}
// 执行结果缓存
executorTimeMeasurement := measure.NewExecutorTimeMeasurement(
execute.NewDefaultExecute(
execute.WithWrite(io.Writer(buff)),
),
)
// 构造 ansible
playbook := &playbook.AnsiblePlaybookCmd{
Playbooks: []string{"site.yml"},
ConnectionOptions: ansiblePlaybookConnectionOptions,
Options: ansiblePlaybookOptions,
Exec: execute.NewDefaultExecute(
execute.WithWrite(io.Writer(buff)),
),
// Exec: executorTimeMeasurement,
StdoutCallback: "json",
}
// 执行 playbook
err := playbook.Run(ctx)
if err != nil {
panic(err)
}
// 输出结果
res, err = results.ParseJSONResultsStream(io.Reader(buff))
if err != nil {
panic(err)
}
}
|
总结
使用别人封装好的第三方库,就不需要自己耗时耗力去重复造轮子,可以把更多的精力用在业务上。