一、ansible api
在了解python的ansible api之前,先简单了解一下ansible。
ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。
ansible是基于模块工作的,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架。主要包括:
- 连接插件connection plugins:负责和被监控端实现通信;
- host inventory:指定操作的主机,是一个配置文件里面定义监控的主机;
- 各种模块核心模块、command模块、自定义模块;
- 借助于插件完成记录日志邮件等功能;
- playbook:剧本执行多个任务时,非必需可以让节点一次性运行多个任务。
安装ansible
[root@yaoliang python]# yum install -y ansible # 直接yum安装即可
配置ansible
[root@yaoliang day_13]# ssh-keygen -t rsa # 创建密钥
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
8c:91:b4:b5:f5:79:ae:19:5a:a4:a3:ef:35:72:91:91 root@yaoliang
The key's randomart p_w_picpath is:
+--[ RSA 2048]----+
| . . . |
| . + o . o |
| + . E . |
| + o = |
| . S o = . |
| . + = |
| . o * |
| . + . |
| .o |
+-----------------+
[root@yaoliang day_13]# ssh-copy-id -i /root/.ssh/id_rsa.pub 192.168.38.250 # 传输密钥,使其免密钥访问
[root@yaoliang day_13]# vim /etc/ansible/hosts
[web]
192.168.38.250
测试
[root@yaoliang day_13]# ansible web -a 'uname -r'
192.168.38.250 | success | rc=0 >>
3.10.0-327.el7.x86_64
常用参数
- -m: 使用模块名
- -a: 传入的参数
常用模块
- copy模块
# 将/root/anaconda-ks.cfg复制到/tmp下
[root@yaoliang day_13]# ansible web -m copy -a 'src=/root/anaconda-ks.cfg dest=/tmp'
- file模块
# 修改/tmp的属主,属组和权限
[root@yaoliang day_13]# ansible web -m file -a 'dest=/tmp mode=755 owner=root group=root'
- cron模块
# 创建周期性任务
[root@yaoliang day_13]# ansible web -m cron -a 'name="ntp job" minute=*/3 hour=* day=* month=* weekday=* job="/usr/sbin/ntpdate "'
- group模块
# 创建用户组
[root@yaoliang day_13]# ansible web -m group -a 'gid=2000 name=linux'
- user模块
# 创建用户
[root@yaoliang day_13]# ansible web -m user -a 'name=linux groups=linux state=present'
- yum模块
# 安装httpd服务
[root@yaoliang day_13]# ansible web -m yum -a "state=present name=httpd"
- service模块
# 重启httpd服务
[root@yaoliang day_13]# ansible web
- script模块
# 执行脚本
[root@yaoliang day_13]# ansible web -m script -a '/root/test.sh'
- ping模块
# 查看能否ping通
[root@yaoliang day_13]# ansible web -m ping
• command模块# 执行命令,和shell模块相似 [root@yaoliang day_13]# ansible web -m command -a 'hostname'
安装python的ansible模块
# ansible 2.0之后变化很大,故安装2.0之前的版本 [root@yaoliang day_13]# pip install 'ansible<2.0'
ansible中的函数
PACKAGE CONTENTS
cache (package)
callback_plugins (package)
callbacks
color
constants
errors
inventory (package)
module_common
module_utils (package)
modules (package)
playbook (package)
runner (package)
utils (package)实例
In [1]: import ansible.runner
In [2]: runner = ansible.runner.Runner(
...: module_name='shell', # 模块名
...: module_args='uname -r', # 参数
...: pattern='web', # 组名
...: forks=10 # 线程数
...: )
In [3]: res = runner.run()
In [4]: res
Out[4]:
{'contacted': {'192.168.38.250': {u'changed': True,
u'cmd': u'uname -r',
u'delta': u'0:00:00.006807',
u'end': u'2016-11-02 02:43:47.664868',
'invocation': {'module_args': u'uname -r',
'module_complex_args': {},
'module_name': 'shell'},
u'rc': 0,
u'start': u'2016-11-02 02:43:47.658061',
u'stderr': u'',
u'stdout': u'3.10.0-327.el7.x86_64',
u'warnings': []}},
'dark': {}}批量命令的思路:从前端获取module_name,module_args,pattern和forks参数,通过ansible.runner.Runner()获取执行结果,对结果处理后对在前端进行展示。
前端
// 通过点击执行按钮,获取参数并传递给回调函数
$('#cmdform').on('submit',function(){
var str = $('#cmdform').serialize()
var url = '/cmd?'+str
$.get(url,function(data){
//data = "<strong><pre>"+data+"</pre></strong>"
# 获取结果,在前端展示
$('#display').html(data)
})
return false
})
逻辑端
# 获取参数并格式化
cmd_time = time.strftime('%Y-%m-%d %H:%M:%S')
pattern = request.args.get('pattern','all')
module = request.args.get('module','shell')
args = urllib.unquote(request.args.get('cmd','whoami'))
forks = request.args.get('forks',5)
results = ansible_cmd(pattern,module,args,forks)
record = "[%s] - %s - %s - %s\n" % (cmd_time,name,pattern,args)
# 拼接字符串并返回结果
for (hostname,result) in results['contacted'].items():
if not "failed" in result and result['stdout'] != "":
str += "%s | %s | success >> \n %s \n" % (hostname,result['cmd'],result['stdout'])
else:
str += "%s | %s | FAILED >> \n %s \n" % (hostname,result['cmd'],result['stderr'])
for (hostname,result) in results['dark'].items():
str += "%s | SSH Error >> \n %s \ n" % (hostname, result['msg'])
return str效果图

缺点
虽然批量化执行命令很方便,但是用一个缺点,就是前端将数据传送到逻辑端使用的是'GET'请求,并不安全,当用户在前端通过固定格式,将危险的执行操作通过url的格式传递到逻辑端的话会非常危险,所以要在逻辑端进行判断,禁止像'rm'这样危险命令的执行。
类(class)
python的多线程
Python的线程虽然是真正的线程,但解释器执行代码时,有一个GIL锁:Global Interpreter Lock,任何Python线程执行前,必须先获得GIL锁,然后,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行。这个GIL全局锁实际上把所有线程的执行代码都给上了锁,所以,多线程在Python中只能交替执行,即使100个线程跑在100核CPU上,也只能用到1个核。
Python的标准库提供了两个模块:thread和threading,thread是低级模块,threading是高级模块,对thread进行了封装。绝大多数情况下,我们只需要使用threading这个高级模块。
threading 模块提供的方法:
- threading.currentThread(): 返回当前的线程变量。
- threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
- threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
- run(): 用以表示线程活动的方法。
- start():启动线程活动。
- join(): 等待至线程中止。join()的作用是,在子线程完成运行之前,这个子线程的父线程将一直被阻塞。
- isAlive(): 返回线程是否活动的。
- getName(): 返回线程名。
- setName(): 设置线程名。
在此之前,先看一下单线程是如何工作的
# coding:utf-8
from time import sleep,ctime
def music():
for i in range(2):
print 'I was listening to music. {}'.format(ctime())
sleep(1)
def movie():
for i in range(2):
print 'I was see movie. {}'.format(ctime())
sleep(2)
if __name__=='__main__':
music()
movie()
print 'all done {}'.format(ctime())执行结果
[root@yaoliang day_14]# python simple_thread.py
I was listening to music. Wed Nov 2 06:21:42 2016
I was listening to music. Wed Nov 2 06:21:43 2016
I was see movie. Wed Nov 2 06:21:44 2016
I was see movie. Wed Nov 2 06:21:46 2016
all done Wed Nov 2 06:21:48 2016
总结:在执行music函数过程中,movie始终处于阻塞状态,耗时6秒。
多线程
# coding:utf-8
import threading
from time import sleep,ctime
def music(music):
for i in range(2):
print 'I was listening to {}. {}'.format(music,ctime())
sleep(1)
def movie(movie):
for i in range(2):
print 'I was see {}. {}'.format(movie,ctime())
sleep(2)
threads = []
thread1 = threading.Thread(target=music,args=('爱情买卖',))
threads.append(thread1)
thread2 = threading.Thread(target=movie,args=('阿凡达',))
threads.append(thread2)
if __name__=='__main__':
for i in threads:
i.start()
i.join() # join()使主线程在子线程完成之前处于阻塞状态
print 'all done {}'.format(ctime())运行结果
[root@yaoliang day_14]# python multi_thread.py
I was listening to 爱情买卖. Wed Nov 2 06:21:58 2016
I was see 阿凡达. Wed Nov 2 06:21:58 2016
I was listening to 爱情买卖. Wed Nov 2 06:21:59 2016
I was see 阿凡达. Wed Nov 2 06:22:00 2016
all done Wed Nov 2 06:22:02 2016总结:两个子线程同是执行,耗时4秒。
python的多进程
Python提供了非常好用的多进程包multiprocessing,只需要定义一个函数,Python会完成其他所有事情。借助这个包,可以轻松完成从单进程到并发执行的转换。multiprocessing支持子进程、通信和共享数据、执行不同形式的同步,提供了Process、Queue、Pipe、Lock等组件。
一、multiprocessing实现python跨平台多进程任务
multiprocessing模块提供了一个Process类来代表一个进程对象,创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,用start()方法启动,这样创建进程比fork()还要简单。
join()方法可以等待子进程结束后再继续往下运行,和线程不同的时,不加join()父进程不会退出,子进程也不会成为孤儿
单个子进程实例
# codiing:utf-8
from multiprocessing import Process
import os,time
def run(name):
time.sleep(5)
print 'Run child process {} {}'.format(name,os.getpid())
if __name__=='__main__':
print 'Parent process {}.'.format(os.getpid())
p = Process(target=run,args=('child_process',))
print 'I am parent process {}, child process will start.'.format(os.getpid())
p.start()
p.join() # 子进程结束后再往下执行父进程,即使父进程执行完也不退出,等待子进程一起退出
print 'I am parent process {}, child process end.'.format(os.getpid())
运行结果
# 加了join()
[root@yaoliang day_14]# python simple_process.py
Parent process 47143.
I am parent process 47143, child process will start.
Run child process child_process 47145
I am parent process 47143, child process end.
# 注释掉join()
[root@yaoliang day_14]# python simple_process.py
Parent process 32359.
I am parent process 32359, child process will start.
I am parent process 32359, child process end.
Run child process child_process 32361
多个子进程实例
#coding:utf-8
from multiprocessing import Process
import os
def run(name,num):
print '{} Run child process {}{},my parent is {}..'.format(num,name,os.getpid(),os.getppid())
if __name__=='__main__':
print 'Parent process is {}.'.format(os.getpid())
for i in range(3):
p = Process(target=run,args=('test',i,))
print 'Process will start {}.'.format(os.getpid())
p.start()
p.join()
print 'Process end {}.'.format(os.getpid())运行结果
# 开启join()阻塞时候的执行结果——有序但阻塞
[root@yaoliang day_14]# python multi_process.py
Parent process is 91474.
Process will start 91474.
0 Run child process test91477,my parent is 91474..
Process will start 91474.
1 Run child process test91478,my parent is 91474..
Process will start 91474.
2 Run child process test91479,my parent is 91474..
Process end 91474.
# 关闭join()非阻塞时候的执行结果——高效非阻塞,但无序混乱了
[root@yaoliang day_14]# python multi_process.py
Parent process is 113725.
Process will start 113725.
Process will start 113725.
Process will start 113725.
Process end 113725.
0 Run child process test113726,my parent is 113725..
1 Run child process test113727,my parent is 113725..
2 Run child process test113728,my parent is 113725..二、 Python多进程并发操作中进程池Pool的应用
在利用Python进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间。当被操作对象数目不大时,可以直接利用multiprocessing中的Process动态成生多个进程,10几个还好,但如果是上百个,上千个目标,手动的去限制进程数量却又太过繁琐,这时候进程池Pool发挥作用的时候就到了。
Pool可以提供指定数量的进程,供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来它。这里有一个简单的例子:
#!/usr/bin/python
#coding:utf-8
from multiprocessing import Pool
import os,time,random
def run(name):
print "Run child process %s (%s),my parent is (%s).." % (name,os.getpid(),os.getppid())
start = time.time()
time.sleep(random.random()*3)
end = time.time()
print 'Task %s runs %0.2f seconds..(%s)' % (name,(end-start),os.getpid())
if __name__=='__main__':
print 'Parent process %s' % os.getpid()
pool = Pool(processes=3) # 创建进程池 p=Pool() 默认创建进程数为cpu核数
for n in xrange(4):
result = pool.apply_async(run,args=(n,)) # 用子进程处理任务,
print 'waiting for all subprocess done (%s)' % os.getpid()
pool.close() # 调用close()会等待池中的worker进程执行结束再关闭pool,
pool.join() # 等待所有子进程执行完毕后在执行父进程,如果父进程先退出,所有子进程也消失,任务终止
if result.successful(): # result.successful()表示整个调用执行的状态,如果还有worker没有执行完,则会抛出AssertionError异常。
print 'successful'
print 'all subprocess end (%s)' % os.getpid()
运行结果
[root@yaoliang day_14]# python process_pool.py
Parent process 114005
waiting for all subprocess done (114005)
Run child process 0 (114007),my parent is (114005).. # 进程池有三个进程,故前三个任务是并发执行的
Run child process 1 (114008),my parent is (114005)..
Run child process 2 (114006),my parent is (114005)..
Task 0 runs 0.66 seconds..(114007)
Run child process 3 (114007),my parent is (114005).. # 第四个任务开始被前面闲下来的子进程处理
Task 3 runs 0.01 seconds..(114007)
Task 2 runs 1.79 seconds..(114006)
Task 1 runs 2.73 seconds..(114008)
successful
all subprocess end (114005)
三、进行间通信
Process之间肯定是需要通信的,操作系统提供了很多机制来实现进程间的通信。Python的multiprocessing模块包装了底层的机制,提供了Queue、Pipes等多种方式来交换数据。以Queue为例,在父进程中创建两个子进程,一个往Queue里写数据,一个从Queue里读数据:
# coding:utf-8
from multiprocessing import Queue,Process
import os,time,random
def write(q):
for value in ['A','B','C']:
print 'Put {} to queue'.format(value)
q.put(value)
time.sleep(random.random())
def read(q):
while True: # 此处不能为while not q.empty(),因为不能保证读和写速度,当队列为空,读进程就会结束
value = q.get(True) # 当队列为空时,get()会被阻塞,需要强制关闭进程
print 'Get {} from queue'.format(value)
if __name__=='__main__':
q = Queue()
pw = Process(target=write,args=(q,))
pr = Process(target=read,args=(q,))
pw.start() # 写进程与读进程同时执行
pr.start()
pw.join()
pr.terminate() # 强制结束都进程,因为它是死循环
运行结果
[root@yaoliang day_14]# python process_queue.py
Put A to queue
Get A from queue
Put B to queue
Get B from queue
Put C to queue
Get C from queue
Flask-SQLALchemy
学习地址:http://forlinux.blog.51cto.com/8001278/1420961
SQLAlchemy
学习地址:
转载于:https://blog.51cto.com/yaoliang83/1872666
















