Python模塊及詳解(2)

目錄:

一、報表之Excel操作XlsxWriter模塊

二、Python與rrdtool的結合模塊

三、構建集中式的病毒掃描機制

四、系統批量運維管理器paramiko詳解

五、系統批量運維管理器Fabric詳解

一、報表之Excel操作XlsxWriter模塊

Excel是當今最流行的電子表格處理軟件,支持豐富的計算函數及圖表,在系統運營方面廣泛用于運營數據報表,比如業務質量、資源利用、安全掃描等報表,同時也是應用系統常見的文件導出格式,以便數據使用人員做進一步加工處理。本節主要講述利用Python操作Excel的模塊XlsxWriter(https://xlsxwriter.readthedocs.org),可以操作多個工作表的文字、數字、公式、圖表等。XlsxWriter模塊具有以下功能:

·100%兼容的Excel XLSX文件,支持Excel 2003、Excel 2007等版本;

·支持所有Excel單元格數據格式;

·單元格合并、批注、自動篩選、豐富多格式字符串等;

·支持工作表PNG、JPEG圖像,自定義圖表;

·內存優化模式支持寫入大文件。

1.XlsxWriter模塊的安裝方法如下:

 # pip install XlsxWriter ? ?#pip安裝方法 

# easy_install XlsxWriter ? ?#easy_install安裝方法 

#源碼安裝方法 

# curl -O -L http://github.com/jmcnamara/XlsxWriter/archive/master.tar.gz 

# tar zxvf master.tar.gz 

# cd XlsxWriter-master/ 

# sudo python setup.py install

下面通過一個簡單的功能演示示例,實現插入文字(中英字符)、數字(求和計算)、圖片、單元格格式等,代碼如下:

【/home/test/XlsxWriter/simple1.py】

#coding: utf-8

import xlsxwriter

workbook = xlsxwriter.Workbook(’demo1.xlsx’) ? ?#創建一個Excel文件 worksheet =

workbook.add_worksheet() ? ?#創建一個工作表對象

worksheet.set_column(’A:A’, 20) ? ?#設定第一列(A)寬度為20像素

bold= workbook.add_format({‘bold’: True}) ? ?#定義一個加粗的格式對象

worksheet.write(’A1’, ‘Hello’) ? ?#A1單元格寫入’Hello’

worksheet.write(’A2’, ‘World’, bold) ? ?#A2單元格寫入’World’并引用加粗格式對象bold

worksheet.write(’B2’, u’中文測試’, bold) ? ?#B2單元格寫入中文并引用加粗格式對象bold

worksheet.write(2, 0, 32) ? ?#用行列表示法寫入數字’32’與’35.5′

worksheet.write(3, 0, 35.5) ? ?#行列表示法的單元格下標以0作為起始值,’3,0’等價于’A3’

worksheet.write(4, 0, ‘=SUM(A3:A4)’) ? ?#求A3:A4的和,并將結果寫入’4,0’,即’A5’

worksheet.insert_image(’B5’, ‘img/python-logo.png’) ? ?#在B5單元格插入圖片

workbook.close() ? ?#關閉Excel文件

程序生成的demo1.xlsx文檔截圖如圖1-1所示。

Python模塊及詳解(2)

圖3-1 demo1.xlsx文檔截圖

2.模塊常用方法說明

2.1Workbook類

Workbook類定義:Workbook(filename[,options]),該類實現創建一個XlsxWriter的Workbook對象。Workbook類代表整個電子表格文件,并且存儲在磁盤上。參數filename(String類型)為創建的Excel文件存儲路徑;參數options(Dict類型)為可選的Workbook參數,一般作為初始化工作表內容格式,例如值為{‘strings_to_numbers’:True}表示使用worksheet.write()方法時激活字符串轉換數字。

·add_worksheet([sheetname])方法,作用是添加一個新的工作表,參數sheetname(String類型)為可選的工作表名稱,默認為Sheet1。例如,下面的代碼對應的效果圖如圖3-2所示。

worksheet1 = workbook.add_worksheet() ? ? ? ? ? ? # Sheet1 

worksheet2 = workbook.add_worksheet('Foglio2') ? ?# Foglio2 

worksheet3 = workbook.add_worksheet('Data') ? ? ? # Data 

worksheet4 = workbook.add_worksheet() ? ? ? ? ? ? ? ?#Sheet4

Python模塊及詳解(2)

圖3-2 添加新工作表

·add_format([properties])方法,作用是在工作表中創建一個新的格式對象來格式化單元格。參數properties(dict類型)為指定一個格式屬性的字典,例如設置一個加粗的格式對象,workbook.add_format({‘bold’:True})。通過Format methods(格式化方法)也可以實現格式的設置,等價的設置加粗格式代碼如下:

bold = workbook.add_format()

bold.set_bold()

更多格式化方法見http://xlsxwriter.readthedocs.org/working_with_formats.html。

·add_chart(options)方法,作用是在工作表中創建一個圖表對象,內部是通過insert_chart()方法來實現,參數options(dict類型)為圖表指定一個字典屬性,例如設置一個線條類型的圖表對象,代碼為chart=workbook.add_chart({‘type’:’line’})。

·close()方法,作用是關閉工作表文件,如workbook.close()。

2.2Worksheet類

Worksheet類代表了一個Excel工作表,是XlsxWriter模塊操作Excel內容最核心的一個類,例如將數據寫入單元格或工作表格式布局等。Worksheet對象不能直接實例化,取而代之的是通過Workbook對象調用add_worksheet()方法來創建。Worksheet類提供了非常豐富的操作Excel內容的方法,其中幾個常用的方法如下:

·write(row,col,*args)方法,作用是寫普通數據到工作表的單元格,參數row為行坐標,col為列坐標,坐標索引起始值為0;*args無名字參數為數據內容,可以為數字、公式、字符串或格式對象。為了簡化不同數據類型的寫入過程,write方法已經作為其他更加具體數據類型方法的別名,包括:

·write_string()寫入字符串類型數據,如:

worksheet.write_string(0, 0, 'Your text here');

·write_number()寫入數字類型數據,如:

worksheet.write_number('A2', 2.3451);

·write_blank()寫入空類型數據,如:

worksheet.write('A2', None);

·write_formula()寫入公式類型數據,如:

worksheet.write_formula(2, 0, '=SUM(B1:B5)');

·write_datetime()寫入日期類型數據,如:

worksheet.write_datetime(7, 0,datetime.datetime.strptime('2013-01-23', '%Y-%m-%d'),workbook.add_format({'num_format': 'yyyy-mm-dd'}));

·write_boolean()寫入邏輯類型數據,如:

worksheet.write_boolean(0, 0, True);

·write_url()寫入超鏈接類型數據,如:

worksheet.write_url('A1', 'ftp://www.python.org/')。

下列通過具體的示例來觀察別名write方法與數據類型方法的對應關系,代碼如下:

worksheet.write(0, 0, 'Hello') ? ? ? ? ?# write_string() 
worksheet.write(1, 0, 'World') ? ? ? ? ?# write_string() 
worksheet.write(2, 0, 2) ? ? ? ? ? ? ? ?# write_number()
worksheet.write(3, 0, 3.00001) ? ? ? ? ?# write_number() 
worksheet.write(4, 0, '=SIN(PI()/4)') ? # write_formula() 
worksheet.write(5, 0, '') ? ? ? ? ? ? ? # write_blank() 
worksheet.write(6, 0, None) ? ? ? ? ? ? # write_blank()

上述示例將創建一個如圖3-3所示的工作表。

Python模塊及詳解(2)

圖3-3 創建單元格并寫入數據的工作表

·set_row(row,height,cell_format,options)方法,作用是設置行單元格的屬性。參數row(int類型)指定行位置,起始下標為0;參數height(float類型)設置行高,單位像素;參數cell_format(format類型)指定格式對象;參數options(dict類型)設置行hidden(隱藏)、level(組合分級)、collapsed(折疊)。操作示例如下:

worksheet.write('A1', 'Hello') ? ? #在A1單元格寫入'Hello'字符串 
cell_format = workbook.add_format({'bold': True}) ? ?#定義一個加粗的格式對象 
worksheet.set_row(0, 40, cell_format) ? ?#設置第1行單元格高度為40像素,且引用加粗 ? 格式對象 
worksheet.set_row(1, None, None, {'hidden': True}) ? ?#隱藏第2行單元格

上述示例將創建一個如圖3-4所示的工作表。

Python模塊及詳解(2)

圖3-4 設置行單元格屬性后的效果

·set_column(first_col,last_col,width,cell_format,options)方法,作用為設置一列或多列單元格屬性。參數first_col(int類型)指定開始列位置,起始下標為0;參數last_col(int類型)指定結束列位置,起始下標為0,可以設置成與first_col一樣;參數width(float類型)設置列寬;參數cell_format(Format類型)指定格式對象;參數options(dict類型)設置行hidden(隱藏)、level(組合分級)、collapsed(折疊)。操作示例如下:

worksheet.write('A1', 'Hello') ? ? #在A1單元格寫入'Hello'字符串 
worksheet.write('B1', 'World') ? ? #在B1單元格寫入'World'字符串 
cell_format = workbook.add_format({'bold': True}) ? ?#定義一個加粗的格式對象設置0到1即(A到B) 列單元格寬度為10像素,且引用加粗格式對象 
worksheet.set_column(0,1, 10,cell_format) 
worksheet.set_column('C:D', 20) ? ?#設置C到D列單元格寬度為20像素 
worksheet.set_column('E:G', None, None, {'hidden': 1}) ? ?#隱藏E到G列單元格

·insert_image(row,col,image[,options])方法,作用是插入圖片到指定單元格,支持PNG、JPEG、BMP等圖片格式。參數row為行坐標,col為列坐標,坐標索引起始值為0;參數image(string類型)為圖片路徑;參數options(dict類型)為可選參數,作用是指定圖片的位置、比例、鏈接URL等信息。操作示例如下:

#在B5單元格插入python-logo.png圖片,圖片超級鏈接為http://python.org 
worksheet.insert_image('B5', 'img/python-logo.png', {'url': 'http://python.org'})

2.3Chart類

Chart類實現在XlsxWriter模塊中圖表組件的基類,支持的圖表類型包括面積、條形圖、柱形圖、折線圖、餅圖、散點圖、股票和雷達等,一個圖表對象是通過Workbook(工作簿)的add_chart方法創建,通過{type,’圖表類型’}字典參數指定圖表的類型,語句如下:

chart = workbook.add_chart({type, ‘column’}) ? ?#創建一個column(柱形)圖表 更多圖表類型說明:

·area:創建一個面積樣式的圖表;

·bar:創建一個條形樣式的圖表;

·column:創建一個柱形樣式的圖表;

·line:創建一個線條樣式的圖表;

·pie:創建一個餅圖樣式的圖表;

·scatter:創建一個散點樣式的圖表;

·stock:創建一個股票樣式的圖表;

·radar:創建一個雷達樣式的圖表。

然后再通過Worksheet(工作表)的insert_chart()方法插入到指定位置,語句如下:

worksheet.insert_chart(’A7’, chart) ? ?#在A7單元格插入圖表

下面介紹chart類的幾個常用方法。

·chart.add_series(options)方法,作用為添加一個數據系列到圖表,參數options(dict類型)設置圖表系列選項的字典,操作示例如下:

chart.add_series({

 ? ? 'categories': '=Sheet1!$A$1:$A$5',

 ? ? 'values': ? ? '=Sheet1!$B$1:$B$5',

 ? ? 'line': ? ? ? {'color': 'red'},

 })

add_series方法最常用的三個選項為categories、values、line,其中categories作為是設置圖表類別標簽范圍;values為設置圖表數據范圍;line為設置圖表線條屬性,包括顏色、寬度等。

·其他常用方法及示例。

·set_x_axis(options)方法,設置圖表X軸選項,示例代碼如下,效果圖如圖3-7所示。

chart.set_x_axis({

 ? ? 'name': 'Earnings per Quarter', ? ?#設置X軸標題名稱

 ? ? 'name_font': {'size': 14, 'bold': True}, ?#設置X軸標題字體屬性

 ? ? 'num_font': ?{'italic': True }, ? ?#設置X軸數字字體屬性

})

Python模塊及詳解(2)

圖3-7 設置圖表X軸選項

·set_size(options)方法,設置圖表大小,如chart.set_size({‘width’:720,’height’:576}),其中width為寬度,height為高度。

·set_title(options)方法,設置圖表標題,如chart.set_title({‘name’:’Year End Results’}),效果圖如圖3-8所示。

Python模塊及詳解(2)

圖3-8 設置圖表標題

·set_style(style_id)方法,設置圖表樣式,style_id為不同數字則代表不同樣式,如chart.set_style(37),效果圖如圖3-9所示。

Python模塊及詳解(2)

圖3-9 設置圖表樣式

·set_table(options)方法,設置X軸為數據表格形式,如chart.set_table(),效果圖如圖3-10所示。

Python模塊及詳解(2)

圖3-10 設置X軸為數據表格形式

3.實踐:定制自動化業務流量報表周報

本次實踐通過定制網站5個頻道的流量報表周報,通過XlsxWriter模塊將流量數據寫入Excel文檔,同時自動計算各頻道周平均流量,再生成數據圖表。具體是通過workbook.add_chart({‘type’:’column’})方法指定圖表類型為柱形,使用write_row、write_column方法分別以行、列方式寫入數據,使用add_format()方法定制表頭、表體的顯示風格,使用add_series()方法將數據添加到圖表,同時使用chart.set_size、set_title、大小及標題屬性,最后通過insert_chart方法將圖表插入工作表中。我們可以結合2.3節的內容來實現周報的郵件推送,本示例略去此功能。實現的代碼如下:

【/home/test/XlsxWriter/simple2.py】 

#coding: utf-8 

import xlsxwriter 

workbook = xlsxwriter.Workbook('chart.xlsx') ? ?#創建一個Excel文件 worksheet = 

workbook.add_worksheet() ? ?#創建一個工作表對象 

chart = workbook.add_chart({'type': 'column'}) ? ?#創建一個圖表對象 

#定義數據表頭列表 

title = [u'業務名稱',u'星期一',u'星期二',u'星期三',u'星期四',u'星期五',u'星期六',u'星期日',u'平均流量'] buname= [u'業務官網',u'新聞中心',u'購物頻道',u'體育頻道',u'親子頻道'] ? ?#定義頻道名稱 

#定義5頻道一周7天流量數據列表 

data = [ 

? ? [150,152,158,149,155,145,148],

 ? ? [89,88,95,93,98,100,99],

 ? ? [201,200,198,175,170,198,195],

 ? ? [75,77,78,78,74,70,79],

 ? ? [88,85,87,90,93,88,84],

 ] 

format=workbook.add_format() ? ?#定義format格式對象 

format.set_border(1) ? ?#定義format對象單元格邊框加粗(1像素)的格式 

format_title=workbook.add_format() ? ?#定義format_title格式對象 

format_title.set_border(1) ? #定義format_title對象單元格邊框加粗(1像素)的格式 

format_title.set_bg_color('#cccccc') ? #定義format_title對象單元格背景顏色為 ? ? ? ? ? ? ? ? ? ? ? ? ?#'#cccccc'的格式 

format_title.set_align('center') ? ?#定義format_title對象單元格居中對齊的格式 

format_title.set_bold() ? ?#定義format_title對象單元格內容加粗的格式 

format_ave=workbook.add_format() ? ?#定義format_ave格式對象 

format_ave.set_border(1) ? ?#定義format_ave對象單元格邊框加粗(1像素)的格式 

format_ave.set_num_format('0.00') ? #定義format_ave對象單元格數字類別顯示格式

#下面分別以行或列寫入方式將標題、業務名稱、流量數據寫入起初單元格,同時引用不同格式對象 

worksheet.write_row('A1',title,format_title) ? 

worksheet.write_column('A2', buname,format) 

worksheet.write_row('B2', data[0],format) 

worksheet.write_row('B3', data[1],format) 

worksheet.write_row('B4', data[2],format) 

worksheet.write_row('B5', data[3],format) 

worksheet.write_row('B6', data[4],format) 

#定義圖表數據系列函數 

def chart_series(cur_row):

 ? ? worksheet.write_formula('I'+cur_row, \

 ? ? ?'=AVERAGE(B'+cur_row+':H'+cur_row+')',format_ave) ? ?#計算(AVERAGE函數)頻 ? 道周平均流量 ? ? 

chart.add_series({

 ? ? ? ? 'categories': '=Sheet1!$B$1:$H$1', ? ?#將“星期一至星期日”作為圖表數據標簽(X軸) 

? ? ? ? 'values': ? ? '=Sheet1!$B$'+cur_row+':$H$'+cur_row, ? ?#頻道一周所有數據作 ? ? ? ? ? 為數據區域 

? ? ? ? 'line': ? ? ? {'color': 'black'}, ? ?#線條顏色定義為black(黑色)

 ? ? ? ? 'name': '=Sheet1!$A$'+cur_row, ? ?#引用業務名稱為圖例項

 ? ? })

 for row in range(2, 7): ? ?#數據域以第2~6行進行圖表數據系列函數調用 ? ? 

chart_series(str(row))

 #chart.set_table() ? ?#設置X軸表格格式,本示例不啟用

 #chart.set_style(30) ? ?#設置圖表樣式,本示例不啟用

 chart.set_size({'width': 577, 'height': 287}) ? ?#設置圖表大小

 chart.set_title ({'name': u'業務流量周報圖表'}) ? ?#設置圖表(上方)大標題 

chart.set_y_axis({'name': 'Mb/s'}) ? ?#設置y軸(左側)小標題 

worksheet.insert_chart('A8', chart) ? ?#在A8單元格插入圖表 

workbook.close() ? ?#關閉Excel文檔

上述示例將創建一個如圖3-11所示的工作表。

Python模塊及詳解(2)

圖3-11 業務流量周報圖表工作表 參考提示

XlsxWrite模塊的常用類與方法說明參考官網http://xlsxwriter.readthedocs.org。

二、Python與rrdtool的結合模塊

rrdtool(round robin database)工具為環狀數據庫的存儲格式,round robin是一種處理定量數據以及當前元素指針的技術。rrdtool主要用來跟蹤對象的變化情況,生成這些變化的走勢圖,比如業務的訪問流量、系統性能、磁盤利用率等趨勢圖,很多流行監控平臺都使用到rrdtool,比較有名的為Cacti、Ganglia、Monitorix等。更多rrdtool介紹見官網http://oss.oetiker.ch/rrdtool/。rrdtool是一個復雜的工具,涉及較多參數概念,本節主要通過Python的rrdtool模塊對rrdtool的幾個常用方法進行封裝,包括create、fetch、graph、info、update等方法,本節對rrdtool的基本知識不展開說明,重點放在Python rrdtool模塊的常用方法使用介紹上。

1.rrdtool模塊的安裝方法:

easy_install python-rrdtool ? ?#pip安裝方法

pip install python-rrdtool ? ?#easy_install安裝方法#需要rrdtool工具及其他類包支持,

CentOS環境推薦使用yum安裝方法 # yum install rrdtool-python

2.rrdtool模塊常用方法說明

下面介紹rrdtool模塊常用的幾個方法,包括create(創建rrd)、update(更新rrd)、graph(繪圖)、fetch(查詢rrd)等。

2.1Create方法create filename[–start|-b start time][–step|-s step][DS:ds-name:DST:heartbeat:min:max][RRA:CF:xff:steps:rows]方法,創建一個后綴為rrd的rrdtool數據庫,參數說明如下:

·filename創建的rrdtool數據庫文件名,默認后綴為.rrd;

·–start指定rrdtool第一條記錄的起始時間,必須是timestamp的格式;

·–step指定rrdtool每隔多長時間就收到一個值,默認為5分鐘;

·DS用于定義數據源,用于存放腳本的結果的變量;

·DST用于定義數據源類型,rrdtool支持COUNTER(遞增類型)、DERIVE(可遞增可遞減類型)、ABSOLUTE(假定前一個時間間隔的值為0,再計算平均值)、GUAGE(收到值后直接存入RRA)、COMPUTE(定義一個表達式,引用DS并自動計算出某個值)5種,比如網卡流量屬于計數器型,應該選擇COUNTER;

·RRA用于指定數據如何存放,我們可以把一個RRA看成一個表,保存不同間隔的統計結果數據,為CF做數據合并提供依據,定義格式為:[RRA:CF:xff:steps:rows];

·CF統計合并數據,支持AVERAGE(平均值)、MAX(最大值)、MIN(最小值)、LAST(最新值)4種方式。

2.2update方法

update filename[–template|-t ds-name[:ds-name]…]N|timestamp:value[:value…][timestamp:value[:value…]…]方法,存儲一個新值到rrdtool數據庫,updatev和update類似,區別是每次插入后會返回一個狀態碼,以便了解是否成功(updatev用0表示成功,–1表示失?。嫡f明如下:

·filename指定存儲數據到的目標rrd文件名;

·-t ds-name[:ds-name]指定需要更新的DS名稱;

·N|Timestamp表示數據采集的時間戳,N表示當前時間戳;

·value[:value…]更新的數據值,多個DS則多個值。

2.3graph方法

graph filename[-s|–start seconds][-e|–end seconds][-x|–x-grid x-axis grid and label][-y|–y-grid y-axis grid and label][–alt-y-grid][–alt-y-mrtg][–alt-autoscale][–alt-autoscale-max][–units-exponent]value[-v|–vertical-label text][-w|–width pixels][-h|–height pixels][-i|–interlaced][-f|–imginfo formatstring][-a|–imgformat GIF|PNG|GD][-B|–background value][-O|–overlay value][-U|–unit value][-z|–lazy][-o|–logarithmic][-u|–upper-limit value][-l|–lower-limit value][-g|–no-legend][-r|–rigid][–step value][-b|–base value][-c|–color COLORTAG#rrggbb][-t|–title title][DEF:vname=rrd:ds-name:CF][CDEF:vname=rpn-expression][PRINT:vname:CF:format][GPRINT:vname:CF:format][COMMENT:text][HRULE:value#rrggbb[:legend]][VRULE:time#rrggbb[:legend]][LINE{1|2|3}:vname[#rrggbb[:legend]]][AREA:vname[#rrggbb[:legend]]][STACK:vname[#rrggbb[:legend]]]方法,根據指定的rrdtool數據庫進行繪圖,關鍵參數說明如下:

·filename指定輸出圖像的文件名,默認是PNG格式;

·–start指定起始時間;·–end指定結束時間;

·–x-grid控制X軸網格線刻度、標簽的位置;

·–y-grid控制Y軸網格線刻度、標簽的位置;

·–vertical-label指定Y軸的說明文字;

·–width pixels指定圖表寬度(像素);

·–height pixels指定圖表高度(像素);

·–imgformat指定圖像格式(GIF|PNG|GD);

·–background指定圖像背景顏色,支持#rrggbb表示法;

·–upper-limit指定Y軸數據值上限;

·–lower-limit指定Y軸數據值下限;

·–no-legend取消圖表下方的圖例;

·–rigid嚴格按照upper-limit與lower-limit來繪制;

·–title圖表頂部的標題;

·DEF:vname=rrd:ds-name:CF指定繪圖用到的數據源;

·CDEF:vname=rpn-expression合并多個值;

·GPRINT:vname:CF:format圖表的下方輸出最大值、最小值、平均值等;

·COMMENT:text指定圖表中輸出的一些字符串;

·HRULE:value#rrggbb用于在圖表上面繪制水平線;

·VRULE:time#rrggbb用于在圖表上面繪制垂直線;

·LINE{1|2|3}:vname使用線條來繪制數據圖表,{1|2|3}表示線條的粗細;

·AREA:vname使用面積圖來繪制數據圖表。

2.4fetch方法

fetch filename CF[–resolution|-r resolution][–start|-s start][–end|-e end]方法,根據指定的rrdtool數據庫進行查詢,關鍵參數說明如下:

·filename指定要查詢的rrd文件名;

·CF包括AVERAGE、MAX、MIN、LAST,要求必須是建庫時RRA中定義的類型,否則會報錯;

·–start–end指定查詢記錄的開始與結束時間,默認可省略。

3.實踐:實現網卡流量圖表繪制

在日常運營工作當中,觀察數據的變化趨勢有利于了解我們的服務質量,比如在系統監控方面,網絡流量趨勢圖直接展現了當前網絡的吞吐。CPU、內存、磁盤空間利用率趨勢則反映了服務器運行健康狀態。通過這些數據圖表管理員可以提前做好應急預案,對可能存在的風險點做好防范。本次實踐通過rrdtool模塊實現服務器網卡流量趨勢圖的繪制,即先通過create方法創建一個rrd數據庫,再通過update方法實現數據的寫入,最后可以通過graph方法實現圖表的繪制,以及提供last、first、info、fetch方法的查詢。圖3-12為rrd創建到輸出圖表的過程。

Python模塊及詳解(2)

圖3-12 創建、更新rrd及輸出圖表流程

第一步 采用create方法創建rrd數據庫,參數指定了一個rrd文件、更新頻率step、起始時間–start、數據源DS、數據源類型DST、數據周期定義RRA等,詳細源碼如下:

【/home/test/rrdtool/create.py】

# -*- coding: utf-8 -*- 

#!/usr/bin/python 

import rrdtool

 import time 

cur_time=str(int(time.time())) ? ?#獲取當前Linux時間戳作為rrd起始時間 

#數據寫頻率--step為300秒(即5分鐘一個數據點) 

rrd=rrdtool.create('Flow.rrd','--step','300','--start',cur_time, #定義數據源eth0_in(入流量)、eth0_out(出流量);類型都為COUNTER(遞增);600秒為心跳值, #其含義是600秒沒有收到值,則會用UNKNOWN代替;0為最小值;最大值用U代替,表示不確定

 ? 'DS:eth0_in:COUNTER:600:0:U',

 ? 'DS:eth0_out:COUNTER:600:0:U',

 ? #RRA定義格式為[RRA:CF:xff:steps:rows],

CF定義了AVERAGE、MAX、MIN三種數據合并方式 

? #xff定義為0.5,表示一個CDP中的PDP值如超過一半值為UNKNOWN,則該CDP的值就被標為UNKNOWN

 ? #下列前4個RRA的定義說明如下,其他定義與AVERAGE方式相似,區別是存最大值與最小值

 ? # 每隔5分鐘(1*300秒)存一次數據的平均值,600筆,即2.08天

 ? # 每隔30分鐘(6*300秒)存一次數據的平均值,存700筆,即14.58天(2周)

 ? # 每隔2小時(24*300秒)存一次數據的平均值,存775筆,即64.58天(2個月)

 ? # 每隔24小時(288*300秒)存一次數據的平均值,存797筆,即797天(2年)

 ? 'RRA:AVERAGE:0.5:1:600',

 ? ?'RRA:AVERAGE:0.5:6:700',

 ? 'RRA:AVERAGE:0.5:24:775',

 ? 'RRA:AVERAGE:0.5:288:797',

 ? 'RRA:MAX:0.5:1:600',

 ? ?'RRA:MAX:0.5:6:700',

 ? 'RRA:MAX:0.5:24:775',

 ? 'RRA:MAX:0.5:444:797',

 ? 'RRA:MIN:0.5:1:600',

 ? 'RRA:MIN:0.5:6:700',

 ? 'RRA:MIN:0.5:24:775',

 ? 'RRA:MIN:0.5:444:797')

 if rrd:

 ? ? print rrdtool.error()

第二步 采用updatev方法更新rrd數據庫,參數指定了當前的Linux時間戳,以及指定eth0_in、eth0_out值(當前網卡的出入流量),網卡流量我們通過psutil模塊來獲取,如psutil.net_io_counters()[1]為入流量。詳細源碼如下:

【/home/test/rrdtool/update.py】

 # -*- coding: utf-8 -*- 

#!/usr/bin/python 

import rrdtool

 import time,psutil

 total_input_traffic = psutil.net_io_counters()[1] ? ?#獲取網卡入流量 total_output_traffic = 

psutil.net_io_counters()[0] ? ?#獲取網卡出流量 

starttime=int(time.time()) ? ?#獲取當前Linux時間戳 #將獲取到的三個數據作為updatev的參數,返回{'return_value': 0L}則說明更新成功,反之失敗 

update=rrdtool.updatev('/home/test/rrdtool/Flow.rrd','%s:%s:%s' % (str(starttime),str(total_input_traffic),str(total_output_traffic)))

 print update 

將代碼加入crontab,并配置5分鐘作為采集頻率,crontab配置如下:

 */5 * * * * /usr/bin/python /home/test/rrdtool/update.py > /dev/null 2>&1

第三步 采用graph方法繪制圖表,此示例中關鍵參數使用了–x-grid定義X軸網格刻度;DEF指定數據源;使用CDEF合并數據;HRULE繪制水平線(告警線);GPRINT輸出最大值、最小值、平均值等。詳細源碼如下:

【/home/test/rrdtool/graph.py】

# -*- coding: utf-8 -*- 
#!/usr/bin/python 
import rrdtool
 import time
 #定義圖表上方大標題
 title="Server network ?traffic flow ("+time.strftime('%Y-%m-%d', \ 
time.localtime(time.time()))+")"
 #重點解釋"--x-grid","MINUTE:12:HOUR:1:HOUR:1:0:%H"參數的作用(從左往右進行分解)
“MINUTE:12”表示控制每隔12分鐘放置一根次要格線 
“HOUR:1”表示控制每隔1小時放置一根主要格線 
“HOUR:1”表示控制1個小時輸出一個label標簽
“0:%H”0表示數字對齊格線,%H表示標簽以小時顯示
rrdtool.graph( "Flow.png", "--start", "-1d","--vertical-label=Bytes/s",\
"--x-grid","MINUTE:12:HOUR:1:HOUR:1:0:%H",\ 
"--width","650","--height","230","--title",title,
"DEF:inoctets=Flow.rrd:eth0_in:AVERAGE", ? ?#指定網卡入流量數據源DS及CF ?
"DEF:outoctets=Flow.rrd:eth0_out:AVERAGE", ? ?#指定網卡出流量數據源DS及CF
"CDEF:total=inoctets,outoctets,+", ? ?#通過CDEF合并網卡出入流量,得出總流量total 
"LINE1:total#FF8833:Total traffic", ? ?#以線條方式繪制總流量 
"AREA:inoctets#00FF00:In traffic", ? ?#以面積方式繪制入流量 
"LINE1:outoctets#0000FF:Out traffic", ? ?#以線條方式繪制出流量 ?
"HRULE:6144#FF0000:Alarm value\\r", ? ?#繪制水平線,作為告警線,閾值為6.1k ?
CDEF:inbits=inoctets,8,*", ? ?#將入流量換算成bit,即*8,計算結果給inbits 
"CDEF:outbits=outoctets,8,*", ? ?#將出流量換算成bit,即*8,計算結果給outbits 
"COMMENT:\\r", ? ?#在網格下方輸出一個換行符 ?
"COMMENT:\\r", 
"GPRINT:inbits:AVERAGE:Avg In traffic\: %6.2lf %Sbps", ? ?#繪制入流量平均值
"COMMENT: ? ",
 ?"GPRINT:inbits:MAX:Max In traffic\: %6.2lf %Sbps", ? ?#繪制入流量最大值 ?"COMMENT: ?",
 ?"GPRINT:inbits:MIN:MIN In traffic\: %6.2lf %Sbps\\r", ? ?#繪制入流量最小值 
"COMMENT: ",
 ?"GPRINT:outbits:AVERAGE:Avg Out traffic\: %6.2lf %Sbps", ? ?#繪制出流量平均值 ?
"COMMENT: ", 
 ?"GPRINT:outbits:MAX:Max Out traffic\: %6.2lf %Sbps", ? ?#繪制出流量最大值 ?
"COMMENT: ", 
? "GPRINT:outbits:MIN:MIN Out traffic\: %6.2lf %Sbps\\r") ? ?#繪制出流量最小值

上代碼將生成一個Flow.png文件,如圖3-13所示。

提示查看rrd文件內容有利于觀察數據的結構、更新等情況,rrdtool提供幾個常用命令:

·info查看rrd文件的結構信息,如rrdtool info Flow.rrd;

·first查看rrd文件第一個數據的更新時間,如rrdtool first Flow.rrd;

·last查看rrd文件最近一次更新的時間,如rrdtool last Flow.rrd;

·fetch根據指定時間、CF查詢rrd文件,如rrdtool fetch Flow.rrd AVERAGE。

Python模塊及詳解(2)

圖3-13 graph.py執行輸出圖表 參考提示

rrdtool參數說明參考http://bbs.chinaunix.net/thread-2150417-1-1.html和http://oss.oetiker.ch/rrdtool/doc/index.en.html。

三、構建集中式的病毒掃描機制

Clam AntiVirus(ClamAV)是一款免費而且開放源代碼的防毒軟件,軟件與病毒庫的更新皆由社區免費發布,官網地址:http://www.clamav.net/lang/en/。目前ClamAV主要為Linux、Unix系統提供病毒掃描、查殺等服務。pyClamad(http://xael.org/norman/python/pyclamd/)是一個Python第三方模塊,可讓Python直接使用ClamAV病毒掃描守護進程clamd,來實現一個高效的病毒檢測功能,另外,pyClamad模塊也非常容易整合到我們已有的平臺當中。下面詳細進行說明。

1.pyClamad模塊的安裝

# 1、客戶端(病毒掃描源)安裝步驟

# yum install -y clamav clamd clamav-update ? #安裝clamavp相關程序包

# chkconfig --levels 235 clamd on ? ?#添加掃描守護進程clamd系統服務 

# /usr/bin/freshclam ? ?#更新病毒庫,建議配置到crontab中定期更新 

# setenforce 0 ? ?#關閉SELinux,避免遠程掃描時提示無權限的問題 

# 更新守護進程監聽IP配置文件,根據不同環境自行修改監聽的IP,“0.0.0.0”為監聽所有主機IP 

# sed -i -e '/^TCPAddr/{ s/127.0.0.1/0.0.0.0/; }' /etc/clamd.conf 

# /etc/init.d/clamd start ? ?#啟動掃描守護進程

# 2、主控端部署pyClamad環境步驟

 # wget http://xael.org/norman/python/pyclamd/pyClamd-0.3.4.tar.gz 

# tar -zxvf pyClamd-0.3.4.tar.gz 

# cd pyClamd-0.3.4 

# python setup.py install

2.模塊常用方法說明

pyClamad提供了兩個關鍵類,一個為ClamdNetworkSocket()類,實現使用網絡套接字操作clamd;另一個為ClamdUnixSocket()類,實現使用Unix套接字類操作clamd。兩個類定義的方法完全一樣,本節以ClamdNetworkSocket()類進行說明。

·__init__(self,host=’127.0.0.1’,port=3310,timeout=None)方法,是ClamdNetworkSocket類的初始化方法,參數host為連接主機IP;參數port為連接的端口,默認為3310,與/etc/clamd.conf配置文件中的TCPSocket參數要保持一致;timeout為連接的超時時間。

·contscan_file(self,file)方法,實現掃描指定的文件或目錄,在掃描時發生錯誤或發現病毒將不終止,參數file(string類型)為指定的文件或目錄的絕對路徑。

·multiscan_file(self,file)方法,實現多線程掃描指定的文件或目錄,多核環境速度更快,在掃描時發生錯誤或發現病毒將不終止,參數file(string類型)為指定的文件或目錄的絕對路徑。

·scan_file(self,file)方法,實現掃描指定的文件或目錄,在掃描時發生錯誤或發現病毒將終止,參數file(string類型)為指定的文件或目錄的絕對路徑。

·shutdown(self)方法,實現強制關閉clamd進程并退出。

·stats(self)方法,獲取Clamscan的當前狀態。

·reload(self)方法,強制重載clamd病毒特征庫,掃描前建議做reload操作。

·EICAR(self)方法,返回EICAR測試字符串,即生成具有病毒特征的字符串,便于測試。

3.實踐:實現集中式的病毒掃描

本次實踐實現了一個集中式的病毒掃描管理,可以針對不同業務環境定制掃描策略,比如掃描對象、描述模式、掃描路徑、調度頻率等。示例實現的架構見圖4-1,首先業務服務器開啟clamd服務(監聽3310端口),管理服務器啟用多線程對指定的服務集群進行掃描,掃描模式、掃描路徑會傳遞到clamd,最后返回掃描結果給管理服務器端。

Python模塊及詳解(2)

圖4-1 集群病毒掃描架構圖

本次實踐通過ClamdNetworkSocket()方法實現與業務服務器建立掃描socket連接,再通過啟動不同掃描方式實施病毒掃描并返回結果。實現代碼如下:【/home/test/pyClamad/simple1.py】

 #!/usr/bin/env python 

# -*- coding: utf-8 -*- 

import time

 import pyclamd

 from threading import Thread

class Scan(Thread):

 ? ? def __init__ (self,IP,scan_type,file):

 ? ? ? ? """構造方法,參數初始化"""

 ? ? ? ? Thread.__init__(self)

 ? ? ? ? self.IP = IP

 ? ? ? ? self.scan_type=scan_type

 ? ? ? ? self.file = file ? ? ? ? self.connstr="" 

? ? ? ? self.scanresult=""

 ? ? def run(self):

 ? ? ? ? """多進程run方法"""

 ? ? ? ? try:

 ? ? ? ? ? ? cd = pyclamd.ClamdNetworkSocket(self.IP,3310) ? ?#創建網絡套接字連接對象

 ? ? ? ? ? ? if cd.ping(): ? ?#探測連通性

 ? ? ? ? ? ? ? ? self.connstr=self.IP+" connection [OK]"

 ? ? ? ? ? ? ? ? cd.reload() ? ?#重載clamd病毒特征庫,建議更新病毒庫后做reload()操作

 ? ? ? ? ? ? ? ? if self.scan_type=="contscan_file": ? ?#選擇不同的掃描模式

 ? ? ? ? ? ? ? ? ? ? self.scanresult="{0}\n".format(cd.contscan_file(self.file))

 ? ? ? ? ? ? ? ? elif self.scan_type=="multiscan_file":

 ? ? ? ? ? ? ? ? ? ? self.scanresult="{0}\n".format(cd.multiscan_file(self.file))

 ? ? ? ? ? ? ? ? elif self.scan_type=="scan_file":

 ? ? ? ? ? ? ? ? ? ? self.scanresult="{0}\n".format(cd.scan_file(self.file))

 ? ? ? ? ? ? ? ? time.sleep(1) ? ?#線程掛起1秒

 ? ? ? ? ? ? else:

 ? ? ? ? ? ? ? ? self.connstr=self.IP+" ping error,exit"

 ? ? ? ? ? ? ? ? return ? ? ? ? except Exception,e:

 ? ? ? ? ? ? self.connstr=self.IP+" "+str(e)

 IPs=['192.168.1.21','192.168.1.22'] ? ?#掃描主機列表

 scantype="multiscan_file" ? ?#指寫掃描模式,支持multiscan_file、contscan_file、scan_file 

scanfile="/data/www" ? ?#指定掃描路徑

 i=1

 threadnum=2 ? ?#指定啟動的線程數 

scanlist = [] ? ?#存儲掃描Scan類線程對象列表

 for ip in IPs:

 ? ? currp = Scan(ip,scantype,scanfile)#創建掃描Scan類對象,參數(IP,掃描模式,掃描路徑)

 ? ? scanlist.append(currp) ? ?#追加對象到列表 

? ? if i%threadnum==0 or i==len(IPs): ? ?#當達到指定的線程數或IP列表數后啟動、退出線程 

? ? ? ? for task in scanlist:

 ? ? ? ? ? ? task.start() ? ?#啟動線程

 ? ? ? ? for task in scanlist:

 ? ? ? ? ? ? task.join() ? ?#等待所有子線程退出,并輸出掃描結果

 ? ? ? ? ? ? print task.connstr ? ?#打印服務器連接信息

 ? ? ? ? ? ? print task.scanresult ? ?#打印掃描結果

 ? ? ? ? scanlist = []

i+=1

通過EICAR()方法生成一個帶有病毒特征的文件/tmp/EICAR,代碼如下:

void = open(’/tmp/EICAR’,’w’).write(cd.EICAR())

生成帶有病毒特征的字符串內容如下,復制文件/tmp/EICAR到目標主機的掃描目錄當中,以便進行測試。

#cat /tmp/EICAR

u’X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*’

最后,啟動掃描程序,在本次實踐過程中啟用兩個線程,可以根據目標主機數量隨意修改,代碼運行結果如圖4-2,其中192.168.1.21主機沒有發現病毒,192.168.1.22主機發現了病毒測試文件EICAR。 圖4-2 集中式病毒掃描程序運行結果 參考提示

pyClamad模塊方法說明參考http://xael.org/norman/python/pyclamd/pyclamd.html。

 

四、系統批量運維管理器paramiko詳解

paramiko是基于Python實現的SSH2遠程安全連接,支持認證及密鑰方式。可以實現遠程命令執行、文件傳輸、中間SSH代理等功能,相對于Pexpect,封裝的層次更高,更貼近SSH協議的功能,官網地址:http://www.paramiko.org。

1.paramiko的安裝

paramiko支持pip、easy_install或源碼安裝方式,很方便解決包依賴的問題,具體安裝命令如下(根據用戶環境,自行選擇pip或easy_install):

pip install paramiko

easy_install paramiko paramiko

依賴第三方的Crypto、Ecdsa包及Python開發包python-devel的支持,源碼安裝步驟如下:

# yum -y install python-devel 

# wget http://ftp.dlitz.net/pub/dlitz/crypto/pycrypto/pycrypto-2.6.tar.gz

# tar -zxvf pycrypto-2.6.tar.gz 

# cd pycrypto-2.6

# python setup.py install 

# cd ..

# wget https://pypi.python.org/packages/source/e/ecdsa/ecdsa-0.10.tar.gz --no-check-certificate 

# tar -zxvf ecdsa-0.10.tar.gz 

# cd ecdsa-0.10 

# python setup.py install 

# cd .. 

# wget https://github.com/paramiko/paramiko/archive/v1.12.2.tar.gz 

# tar -zxvf v1.12.2.tar.gz

# cd paramiko-1.12.2/

# python setup.py install

校驗安裝結果,導入模塊沒有提示異常則說明安裝成功:

# python

Python 2.6.6 (r266:84292, Jul 10 2013, 22:48:45)

[GCC 4.4.7 20120313 (Red Hat 4.4.7-3)] on linux2

Type “help”, “copyright”, “credits” or “license” for more information.

>>> import paramiko

>>>

下面介紹一個簡單實現遠程SSH運行命令的示例。該示例使用密碼認證方式,通過exec_command()方法

源碼如下:

【/home/test/paramiko/simple1.py】

#!/usr/bin/env python 
import paramiko
hostname='192.168.1.21'
username='root' 
password='SKJh935yft
#' paramiko.util.log_to_file('syslogin.log') #發送paramiko日志到syslogin.log文件 
ssh=paramiko.SSHClient() #創建一個ssh客戶端client對象 
ssh.load_system_host_keys() #獲取客戶端host_keys,默認~/.ssh/known_hosts,非默認路 ? ? ?徑需指定 
ssh.connect(hostname=hostname,username=username,password=password) #創建ssh連接 
stdin,stdout,stderr=ssh.exec_command('free -m') #調用遠程執行命令方法exec_command() 
print stdout.read() ?#打印命令執行結果,得到Python列表形式,可以使用stdout.readlines() s
sh.close() ?#關閉ssh連接

程序的運行結果截圖如圖6-1所示。

Python模塊及詳解(2)

圖6-1 程序運行結果

2.核心組件

paramiko包含兩個核心組件,一個為SSHClient類,另一個為SFTPClient類,下面詳細介紹。

2.1SSHClient類

SSHClient類是SSH服務會話的高級表示,該類封裝了傳輸(transport)、通道(channel)及SFTPClient的校驗、建立的方法,通常用于執行遠程命令,下面是一個簡單的例子:

client = SSHClient()

client.load_system_host_keys()

client.connect(’ssh.example.com’)

stdin, stdout, stderr = client.exec_command(’ls -l’)

下面介紹SSHClient常用的幾個方法。

1.connect方法

connect方法實現了遠程SSH連接并校驗。

方法定義:

connect(self, hostname, port=22, username=None, password=None, pkey=None, key_filename=None, timeout=None, allow_agent=True, look_for_keys=True, compress=False)

參數說明:

·hostname(str類型),連接的目標主機地址;

·port(int類型),連接目標主機的端口,默認為22;

·username(str類型),校驗的用戶名(默認為當前的本地用戶名);

·password(str類型),密碼用于身份校驗或解鎖私鑰;

·pkey(PKey類型),私鑰方式用于身份驗證;

·key_filename(str or list(str)類型),一個文件名或文件名的列表,用于私鑰的身份驗證;

·timeout(float類型),一個可選的超時時間(以秒為單位)的TCP連接;

·allow_agent(bool類型),設置為False時用于禁用SSH代理;

·look_for_keys(bool類型),設置為False時用來禁用在~/.ssh中搜索私鑰文件;

·compress(bool類型),設置為True時打開壓縮。

2.exec_command方法

遠程命令執行方法,該命令的輸入與輸出流為標準輸入(stdin)、輸出(stdout)、錯誤(stderr)的Python文件對象,方法定義:

 exec_command(self, command, bufsize=-1)

參數說明:

·command(str類型),執行的命令串;

·bufsize(int類型),文件緩沖區大小,默認為–1(不限制)。

3.load_system_host_keys方法

加載本地公鑰校驗文件,默認為~/.ssh/known_hosts,非默認路徑需要手工指定,方法定義:

load_system_host_keys(self, filename=None)

參數說明:

filename(str類型),指定遠程主機公鑰記錄文件。

4.set_missing_host_key_policy方法

設置連接的遠程主機沒有本地主機密鑰或HostKeys對象時的策略,目前支持三種,分別是AutoAddPolicy、RejectPolicy(默認)、WarningPolicy,僅限用于SSHClient類,分別代表的含義如下:

·AutoAddPolicy,自動添加主機名及主機密鑰到本地HostKeys對象,并將其保存,不依賴load_system_host_keys()的配置,即使~/.ssh/known_hosts不存在也不產生影響;

·RejectPolicy,自動拒絕未知的主機名和密鑰,依賴load_system_host_keys()的配置;

·WarningPolicy,用于記錄一個未知的主機密鑰的Python警告,并接受它,功能上與AutoAddPolicy相似,但未知主機會有告警。使用方法如下:

ssh=paramiko.SSHClient()

missing_host_key_policy(paramiko.AutoAddPolicy())

2.2SFTPClient類

SFTPClient作為一個SFTP客戶端對象,根據SSH傳輸協議的sftp會話,實現遠程文件操作,比如文件上傳、下載、權限、狀態等操作,下面介紹SFTPClient類的常用方法。

1.from_transport方法

創建一個已連通的SFTP客戶端通道,方法定義:

from_transport(cls, t)

參數說明:

t(Transport),一個已通過驗證的傳輸對象。

例子說明:

t = paramiko.Transport(("192.168.1.22",22))

t.connect(username="root", password="KJSdj348g")

sftp =paramiko.SFTPClient.from_transport(t)

2.put方法

上傳本地文件到遠程SFTP服務端,方法定義:

 put(self, localpath, remotepath, callback=None, confirm=True)

參數說明:

·localpath(str類型),需上傳的本地文件(源);

·remotepath(str類型),遠程路徑(目標);

·callback(function(int,int)),獲取已接收的字節數及總傳輸字節數,以便回調函數調用,默認為None;

·confirm(bool類型),文件上傳完畢后是否調用stat()方法,以便確認文件的大小。

例子說明:

localpath=’/home/access.log’ remotepath=’/data/logs/access.log’ sftp.put(localpath,remotepath)

3.get方法

SFTP服務端下載文件到本地,方法定義:

get(self, remotepath, localpath, callback=None)

參數說明:

·remotepath(str類型),需下載的遠程文件(源);

·localpath(str類型),本地路徑(目標);

·callback(function(int,int)),獲取已接收的字節數及總傳輸字節數,以便回調函數調用,默認為None。

例子說明:

 remotepath='/data/logs/access.log'

 localpath='/home/access.log'

 sftp.get(remotepath, localpath)

4.其他方法

SFTPClient類其他常用方法說明:

·Mkdir,在SFTP服務器端創建目錄,如sftp.mkdir(”/home/userdir”,0755)。

·remove,刪除SFTP服務器端指定目錄,如sftp.remove(”/home/userdir”)。

·rename,重命名SFTP服務器端文件或目錄,如sftp.rename(”/home/test.sh”,”/home/testfile.sh”)。

·stat,獲取遠程SFTP服務器端指定文件信息,如sftp.stat(”/home/testfile.sh”)。

·listdir,獲取遠程SFTP服務器端指定目錄列表,以Python的列表(List)形式返回,如sftp.listdir(”/home”)。

5.SFTPClient類應用示例

下面為SFTPClient類的一個完整示例,實現了文件上傳、下載、創建與刪除目錄等,需要注意的是,put和get方法需要指定文件名,不能省略。詳細源碼如下:

#!/usr/bin/env python

import paramiko 

username = "root"

password = "KJsd8t34d"

hostname = "192.168.1.21"

port = 22

try:

? ? t = paramiko.Transport((hostname, port))

? ? t.connect(username=username, password=password)

? ? sftp =paramiko.SFTPClient.from_transport(t)

? ? sftp.put("/home/user/info.db", "/data/user/info.db") ?#上傳文件 ? ? 

    sftp.get("/data/user/info_1.db", "/home/user/info_1.db") ?#下載文件 ? ? 

    sftp.mkdir("/home/userdir",0755) ?#創建目錄 ? ? sftp.rmdir("/home/userdir") ?#刪除目錄 ? 

?   sftp.rename("/home/test.sh","/home/testfile.sh") ?#文件重命名 ? ? print 

    sftp.stat("/home/testfile.sh") ?#打印文件信息 ?

  ? print sftp.listdir("/home") ?#打印目錄列表 ? ? 

    t.close();

except Exception, e:

? ? print str(e)

3.paramiko應用示例

3.1 ? 實現密鑰方式登錄遠程主機

實現自動密鑰登錄方式,第一步需要配置與目標設備的密鑰認證支持,具體見9.2.5節,私鑰文件可以存放在默認路徑“~/.ssh/id_rsa”,當然也可以自定義,如本例的“/home/key/id_rsa”,通過paramiko.RSAKey.from_private_key_file()方法引用,詳細代碼如下:【/home/test/paramiko/simple2.py】

 #!/usr/bin/env python

 import paramiko

 import os

 hostname='192.168.1.21'

 username='root' paramiko.util.log_to_file('syslogin.log')

 ssh=paramiko.SSHClient()

 ssh.load_system_host_keys() privatekey = os.path.expanduser('/home/key/id_rsa') ?#定義私鑰存放路徑 

 key = paramiko.RSAKey.from_private_key_file(privatekey) ?#創建私鑰對象key s

 sh.connect(hostname=hostname,username=username,pkey = key) 

 stdin,stdout,stderr=ssh.exec_command('free -m') 

 print stdout.read()

 ssh.close()

程序執行結果見圖6-1。

3.2 實現堡壘機模式下的遠程命令執行

堡壘機環境在一定程度上提升了運營安全級別,但同時也提高了日常運營成本,作為管理的中轉設備,任何針對業務服務器的管理請求都會經過此節點,比如SSH協議,首先運維人員在辦公電腦通過SSH協議登錄堡壘機,再通過堡壘機SSH跳轉到所有的業務服務器進行維護操作,如圖6-2所示。

Python模塊及詳解(2)

圖6-2 堡壘機模式下的遠程命令執行我們可以利用paramiko的invoke_shell機制來實現通過堡壘機實現服務器操作,原理是SSHClient.connect到堡壘機后開啟一個新的SSH會話(session),通過新的會話運行”ssh user@IP”去實現遠程執行命令的操作。實現代碼如下:【/home/test/paramiko/simple3.py】

 #!/usr/bin/env python

 import paramiko

 import os,sys,time

 blip="192.168.1.23" ? ?#定義堡壘機信息

 bluser="root"

 blpasswd="KJsdiug45"

 hostname="192.168.1.21" ? ?#定義業務服務器信息 

 username="root"

 password="IS8t5jgrie" 

 port=22 

 passinfo='\'s password: ' ? ?#輸入服務器密碼的前標志串 

 paramiko.util.log_to_file('syslogin.log') 

 ssh=paramiko.SSHClient() ? ?#ssh登錄堡壘機 

 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 

 ssh.connect(hostname=blip,username=bluser,password=blpasswd) 

 channel=ssh.invoke_shell() ? ?#創建會話,開啟命令調用 

 channel.settimeout(10) ? ?#會話命令執行超時時間,單位為秒

 buff = ''

 resp = '' 

 channel.send('ssh '+username+'@'+hostname+'\n') ? ?#執行ssh登錄業務主機 

 while not buff.endswith(passinfo): ? ?#ssh登錄的提示信息判斷,輸出串尾含有"\'s password:"時

 ? ? try: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?#退出while循環

 ? ? ? ? resp = channel.recv(9999)

 ? ? except Exception,e:

 ? ? ? ? print 'Error info:%s connection time.' % (str(e))

 ? ? ? ? channel.close()

 ? ? ? ? ssh.close()

 ? ? ? ? sys.exit()

 ? ? buff += resp

 ? ? if not buff.find('yes/no')==-1: ? ?#輸出串尾含有"yes/no"時發送"yes"并回車 ? ? ? ? 

 channel.send('yes\n')

 ? ? ? ? buff='' 

 channel.send(password+'\n') ? ?#發送業務主機密碼 

 buff='' 

 while not buff.endswith('# '): ? ?#輸出串尾為“#”說明校驗通過并退出while循環

 ? ? resp = channel.recv(9999)

 ? ? if not resp.find(passinfo)==-1: ? ?#輸出串尾含有"\'s password: "時說明密碼不正確, ? ? 要求重新輸入

 ? ? ? ? print 'Error info: Authentication failed.'

 ? ? ? ? channel.close() ? ?#關閉連接對象后退出

 ? ? ? ? ssh.close()

 ? ? ? ? sys.exit()

 ? ? buff += resp

 channel.send('ifconfig\n') ? ?#認證通過后發送ifconfig命令來查看結果

 buff='' 

 try:

 ? ? while buff.find('# ')==-1:

 ? ? ? ? resp = channel.recv(9999)

 ? ? ? ? buff += resp 

 except Exception, e:

 ? ? print "error info:"+str(e)

 print buff ? ?#打印輸出串 

 channel.close()

 ssh.close()

運行結果如下:

# python /home/test/paramiko/simple3.py 

ifconfig

eth0 ? ? ?Link encap:Ethernet ?HWaddr 00:50:56:28:63:2D

 ? ? ? ? ? inet addr:192.168.1.21 ?Bcast:192.168.1.255 ?Mask:255.255.255.0

 ? ? ? ? ? inet6 addr: fe80::250:56ff:fe28:632d/64 Scope:Link

 ? ? ? ? ? UP BROADCAST RUNNING MULTICAST ?MTU:1500 ?Metric:1

 ? ? ? ? ? RX packets:3523007 errors:0 dropped:0 overruns:0 frame:0

 ? ? ? ? ? TX packets:6777657 errors:0 dropped:0 overruns:0 carrier:0

 ? ? ? ? ? collisions:0 txqueuelen:1000

? ? ? ? ? ?RX bytes:606078157 (578.0 MiB) ?TX bytes:1428493484 (1.3 GiB) lo

    ? ? ? ?Link encap:Local Loopback

 ? ? ? ? ? inet addr:127.0.0.1 ?Mask:255.0.0.0 … …

顯示“inet addr:192.168.1.21”說明命令已經成功執行。

3.3實現堡壘模式下的遠程文件上傳

實現堡壘機模式下的文件上傳,原理是通過paramiko的SFTPClient將文件從辦公設備上傳至堡壘機指定的臨時目錄,如/tmp,再通過SSHClient的invoke_shell方法開啟ssh會話,執行scp命令,將/tmp下的指定文件復制到目標業務服務器上,如圖6-3所示。

本示例具體使用sftp.put()方法上傳文件至堡壘機臨時目錄,再通過send()方法執行scp命令,將堡壘機臨時目錄下的文件復制到目標主機,詳細的實現源碼如下:【/home/test/paramiko/simple4.py】

#!/usr/bin/env python

import paramiko

import os,sys,time

blip=”192.168.1.23″ ? ?#定義堡壘機信息

bluser=”root”

blpasswd=” IS8t5jgrie”

hostname=”192.168.1.21″ ? ?#定義業務服務器信息

username=”root”

password=” KJsdiug45″

tmpdir=”/tmp”

remotedir=”/data”

localpath=”/home/nginx_access.tar.gz” ? ?#本地源文件路徑

tmppath=tmpdir+”/nginx_access.tar.gz” ? ?#堡壘機臨時路徑

remotepath=remotedir+”/nginx_access_hd.tar.gz” ? ?#業務主機目標路徑

port=22

passinfo=’\’s password: ‘

paramiko.util.log_to_file(’syslogin.log’)

t = paramiko.Transport((blip, port))

t.connect(username=bluser, password=blpasswd)

sftp =paramiko.SFTPClient.from_transport(t)

sftp.put(localpath, tmppath) ? ?#上傳本地源文件到堡壘機臨時路徑

sftp.close()

ssh=paramiko.SSHClient()

ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

ssh.connect(hostname=blip,username=bluser,password=blpasswd)

channel=ssh.invoke_shell()

channel。settimeout(10)

buff = ” resp = ”

#scp中轉目錄文件到目標主機

channel.send(’scp ‘+tmppath+’ ‘+username+’@’+hostname+’:’+remotepath+’\n’)

while not buff.endswith(passinfo):

try:

resp = channel.recv(9999)

except Exception,e:

print ‘Error info:%s connection time.’ % (str(e))

channel.close()

ssh.close()

sys.exit()

buff += resp

if not buff.find(’yes/no’)==-1:

channel.send(’yes\n’)

buff=”

channel.send(password+’\n’)

buff=”

while not buff.endswith(’# ‘):

resp = channel.recv(9999)

if not resp.find(passinfo)==-1:

print ‘Error info: Authentication failed.’

channel.close()

ssh.close()

sys.exit()

buff += resp

print buff

channel.close()

ssh.close()

運行結果如下,如目標主機/data/nginx_access_hd.tar.gz存在,則說明文件已成功上傳。

# python /home/test/paramiko/simple4.py

nginx_access.tar.gz ? ? ? ? ? ? ? ? ? ? ? ? ? 100% 1590KB ? 1.6MB/s ? 00:00

當然,整合以上兩個示例,再引入主機清單及功能配置文件,可以實現更加靈活、強大的功能,大家可以自己動手,在實踐中學習,打造適合自身業務環境的自動化運營平臺。

常用類說明與應用案例參考http://docs.paramiko.org/en/1.13/官網文檔。

五、系統批量運維管理器Fabric詳解

Fabric是基于Python(2.5及以上版本)實現的SSH命令行工具,簡化了SSH的應用程序部署及系統管理任務,它提供了系統基礎的操作組件,可以實現本地或遠程shell命令,包括命令執行、文件上傳、下載及完整執行日志輸出等功能。Fabric在paramiko的基礎上做了更高一層的封裝,操作起來會更加簡單。Fabric官網地址為:http://www.fabfile.org。

1.Fabric的安裝

Fabric支持pip、easy_install或源碼安裝方式,很方便解決包依賴的問題,具體安裝命令如下(根據用戶環境,自行選擇pip或easy_install):

pip install fabric

easy_install fabric

Fabric依賴第三方的setuptools、Crypto、paramiko包的支持,源碼安裝步驟如下:

# yum -y install python-setuptools
# wget https://pypi.python.org/packages/source/F/Fabric/Fabric-1.8.2.tar.gz --no-check-certificate 
# tar -zxvf Fabric-1.8.2.tar.gz 
# cd Fabric-1.8.2 
# python setup.py install

校驗安裝結果,如果導入模塊沒有提示異常,則說明安裝成功:

# python

Python 2.6.6 (r266:84292, Jul 10 2013, 22:48:45)

[GCC 4.4.7 20120313 (Red Hat 4.4.7-3)] on linux2

Type “help”, “copyright”, “credits” or “license” for more information.

>>> import fabric

>>>

簡單的入門示例:

【/home/test/fabric/fabfile.py】

#!/usr/bin/env python

from fabric.api import run

def host_type(): ? ?#定義一個任務函數,通過run方法實現遠程執行‘uname -s’命令

run(’uname -s’)

其中,fab命令引用默認文件名為fabfile.py,如果使用非默認文件名稱,則需通過“-f”來指定,如:fab-H SN2013-08-021,SN2013-08-022-f host_type.py host_type。如果管理機與目標主機未配置密鑰認證信任,將會提示輸入目標主機對應賬號登錄密碼。

2.fab常用參數

fab作為Fabric程序的命令行入口,提供了豐富的參數調用,命令格式如下:

fab [options] <command>[:arg1,arg2=val2,host=foo,hosts=’h1;h2’,…] …

下面列舉了常用的幾個參數,更多參數可使用fab-help查看。

·-l,顯示定義好的任務函數名;

·-f,指定fab入口文件,默認入口文件名為fabfile.py;

·-g,指定網關(中轉)設備,比如堡壘機環境,填寫堡壘機IP即可;

·-H,指定目標主機,多臺主機用“,”號分隔;

·-P,以異步并行方式運行多主機任務,默認為串行運行;

·-R,指定role(角色),以角色名區分不同業務組設備;

·-t,設置設備連接超時時間(秒);

·-T,設置遠程主機命令執行超時時間(秒);

·-w,當命令執行失敗,發出告警,而非默認中止任務。

有時候我們甚至不需要寫一行Python代碼也可以完成遠程操作,直接使用命令行的形式,例如:

# fab -p Ksdh3458d(密碼) -H 192.168.1.21,192.168.1.22 — ‘uname -s’

3 fabfile的編寫

fab命令是結合我們編寫的fabfile.py(其他文件名須添加-f filename引用)來搭配使用的,部分命令行參數可以通過相應的方法來代替,使之更加靈活,例如“-H 192.168.1.21,192.168.1.22”,我們可以通過定義env.hosts來實現,如“env.hosts=[‘192.168.1.21’,’192.168.1.22’]”。fabfile的主體由多個自定義的任務函數組成,不同任務函數實現不同的操作邏輯,下面詳細介紹。

3.1 全局屬性設定

evn對象的作用是定義fabfile的全局設定,支持多個屬性,包括目標主機、用戶、密碼、角色等,各屬性說明如下:

·env.host,定義目標主機,可以用IP或主機名表示,以Python的列表形式定義,如env.hosts=[‘192.168.1.21’,’192.168.1.22’]。

·env.exclude_hosts,排除指定主機,如env.exclude_hosts=[‘192.168.1.22’]。

·env.user,定義用戶名,如env.user=”root”。

·env.port,定義目標主機端口,默認為22,如env.port=”22″。

·env.password,定義密碼,如env.password=’KSJ3548t7d’。

·env.passwords,與password功能一樣,區別在于不同主機不同密碼的應用場景,需要注意的是,配置passwords時需配置用戶、主機、端口等信息,如:

env.passwords = {

 ? ? 'root@192.168.1.21:22': 'SJk348ygd',

 ? ? 'root@192.168.1.22:22': 'KSh458j4f',

 ? ? 'root@192.168.1.23:22': 'KSdu43598'

 }

·env.gateway,定義網關(中轉、堡壘機)IP,如env.gateway=’192.168.1.23’。

·env.deploy_release_dir,自定義全局變量,格式:env.+“變量名稱”,如env.deploy_release_dir、env.age、env.sex等。

·env.roledefs,定義角色分組,比如web組與db組主機區分開來,定義如下:

env.roledefs = {

‘webservers’: [‘192.168.1.21’, ‘192.168.1.22’, ‘192.168.1.23’, ‘192.168.1.24’], ? ? ? ? ? ? ‘dbservers’: [‘192.168.1.25’, ‘192.168.1.26’]

}

引用時使用Python修飾符的形式進行,角色修飾符下面的任務函數為其作用域,下面來看一個示例:

@roles(’webservers’)

def webtask():

run(’/etc/init.d/nginx start’)

@roles(’dbservers’)

def dbtask():

run(’/etc/init.d/mysql start’)

@roles (’webservers’, ‘dbservers’)

def pubclitask():

run(’uptime’)

def deploy():

execute(webtask)

execute(dbtask)

execute(pubclitask)

在命令行執行#fab deploy就可以實現不同角色執行不同的任務函數了。

3.2 常用API

Fabric提供了一組簡單但功能強大的fabric.api命令集,簡單地調用這些API就能完成大部分應用場景需求。Fabric支持常用的方法及說明如下:

·local,執行本地命令,如:local(’uname-s’);

·lcd,切換本地目錄,如:lcd(’/home’);

·cd,切換遠程目錄,如:cd(’/data/logs’);

·run,執行遠程命令,如:run(’free-m’);

·sudo,sudo方式執行遠程命令,如:sudo(’/etc/init.d/httpd start’);

·put,上傳本地文件到遠程主機,如:put(’/home/user.info’,’/data/user.info’);

·get,從遠程主機下載文件到本地,如:get(’/data/user.info’,’/home/root.info’);

·prompt,獲得用戶輸入信息,如:prompt(’please input user password:’);

·confirm,獲得提示信息確認,如:confirm(“Tests fsiled.Continue[Y/N]?”);

·reboot,重啟遠程主機,如:reboot();

·@task,函數修飾符,標識的函數為fab可調用的,非標記對fab不可見,純業務邏輯;

·@runs_once,函數修飾符,標識的函數只會執行一次,不受多臺主機影響。下面結合一些示例來幫助大家理解以上常用的API。

3.3 示例1:查看本地與遠程主機信息

本示例調用local()方法執行本地(主控端)命令,添加“@runs_once”修飾符保證該任務函數只執行一次。調用run()方法執行遠程命令。詳細源碼如下:【/home/test/fabric/simple1.py】

#!/usr/bin/env python

from fabric.api import *

env.user=’root’

env.hosts=[‘192.168.1.21’,’192.168.1.22′]

env.password=’LKs934jh3′

@runs_once ? ?#查看本地系統信息,當有多臺主機時只運行一次

def local_task(): ? ?#本地任務函數

local(”uname -a”)

def remote_task():

with cd(”/data/logs”): ? ?#“with”的作用是讓后面的表達式的語句繼承當前狀態,實現

run(”ls -l”) ? ? ? ? ?# “cd /data/logs && ls -l”的效果

通過fab命令分別調用local_task任務函數運行

調用local_task任務函數運行結果結果中顯示了“[192.168.1.21]Executing task’local_task’”,但事實上并非在主機192.168.1.21上執行任務,而是返回Fabric主機本地“uname-a”的執行結果。

3.4示例2:動態獲取遠程目錄列表

本示例使用“@task”修飾符標志入口函數go()對外部可見,配合“@runs_once”修飾符接收用戶輸入,最后調用worktask()任務函數實現遠程命令執行,詳細源碼如下:【/home/test/fabric/simple2.py】

#!/usr/bin/env python

from fabric.api import *

env.user=’root’

env.hosts=[‘192.168.1.21’,’192.168.1.22′]

env.password=’LKs934jh3′

@runs_once ? ?#主機遍歷過程中,只有第一臺觸發此函數

def input_raw():

return prompt(”please input directory name:”,default=”/home”)

def worktask(dirname):

run(”ls -l “+dirname)

@task ? ?#限定只有go函數對fab命令可見

def go():

getdirname = input_raw()

worktask(getdirname)

該示例實現了一個動態輸入遠程目錄名稱,再獲取目錄列表的功能,由于我們只要求輸入一次,再顯示所有主機上該目錄的列表信息,調用了一個子函數input_raw()同時配置@runs_once修飾符來達到此目的。

 

4.Fabric應用示例

下面介紹幾個比較典型的應用Fabric的示例,涉及文件上傳與校驗、環境部署、代碼發布的功能,讀者可以在此基礎進行功能擴展,寫出更加貼近業務場景的工具平臺。

4.1 示例1:文件打包、上傳與校驗

我們時常做一些文件包分發的工作,實施步驟一般是先壓縮打包,再批量上傳至目標服務器,最后做一致性校驗。本案例通過put()方法實現文件的上傳,通過對比本地與遠程主機文件的md5,最終實現文件一致性校驗。詳細源碼如下:

【/home/test/fabric/simple4.py】

#!/usr/bin/env python

from fabric.api import *

from fabric.context_managers import *

from fabric.contrib.console import confirm

env.user=’root’

env.hosts=[‘192.168.1.21’,’192.168.1.22′]

env.password=’LKs934jh3′

@task

@runs_once

def tar_task(): ? ?#本地打包任務函數,只限執行一次

with lcd(”/data/logs”):

local(”tar -czf access.tar.gz access.log”)

@task

def put_task(): ? ?#上傳文件任務函數

run(”mkdir -p /data/logs”)

with cd(”/data/logs”):

with settings(warn_only=True): ? ?#put(上傳)出現異常時繼續執行,非終止

result = put(”/data/logs/access.tar.gz”, “/data/logs/access.tar.gz”)

if result.failed and not confirm(”put file failed, Continue[Y/N]?”):

abort(”Aborting file put task!”) ? ?#出現異常時,確認用戶是否繼續,(Y繼續)

@task

def check_task(): ? ?#校驗文件任務函數

with settings(warn_only=True): ? ? ? ? #本地local命令需要配置capture=True才能捕獲返回值

lmd5=local(”md5sum /data/logs/access.tar.gz”,capture=True).

split(’ ‘)[0]

rmd5=run(”md5sum /data/logs/access.tar.gz”).split(’ ‘)[0]

if lmd5==rmd5: ? ?#對比本地及遠程文件md5信息

print “OK”

else:

print “ERROR”

本示例通過定義三個功能任務函數,分別實現文件的打包、上傳、校驗功能,且三個功能相互獨立,可分開運行,如:

fab -f simple4.py tar_task ? ?#文件打包

fab -f simple4.py put_task ? ?#文件上傳

fab -f simple4.py check_task ?#文件校驗

當然,我們也可以組合在一起運行,再添加一個任務函數go,代碼如下:

@task

def go():

tar_task()

put_task()

check_task()

運行fab-f simple4.py go就可以實現文件打包、上傳、校驗全程自動化。

4.2 示例2:部署LNMP業務服務環境

業務上線之前最關鍵的一項任務便是環境部署,往往一個業務涉及多種應用環境,比如Web、DB、PROXY、CACHE等,本示例通過env.roledefs定義不同主機角色,再使用“@roles(’webservers’)”修飾符綁定到對應的任務函數,實現不同角色主機的部署差異,詳細源碼如下:

【/home/test/fabric/simple5.py】

#!/usr/bin/env python

from fabric.colors import *

from fabric.api import *

env.user=’root’

env.roledefs = { ? ?#定義業務角色分組

‘webservers’: [‘192.168.1.21’, ‘192.168.1.22’],

‘dbservers’: [‘192.168.1.23’]

}

passwords = {

‘root@192.168.1.21:22’: ‘SJk348ygd’,

‘root@192.168.1.22:22’: ‘KSh458j4f’,

‘root@192.168.1.23:22’: ‘KSdu43598’

}

@roles(’webservers’) ? ?#webtask任務函數引用’webservers’角色修飾符

def webtask(): ? ?#部署nginx php php-fpm等環境

print yellow(”Install nginx php php-fpm…”)

with settings(warn_only=True):

run(”yum -y install nginx”)

run(”yum -y install php-fpm php-mysql php-mbstring php-xml php-mcrypt php-gd”)

run(”chkconfig –levels 235 php-fpm on”)

run(”chkconfig –levels 235 nginx on”)

@roles(’dbservers’) ? ?# dbtask任務函數引用’dbservers’角色修飾符

def dbtask(): ? ?#部署mysql環境

print yellow(”Install Mysql…”)

with settings(warn_only=True):

run(”yum -y install mysql mysql-server”)

run(”chkconfig –levels 235 mysqld on”)

@roles (’webservers’, ‘dbservers’) # publictask任務函數同時引用兩個角色修飾符

def publictask(): ? ?#部署公共類環境,如epel、ntp等

print yellow(”Install epel ntp…”)

with settings(warn_only=True):

run(”rpm -Uvh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel- release-6-8.noarch.rpm”)

run(”yum -y install ntp”)

def deploy():

execute(publictask)

execute(webtask)

execute(dbtask)

本示例通過角色來區別不同業務服務環境,分別部署不同的程序包。我們只需要一個Python腳本就可以完成不同業務環境的定制。

4.3 示例3:生產環境代碼包發布管理

程序生產環境的發布是業務上線最后一個環節,要求具備源碼打包、發布、切換、回滾、版本管理等功能,本示例實現了這一整套流程功能,其中版本切換與回滾使用了Linux下的軟鏈接實現。詳細源碼如下:

【/home/test/fabric/simple6.py】

#!/usr/bin/env python

from fabric.api import *

from fabric.colors import *

from fabric.context_managers import *

from fabric.contrib.consoleimport confirm

import time

env.user=’root’

env.hosts=[‘192.168.1.21’,’192.168.1.22′]

env.password=’LKs934jh3’

env.project_dev_source = ‘/data/dev/Lwebadmin/’ ? ?#開發機項目主目錄

env.project_tar_source = ‘/data/dev/releases/’ ? ?#開發機項目壓縮包存儲目錄

env.project_pack_name = ‘release’ ? ?#項目壓縮包名前綴,文件名為release.tar.gz

env.deploy_project_root = ‘/data/www/Lwebadmin/’ ? ?#項目生產環境主目錄

env.deploy_release_dir = ‘releases’ ? ?#項目發布目錄,位于主目錄下面

env.deploy_current_dir = ‘current’ ? ?#對外服務的當前版本軟鏈接

env.deploy_version=time.strftime(”%Y%m%d”)+”v2″ ? ?#版本號

@runs_once

def input_versionid(): ? ?#獲得用戶輸入的版本號,以便做版本回滾操作

return prompt(”please input project rollback version ID:”,default=””)

@task

@runs_once

def tar_source(): ? ?#打包本地項目主目錄,并將壓縮包存儲到本地壓縮包目錄

print yellow(”Creating source package…”)

with lcd(env.project_dev_source):

local(”tar -czf %s.tar.gz .” % (env.project_tar_source + env.project_pack_name))

print green(”Creating source package success!”)

@task

def put_package(): ? ?#上傳任務函數

print yellow(”Start put package…”)

with settings(warn_only=True):

with cd(env.deploy_project_root+env.deploy_release_dir):

run(”mkdir %s” % (env.deploy_version)) ? ?#創建版本目錄

env.deploy_full_path=env.deploy_project_root + env.deploy_release_dir +

“/”+env.deploy_version

with settings(warn_only=True): ? ?#上傳項目壓縮包至此目錄

result = put(env.project_tar_source + env.project_pack_name +”.tar.gz”, ?env.deploy_full_path)

if result.failed and no(”put file failed, Continue[Y/N]?”):

abort(”Aborting file put task!”)

with cd(env.deploy_full_path): ? ?#成功解壓后刪除壓縮包

run(”tar -zxvf %s.tar.gz” % (env.project_pack_name))

run(”rm -rf %s.tar.gz” % (env.project_pack_name))

print green(”Put & untar package success!”)

@task

def make_symlink(): ? ?#為當前版本目錄做軟鏈接

print yellow(”update current symlink”)

env.deploy_full_path=env.deploy_project_root + env.deploy_release_dir + ?“/”+env.deploy_version

with settings(warn_only=True): ? ?#刪除軟鏈接,重新創建并指定軟鏈源目錄,新版本生效

run(”rm -rf %s” % (env.deploy_project_root + env.deploy_current_dir))

run(”ln -s %s %s” % (env.deploy_full_path, env.deploy_project_root + ?env.deploy_current_dir))

print green(”make symlink success!”)

@task

def rollback(): ? ?#版本回滾任務函數

print yellow(”rollback project version”)

versionid= input_versionid() ? ?#獲得用戶輸入的回滾版本號

if versionid==”:

abort(”Project version ID error,abort!”)

env.deploy_full_path=env.deploy_project_root + env.deploy_release_dir +

“/”+versionid

run(”rm -f %s” % env.deploy_project_root + env.deploy_current_dir)

run(”ln -s %s %s” % (env.deploy_full_path, env.deploy_project_root + env.

deploy_current_dir)) ? ?#刪除軟鏈接,重新創建并指定軟鏈源目錄,新版本生效

print green(”rollback success!”)

@task

def go(): ? ?#自動化程序版本發布入口函數

tar_source()

put_package()

make_symlink()

本示例實現了一個通用性很強的代碼發布管理功能,支持快速部署與回滾,無論發布還是回滾,都可以通過切換current的軟鏈來實現,非常靈活。該功能的流程圖如圖7-5所示。

Python模塊及詳解(2)

圖7-5 生產環境代碼包發布管理流程圖

在生產環境中Nginx的配置如下:

server_name domain.com

index index.html index.htm index.php;

root /data/www/Lwebadmin/current;

將站點根目錄指向“/data/www/Lwebadmin/current”,由于使用Linux軟鏈接做切換,管理員的版本發布、回滾操作用戶無感知,同時也規范了我們業務上線的流程。

參考提示 fab常用參數說明參考http://docs.fabfile.org/en/1.8/官網文檔。

原創文章,作者:nene,如若轉載,請注明出處:http://www.www58058.com/91163

(1)
nenenene
上一篇 2018-01-17
下一篇 2018-01-17

相關推薦

  • Python內建函數

    內建函數 標識id() 返回對象的唯一標識,CPython返回內存地址 哈希hash() 返回一個對象的hash值 類型type() 返回對象的類型 類型轉換 int()、float()、bin()、hex()、oct()、bool()、list()、tuple()、dict()、set()、complex()、bytes()、bytearray() 輸入i…

    2018-04-08
  • Python內置數據結構——字符串

    知識結構圖 學習筆記 字符串 字符組成的有序序列,字符的集合 使用單引號、雙引號、三引號引起來的字符序列 不可變對象 Unicode類型 定義 單引號、雙引號、三引號 r、R:引號內的字符原樣輸出 元素訪問 索引訪問 可迭代 join連接 “string“.join(iteratable) 使用string作為分隔符將可迭代對象連接起…

    2018-03-31
  • Python函數

    函數 數學函數 Python函數 若干語句塊、函數名稱、參數列表構成,組織代碼的最小單元 完成一定的功能 作用 結構化編程對代碼的最基本的封裝,一般按照功能組織一段代碼 復用,減少冗余代碼 簡潔美觀,可讀易懂 函數分類 內建函數,max()、reversed() 庫函數,math.ceil() 函數定義、調用 def語句定義函數 def 函數名(參數列表):…

    2018-04-16
  • Python第十二周學習總結

    Git的使用

    2018-05-27
  • Python爬蟲實戰七之計算大學本學期績點

    大家好,本次為大家帶來的項目是計算大學本學期績點。首先說明的是,博主來自山東大學,有屬于個人的學生成績管理系統,需要學號密碼才可以登錄,不過可能廣大讀者沒有這個學號密碼,不能實際進行操作,所以最主要的還是獲取它的原理。最主要的是了解cookie的相關操作。 本篇目標 1.模擬登錄學生成績管理系統 2.抓取本學期成績界面 3.計算打印本學期成績 1.URL的獲…

    2017-09-09
  • python學習總結

    內建函數、函數、插入排序、樹

    2018-04-15
欧美性久久久久