最近公司在做在线抓娃娃, 领导让我写个运维脚本一键部署代码到所有娃娃机, 要求时间是一天之内搞定, 很好, 感谢您的信任, 让一个python零基础的人做这个, 我的内心是崩溃的….只能先找个python基础的帖子过一遍, 然后开始愣写. 现在为什么写这篇文章分享呢, 因为我真的一天之内写出来了, 看来人真的是逼出来的.

了解到fabric框架可以实现多台远程服务器部署, 而我们娃娃机用的是树莓派安装的Ubuntu, 同样都是linux所以适用

安装fabric

1
$ pip install fabric

创建fabric脚本

新建名为fabfile.py的文件, 添加代码:

1
2
def hello():
print("hello world")
1
2
$ fab hello
hello world

fabfile.py 是fabric默认识别的文件名, 也可以使用别的文件名, 但使用时加参数, 如:

1
2
$ fab -f test.py hello
hello world

主要代码

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
# -*- coding: utf-8 -*-
from fabric.api import *
from fabric.contrib.files import append
env.hosts = ['192.168.0.1', '192.168.0.2:20001'] # 地址列表
env.password = 'I am the password of the remote server'
env.user = 'root'
env.colorize_errors = True # 出错时以红色显示日志
'''
fabric 中lcd表示在本地服务器执行cd, local表示在本地执行命令
@runs_once 表示不管有多少个host, @runs_once修饰的方法只执行一次
此方法就是拉代码, 但要配置ssh key, 否则手动输git账户密码怎么能叫一键部署呢
'''
@runs_once
def prepare():
with lcd('/home/yunai/wawaji/device/'):
local('git pull')
'''
@parallel 修饰的方法就是在每台机器上都执行的方法
pool_size 表示最大并发数量
'''
@parallel(pool_size=10)
def update():
# 输出等级设置,隐藏指定的类型
with settings(
hide('warnings', 'running', 'stdout', 'stderr'),
warn_only=True
):
# 实际业务, 我们是以某个文件的某行内容来作为是否更新过的标准, 这个就根据实际需求来制定就好
if sudo('grep internal /home/yunai/wawaji/control/control.py'):
# env.host_string 表示当前正在更新的机器的host
print env.host_string + ' had been updated before, canceled.'
else:
print env.host_string + ' updating file...'
# 以sudo更新一个文件
put(local_path='/home/yunai/wawaji/device/control/control.py', remote_path='/home/yunai/wawaji/control/', use_sudo=True, mode=755)
# 以sudo给文件追加内容, 相当于:
# sudo('echo "NTP=192.168.0.3 192.168.0.2" >> /etc/systemd/timesyncd.conf')
# 但fabric的append会自动识别文件末是否已有该内容, 如果有, 则不再追加
append('/etc/systemd/timesyncd.conf', 'NTP=192.168.0.3 192.168.0.2', use_sudo=True)
print env.host_string + ' update completed'
'''
在外部设置ip的方法
也可以不使用该方法, 在内部直接写好所有ip
'''
def set_ips(*ips):
[env.hosts.append(p) for p in ips if p not in env.hosts]

所以我们可以这样来调用

1
$ fab set_ips:'192.168.0.3','192.168.0.22' prepare update

从数据库获取ip

初期领导给我的ip列表都是截图, 我的内心那是相当崩溃的, 难道手打出来吗, 当然不是, 机智的我找了个图片识别网站先转成文本, 再用正则匹配出所有ip. 后期步入正轨用数据库就好了, 下面来说python怎么使用pymysql模块来操作数据库

安装pymysql

1
$ pip install pymysql

操作数据库

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
import pymysql
def all_ip():
connection = pymysql.connect(
host = "127.0.0.1",
user = "root",
password = "I am the password of mysql",
database = "doll", # 数据库名
charset = 'utf8'
# 我们可以在此处来配置返回类型, 如下将按字典返回, 不定义则返回tuple
# cursorclass = pymysql.cursors.DictCursor
# 文档链接: http://mysql-python.sourceforge.net/MySQLdb-1.2.2/public/MySQLdb.cursors-module.html
)
cursor = connection.cursor()
result = cursor.execute("select ipaddress from device;") # 查表
result = cursor.fetchall()
cursor.close()
connection.close()
# 此时result结果应为(('192.168.0.1',), ('192.168.0.33',),)
new_array = []
for t in map(lambda x: x, result):
for ip in t:
new_array.append(ip)
# 将ip数组转换为方法参数格式
ipset = set(new_array)
# 内部设置ip列表
set_ips(*ipset)

最后我们就可以直接这样来调用了

1
$ fab all_ip update

附上Fabric文档链接 http://docs.fabfile.org/en/1.14/ 需要什么查文档就好了!!