Python从Mysql里获取值并且调用ansible批量执行的脚本

我们的服务器资产信息都是在购买的时候就记录在mysql里的,表结构如图:
akb48

可见我们的服务器命名都是有标准的,即Ez4IP_地域缩写_模块名,如果有T就是测试环境没有T就是正式环境,现在就是要从mysql里取出来对应的值然后再由ansible 2.7批量执行命令,脚本如下:

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# !/usr/bin/env python
# -*- coding:utf-8 -*-
# 作者:ChrisChan
# 用途:海外模块获取IP脚本,首先先从mysql数据库里获取对应IP,然后写上对应的命令,批量操作
# 注意!这里写死了Ez4ip_XX_xx的格式,如果有需要则自己手动更改
import pymysql, argparse, os, json, shutil
from collections import namedtuple
from ansible.parsing.dataloader import DataLoader
from ansible.vars.manager import VariableManager
from ansible.inventory.manager import InventoryManager
from ansible.playbook.play import Play
from ansible.executor.playbook_executor import PlaybookExecutor
from ansible.executor.task_queue_manager import TaskQueueManager
from ansible.plugins.callback import CallbackBase
import ansible.constants as C

# 命令行参数
parser = argparse.ArgumentParser(description='本脚本先从mysql获取内网IP地址,然后回滚')
parser.add_argument('-i', '--iii', metavar='目标模块名,如Ez4ip_FK_messagepushservice', required=True, dest='hosts', nargs='+', help='请必须输入一个模块名,不然无法执行数据库查询') # required表示此字段一定需要,nargs=’+’ 表示至少一个参数
args = parser.parse_args()

def checkSQL(i):
# 使用cursor()方法获取操作游标
cursor = db.cursor()
# SQL 查询语句
sql = "select * from cloudresource_aws_instance where instance_name regexp '" + i +"' and project_name regexp 'ez4ip';"
try:
cursor.execute(sql)
results = cursor.fetchall()
# 获取所有记录写到文件里,这个文件将来给ansible用
for row in results:
instance_name = row[3]
instance_innerip = row[4]
print("instance_name=%s,instance_innerip=%s" % (instance_name, instance_innerip))
f.write('\n'+instance_innerip)
except:
print("出现错误,mysql无法获取到数据!")

class ResultCallback(CallbackBase):
"""
重构ansible输出
"""
def __init__(self, *args, **kwargs):
super(ResultCallback, self).__init__(*args, **kwargs)
self.host_ok = {}
self.host_unreachable = {}
self.host_failed = {}

def v2_runner_on_ok(self, result, **kwargs):
"""成功"""
self.host_ok[result._host.name] = result._result["stdout"]

def v2_runner_on_unreachable(self, result, **kwargs):
"""不可达"""
self.host_unreachable[result._host.name] = result._result["msg"]

def v2_runner_on_failed(self, result, ignore_errors=False, **kwargs):
"""失败"""
self.host_failed[result._host.name] = result._result["stderr"]

def runner(ansible_host_path, module, args):
"""
类似Ad-Hoc命令
:param ansible_host_path: 一个清单文件,一行一个ip就行
:param module:
:param args:
:return:
"""
Options = namedtuple('Options',
['connection',
'module_path',
'forks',
'private_key_file',
'remote_user',
'become',
'become_method',
'become_user',
'check',
'diff'])
options = Options(connection='smart',
module_path=None,
forks=10,
private_key_file="/root/.ssh/id_rsa", # 你的私钥
remote_user="guest", # 远程用户
become=True,
become_method="sudo",
become_user="root", # sudo的用户
check=False,
diff=False)
# 主要加载设置的变量
loader = DataLoader()
# 一个密码参数,可以设置为None,默认即可,没什么影响,我用的是秘钥登录
passwords = dict(vault_pass='secret')
# 结果回调
callback = ResultCallback()
# 设置传入的机器清单
inventory = InventoryManager(loader=loader, sources=[ansible_host_path])
# 加载之前的变量
variable_manager = VariableManager(loader=loader, inventory=inventory)
play_source = dict(
name="Ansible Play",
hosts="all", # all表示匹配清单所有机器,看源码发现的
gather_facts="no",
tasks=[
dict(action=dict(module=module, args=args), register='shell_out'),
]
)
play = Play().load(play_source, variable_manager=variable_manager, loader=loader)

tqm = None
try:
tqm = TaskQueueManager(
inventory=inventory,
variable_manager=variable_manager,
loader=loader,
options=options,
passwords=passwords,
stdout_callback=callback,
)
result = tqm.run(play)
finally:
if tqm is not None:
tqm.cleanup()
shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)
# 重构输出
result_raw = {'success': {}, 'failed': {}, 'unreachable': {}}
for host, result in callback.host_ok.items():
result_raw["success"][host] = result
for host, result in callback.host_unreachable.items():
result_raw['failed'][host] = result
for host, result in callback.host_failed.items():
result_raw['unreachable'][host] = result
return json.dumps(result_raw, indent=4)

# 连接mysql
db = pymysql.connect("mysql连接地址", "mysql账号", "mysql密码", "database名称")

# 打开文件
f = open('/home/chens/instance.txt','a')

# ansible文件所在的路径
ansible_host_path = os.path.join(os.getcwd(), "instance.txt")

try:
for host in args.hosts:
command = "hostname && date && whoami"
module = host.split("_",2)[2]
print("输入的参数是:" + host)
print("对应的模块是:" + module)
chenchenchen = "cd /opt/" + module +"/ && ./stop.sh && ./start.sh"
print ("重启命令是:" +chenchenchen)
checkSQL(host)
except Exception as e:
print("ansible批量执行出现错误,请检查!")

# 关闭文件
f.close()

# 关闭数据库连接
db.close()

# 执行ansible
data = runner(ansible_host_path, "shell", command)
print(data)

os.remove(ansible_host_path)

执行效果如下:
akb48

上面的脚本里执行的是ansible语句,如果想要执行playbook,可以看一下https://blog.csdn.net/CCjedweat/article/details/88683152 这位大神的文章。

感谢您请我喝咖啡~O(∩_∩)O,如果要联系请直接发我邮箱chenx1242@163.com,我会回复你的
-------------本文结束感谢您的阅读-------------