來源:http://ruiaylin.github.io/2014/11/24/fabric/ python
看一下官方介紹,來一個清晰的認識mysql
Fabric is a Python (2.5-2.7) library and command-line tool for streamlining the use of SSH for application deployment or systems administration tasks. More specifically, Fabric is: A tool that lets you execute arbitrary Python functions via the command line;A library of subroutines (built on top of a lower-level library) to make executing shell commands over SSH easy and Pythonic. Naturally, most users combine these two things, using Fabric to write and execute Python functions, or tasks, to automate interactions with remote servers.
Python 開發者 系統管理員 [ SA , ASA, DBA ...] 應用開發者
fabric是對ssh的一個集成工具,對咱們而言只須要使用相應的接口,來高效的完成工做,咱們經常使用到的功能基本是 : 本地或者遠端執行命令, 分發文件,收集文件,還有一些權限相關的操做。 這些fabric都給咱們提供了對應的接口。
以下所示:linux
run (fabric.operations.run) sudo (fabric.operations.sudo)local (fabric.operations.local)get (fabric.operations.get)put (fabric.operations.put) prompt (fabric.operations.prompt) reboot (fabric.operations.reboot)
接口部分提供了命令運行的方式,不過都沒法保持上下文關係,爲了解決這個問題,fabric的context manager 就派上了用場:git
cd (fabric.context_managers.cd)lcd (fabric.context_managers.lcd)path (fabric.context_managers.path)settings (fabric.context_managers.settings)prefix (fabric.context_managers.prefix)
easy_install fabric
因爲fabric是基於python的,因此寫fabric腳本就是寫python腳本,你能夠像寫python腳本同樣,能夠依賴其餘模塊或者其餘工具來完成工做。Fabric 腳本,經過fab工具運行fabric python腳本。fab工具默認執行fabfile.py ,也能夠經過-f 參數指定 腳本文件名。fabric優點多多,簡單,方便,日誌輸出清晰,命令
中可使用AWK 命令 下面咱們看一個 hello world 程序。github
from fabric.api import *def helloworld(who='world'): print "Hello {0}!".format(who) def helloworld1(you='world',me='ruiaylin'): print "Hello {0}! i am {1} ! ".format(you,me)
執行命令(其中參數的傳遞直接跟在任務後跟變量名和參數):sql
fabric fab -f helloword.py helloworldHello world! Done. fabric fab -f helloword.py helloworld1:you='ruichao',me='ruiaylin'Hello ruichao! i am ruiaylin ! Done.
咱們已經看了一個簡單例子下面咱們來看一下fabric的主要接口。shell
Fabric 中使用最多的就是 run 方法了。run是用來在一臺或者多臺遠程主機上面執行shell 命令。數據庫
方法的返回值是能夠經過變量來進行捕獲編程
能夠經過變量的.failed 和 .succeeded 來檢查命令是否執行成功ubuntu
還有一個很讚的就是 run 方法中執行命令的時候,能夠支持awk 很給力
使用方法:
# creat a directoryrun(" mkdir /tmp/testdir/ -p ")# check proce***esult = run("ps -ef |grep mysqld|grep -v safe |grep -v grep | wc -l "#Check if commandresult.failed
使用 sudo 命令執行對頂的命令。使用方法與run 相似。
local 命令是執行本機的命令或者腳本.使用方法和run 還有sudo相似,可是有一個區別
就是: 捕獲結果的時候,是經過指定 capture=False 或者capture=True來肯定。來看
實例:
# example like this : def helloworld(who='world'): print "Hello {0}!".format(who) yy = local(" pwd ", capture=False) print 'start : yy = ' , yy , ' : :: ',yy.succeeded zz = local(" pwd ", capture=True) print 'start : zz = ' , zz , ' : :: ',zz.succeeded#result : fabric fab -f helloword.py helloworld -H 10.211.55.3 -u root [10.211.55.3] Executing task 'helloworld'Hello world! [localhost] local: pwd /Users/ruiaylin/Documents/workpython/fabric start : yy = : :: True[localhost] local: pwd start : zz = /Users/ruiaylin/Documents/workpython/fabric : :: True
get 方法是從遠程主機 copy file 到本地,功能跟scp同樣。能夠從遠程主機下載
備份,或者日誌文件等等。
經過參數 remote_path 指定遠程文件的路徑
經過參數 local_path 指定遠程文件的路徑
使用方法以下:
# Download some logsget(remote_path="/tmp/xxx.log", local_path="/tmp/xxx.log") # Download a database back-upget("/backup/db.gz", "./db.gz")
某些須要上傳和分發文件的時候,put命令就派上了用場,使用方式相似 get。也一樣能夠
經過.failed .succeeded進行命令是否執行成功的判斷。
local_path - 本地路徑
remote_path - 遠程路徑
mode - 文件屬性
以下例子:
upload = put("requirements.txt", "requirements.txt", mode=664)
目前官方來看 1.X 版本的fabric 並行執行的時候不是thread safe的。若是須要並行執行task。須要在方法上面使用註解 @parallel 爲了防止管控機器上面過多的併發任務能夠經過 @parallel(pool_size=5)來設置. 並行的執行輸出都會輸出到一個終端上面,比較混亂。最好是寫到日誌,以task爲維度。跟下面的代碼相似。
還有幾個接口你們能夠查閱fabric 文檔 :
安裝步驟以下
獲取主機ip
check主機可達性
檢查linux平臺詳情
是否有運行的mysql實例
若是有獲取對應的端口
檢查是否和要安裝的端口衝突
處理mysql用戶以及屬組
處理安裝相關目錄和權限
copy 安裝包到目標機
解壓處理,將主要軟件工具軟鏈接到path路徑中
生成對應標準配置文件並分發到目標機對應目錄
初始化數據庫
啓動數據庫
基本步驟安裝完畢
基本腳本以下:
script 1 sub task :
from fabric.api import *from fabric.colors import green,red,blue,cyan,yellowimport os , sysimport socketimport datetimeimport loggingimport logging.handlers#get logger for logging def initLoggerWithRotate(): logname=''.join(env.host_string.split('.'))+'.log' logFileName="logs/%s"%logname logger = logging.getLogger("fabric") formater = logging.Formatter("%(asctime)s %(name)s %(levelname)s %(message)s","%Y-%m-%d %H:%M:%S") file_handler = logging.handlers.RotatingFileHandler(logFileName, maxBytes=104857600, backupCount=5) file_handler.setFormatter(formater) stream_handler = logging.StreamHandler(sys.stderr) logger.addHandler(file_handler) logger.addHandler(stream_handler) logger.setLevel(logging.INFO) return logger#mkdirdef runmkdir(dir): run(''' mkdir -p %s '''%dir)#stp 1 check hostdef checkhost(logger): host = env.host_string s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) flag_c = 0 try: s.connect((host, 22)) flag_c = 1 logger.info( green( ' --> host %s can be reachable ' %host ) ) except socket.error as e: logger.warning( yellow( ' --> Error on connect %s' %e ) ) s.close() return flag_c#stp 2 check alive instance on target host def checkmysqlinstance(logger): try: wc = run(''' ps -ef |grep mysqld|grep -v safe | grep -v grep | wc -l ''') if int(wc) > 0 : logger.warning(yellow( ' --> %sinstance exist on the target host '%wc )) portraw = run(''' ps -ef |grep mysqld|grep -v safe |grep -v grep |awk ' {for(i=1;i<=NF;i++){if($i ~/--port/ ){print $i}}}' |awk -F '=' '{print $2}' ''') ports = [x.strip() for x in portraw.split() ] logger.warning( yellow( ' --> existing instance port : [ %s ] '%( ','.join( ports )))) if port in ports: logger.error( red( ' --> Install port %s exist , install failed '%port)) logger.error( red( ' <<<exit>>>>> task on host %s stop & exit() '%thost)) sys.exit() except Exception, e: logger.warning(yellow( ' --> checkmysqlinstance() exception : %s '%e )) raise e #stp 3 initdir for installationdef createUser(logger,user='mysql',group='dba'): try: if int(run('grep "^mysql" /etc/passwd|wc -l')) == 0 : run('groupadd dba ') run('useradd -c "mysql software owner" -g dba -G dba mysql') run('mkdir -p /home/mysql ; chown -R mysql.dba /home/mysql ') logger.info(cyan( ' --> create user [ mysql ] in group [ dba ] success ' )) else : logger.info(yellow ( ' --> user [ mysql ] in group [ dba ] exist & skip ' )) except Exception, e: logger.warning(yellow( ' --> createUser() exception : %s '%e )) raise e#stp 4 initail directory for mysql def initdir(logger,port=3306): try : logger.info( green( ' --> begin to create dirs for installation ')) datadir='/data/' logdir ='/log/' mandir = 'mysql%s'%port subddir ='/data/mysql%s/{data,log,run,tmp}'%(port) subldir ='/log/mysql%s/{binlog,iblog}'%(port) #data ck1 = run(' df -vh | grep /data | wc -l ') if ck1 == 0 : logger.error(green(' --> no /data/ partition exist' ) ) #sys.exit() if int( run(' ls / | grep /data | wc -l ')) == 0 or int( run(' ls /data/ | grep -w %s | wc -l '%mandir) ) == 0 : runmkdir(subddir) logger.info(green(' --> /data/*** create Ok ' ) ) else : logger.info(green(' --> /data/mysql%s exsit '%port )) logger.info(green(' --> pls,handle it and restart this task ')) sys.exit() #log ck2 = run(' df -vh | grep /log/ | wc -l ') if int( run(' df -vh | grep /log/ | wc -l ') ) == 0 and int( run(' ls / | grep -w log | wc -l ') ) == 0: logger.warning( yellow(' --> no /log/ partition exist') ) logger.warning( yellow(' --> create link for /log/ --> /data/log/') ) runmkdir('/data/log') run('ln -s /data/log /log ') runmkdir(subldir) logger.info(green(' --> /log/*** create Ok ' ) ) else : if int(run(' ls /log/ | grep -w %s | wc -l '%mandir)) == 0: runmkdir(subldir) logger.info(green(' --> /log/*** create Ok ' ) ) else : logger.info(yellow(' --> /log/mysql%s exsit '%port )) logger.error(red(' --> pls,handle it and restart this task ' )) sys.exit() #change runmkdir('/data/tmp') logger.info(green(' --> change dirs owner&privs start')) run('chown -R mysql:dba /data/*') run('chown -R mysql:dba /log') logger.info(green(' --> change dirs owner&privs done')) except Exception, e: logger.warning(yellow( ' --> initdir() exception : %s '%e )) raise e #stp 5 put mysql install packagedef copymysql(logger,version='5.7'): try: dits = { 'ubuntu':'mysql-server_5.6.21-1ubuntu12.04_amd64.deb-bundle.tar', 'centos':'mysql-server.tar.gz' } issue = run ('cat /etc/issue') ss = issue.lower() logger.info( green( ' %s '%ss)) if int ( run( ' ls /usr/local/ | grep mysql | wc -l ') ) > 0 : logger.info( yellow( ' --> mysql software installed , skip ' )) return plats = dits.keys() for x in plats: if ss.find(x) != -1: logger.info( green( ' --> the target host platform is %s'% x ) ) put( local_path="configs/%s"%dits[x],remote_path="/tmp/%s"%dits[x] ) logger.info( green( ' --> tar the ball to prop dir ')) run( 'tar zxvf /tmp/%s -C /usr/local/ '%dits[x] ) run( 'ln -s /usr/local/%s /usr/local/mysql '%dits[x][:-7] ) break except Exception, e: logger.warning(yellow( ' --> copymysql() exception : %s '%e )) raise e #gen my.cnf file def getnewServerId(logger,port): host = env.host_string print 'getnewServerId : ',host pics = host.split('.') a=int(pics[0]) b=int(pics[1]) c=int(pics[2]) d=int(pics[3]) suf = int(port) % 256 server_id = b * 256 * 256 * 256 + c * 256 * 256 + d * 256 + suf logger.info( cyan( ' --> gen server_id done , %s %s is %s '%( host , port , server_id) ) ) return server_iddef genmycnf(logger,port=3306,itype='h'): host = env.host_string bps={ "a":"48|32|3100|3000", "b":"62|40|4600|4500", 'c':'94|64|7600|7500', 'd':'94|32|3100|3000', 'e':'125|75|10100|10000', 'f':'188|120|15100|15000', 'g':'188|60|7600|7500', 'h':'1|256M|800|750' } try: myfile=''.join(host.split('.'))+'.cnf' cpmycnf="""cp configs/my.cnf tmp/%s """%myfile local( 'rm -f tmp/%s'%myfile ) local("cp configs/my.cnf tmp/%s "%myfile ) sid=getnewServerId(logger,port) keys=bps.keys() bpxs=bps[itype] mem,bpsize,maxc,maxuc=bpxs.split('|') if bpsize[-1] != "M": bpsize = bpsize +'g' chrgcmd=""" sed -i -e "s/3306/%s/g" -e "s/server_id=10000/server_id=%s/g" -e "s/=32g/=%s/g" -e "s/max_connections=3100/max_connections=%s/g" -e "s/max_user_connections=3000/max_user_connections=%s/g" tmp/%s """ local( chrgcmd%(port,sid,bpsize,maxc,maxuc,myfile) ) logger.info( green( ' --> gen my.cnf success ') ) logger.info( green( ' --> copy my.cnf to dist host ') ) put( local_path="tmp/%s"%myfile, remote_path="/data/mysql%s/my.cnf"%(port) ) except Exception, e: logger.warning(yellow( ' --> genmycnf() exception : %s '%traceback.format_exc() ) ) raise e
script 2 whole task :
import inst_utils from inst_utils import * def install_mysql(port): logger = initLoggerWithRotate() thost = env.host_string try: logger.info(green( 'stp 1 get the host %s '%thost )) #check host reachable rs1 = checkhost(logger ) if int(rs1)== 0 : logger.info(red( 'stp 2 check the host is reachable failed ' )) logger.info(green( 'stp 2 check the host is reachable OK ' )) plat_type = run(''' uname -o ''') if plat_type != 'GNU/Linux' : logger.warning(yellow('stp 3 target platform is not GNU/Linux & exit() ')) sys.exit() logger.info(green('stp 3 target platform is GNU/Linux')) #check target host exsist mysql instance logger.info(green( 'stp 4 checkmysqlinstance ' )) checkmysqlinstance(logger) #create MySQL user logger.info( green( 'stp 5 createUser ' )) createUser(logger) put(local_path="configs/bash_profile", remote_path="/home/mysql/.bash_profile") #checking dir logger.info( green( 'stp 6 initdir ' )) initdir(logger,port) #copy file logger.info( green( 'stp 7 copymysql ' )) copymysql(logger) logger.info( green( 'stp 8 genmycnf ') ) genmycnf(logger,port,'h') except Exception, e: print 'main : exception : ' , e
如上腳本完成了,基本的安裝,並無啓動mysql實例,和一些db初始化工做, 有興趣的同窗能夠本身來完成,總之,fabric必定是一個運維利器 。。。