どのようにfabric自動化日常管理任務と配置を使うか?

16094 ワード

ソース:http://ruiaylin.github.io/2014/11/24/fabric/
fabricの公式紹介:
公式の紹介を見て、はっきりした認識をしてください。
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.
fabricはどんな人にサービスできますか?
Python    
      [ SA , ASA, DBA ...]
     
fabric常用インターフェース
fabricはsshに対する集積ツールであり、私たちにとっては相応のインターフェースを使って効率的に仕事を完成するだけでなく、私たちがよく使う機能は基本的には、ローカルまたはリモートでコマンドを実行し、ファイルを配布し、ファイルを収集し、またいくつかの権限に関する操作があります。これらのfabricは対応するインターフェースを提供してくれます。以下の通りです
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はまた、コンテキストマネージャを提供します。
インターフェース部分は命令運行の方式を提供していますが、文脈関係を保つことができません。この問題を解決するために、fabricのcontext managerが役に立ちました。
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)
fabric取り付け
easy_install fabric
fabricプログラミングモデルの紹介
fabricはpythonに基づいていますので、fabricシナリオを書くとpythonスクリプトです。pythonスクリプトを書くように、他のモジュールや他のツールに頼って作業ができます。Fabricスクリプトは、fabツールを介してfabric pythonスクリプトを実行します。fabツールはデフォルトでfabfile.pyを実行します。スクリプトファイル名を-fパラメータで指定することもできます。fabric優勢は多くて、簡単で、便利で、ログ出力がはっきりしています。命令の中でAWK命令を使って、私達はハローワールドのプログラムを見ます。
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)
コマンドを実行します。パラメータの転送はタスクの後にある変数名とパラメータに直接付けられます。
  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主要インターフェース方法
簡単な例を見ました。次にfabricの主要なインターフェースを見てみます。
run(fabric.operations.run)
ファブリックで一番多く使われているのがrun法です。runは、1台以上のリモートホスト上でshellコマンドを実行するために使用されます。
  • 方法の戻り値は、変数によって捕獲可能な
  • である。
  • は、コマンドが実行されたかどうかを変数のfailedおよび.succededによって確認することができます。
  • もう一つの素晴らしいのは、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(fabric.operations.sudo)
    sudoコマンドを使用してトップに対するコマンドを実行します。使用法はrunに類似している。
    local(fabric.operations.local)
    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(fabric.operations.get)
    get方法はリモートホストのcopy fileからローカルまでで、機能はscpと同じです。リモートホストからバックアップやログファイルなどをダウンロードできます。
  • パラメータremote_パス
  • を指定します。
  • パラメータlocal_パス
  • を指定します。
    使用方法は以下の通りです。
    # Download some logsget(remote_path="/tmp/xxx.log", local_path="/tmp/xxx.log")  
    # Download a database back-upget("/backup/db.gz", "./db.gz")
    put(fabric.operations.put)
    アップロードや配布が必要な場合は、putコマンドが役に立ちます。使い方はgetに似ています。また.failed.succededによって命令が実行されるかどうかの判断もできます。
  • local_パス
  • remote_パス
  • mode-ファイル属性
  • 以下の例:
    upload = put("requirements.txt", "requirements.txt", mode=664)
    並行して実行する
    現在の公式は1.Xバージョンのfabricが並行して実行する時thread safeのではありません。並列にtaskを実行する必要がある場合。方法の上に注解@parallelを使用する必要があります。制御マシンの上にあまりにも多くの同時タスクがあるのを防ぐために@parallel(pool_usize=5)で設定できます。並列の実行出力はいずれも一つの端末に出力されます。混乱しています。日記を書いて、taskを次元にしたほうがいいです。下のコードと似ています。
    もういくつかのインターフェースがあります。みんなはfabric文書を調べられます。
    MySQLインストール例
    インストール手順は以下の通りです
  • は、ホスト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( ' <<>>>>  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は、オペレータです。
    転載先:https://blog.51cto.com/5007260/1696741