我的python學習--第十四天(二)

一、ansible api

  在瞭解python的ansible api之前,先簡單瞭解一下ansible。


  ansible是新出現的自動化運維工具,基於Python開發,集合了衆多運維工具(puppet、cfengine、chef、func、fabric)的優點,實現了批量系統配置、批量程序部署、批量運行命令等功能。

  ansible是基於模塊工作的,本身沒有批量部署的能力。真正具有批量部署的是ansible所運行的模塊,ansible只是提供一種框架。主要包括:

  1. 連接插件connection plugins:負責和被監控端實現通信;

  2. host inventory:指定操作的主機,是一個配置文件裏面定義監控的主機;

  3. 各種模塊核心模塊、command模塊、自定義模塊;

  4. 藉助於插件完成記錄日誌郵件等功能;

  5. 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


效果圖

wKioL1glPNjzJ8w9AAA8Vwzs2Bw651.png



缺點

  雖然批量化執行命令很方便,但是用一個缺點,就是前端將數據傳送到邏輯端使用的是'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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章