一、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 image 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 ntp.sjtu.edu.cn"'
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)
學習地址:http://blog.csdn.net/on_1y/article/details/8640012
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://segmentfault.com/a/1190000006949536#articleHeader5