Table of Contents

Middleware

Fabric



Fabric


Summary

Fabric is a Python library and command-line tool for streamlining the use of SSH for application deployment or systems administration tasks.


Installing

http://docs.ansible.com/ansible/latest/intro_installation.html#latest-release-via-yum

Dependencies

CentOS Package

# yum install epel-release
# yum install fabric

Debian/Ubuntus Package

# apt-get install fabric

Python module

# pip install fabric


Check version

# fab -V
or
# fab --version
Fabric 1.6.2
Paramiko 1.16.1


Commands

help

# fab -h
Usage: fab [options] <command>[:arg1,arg2=val2,host=foo,hosts='h1;h2',...] ...

Options:
  -h, --help            show this help message and exit

  -l, --list            print list of possible commands and exit

  -H HOSTS, --hosts=HOSTS
                        comma-separated list of hosts to operate on

  -f PATH, --fabfile=PATH
                        python module file to import, e.g. '../other.py'

  -i PATH               path to SSH private key file. May be repeated.

  -u USER, --user=USER  username to use when connecting to remote hosts

  --skip-bad-hosts      skip over hosts that can't be reached

  --hide=LEVELS         comma-separated list of output levels to hide
                        Ex) --hide=running


Execution method

# fab -l    #print list of possible commands and exit

# fab --list


# fab -H HOST -- COMMAND

# fab -H server1 -- hostname
# fab -H server1, server2, server3 -- hostname



Default configuration file is fabfile.py.

# fab -H 192.168.1.1 mkdir
# fab -H 192.168.1.1,192.168.1.2 mkdir
# fab -u USER -i KEY -H HOST install_git


# fab -H HOST -f myfabfile.py test


# echo xx.xx.xx.xx | fab -- hostname
# echo xx.xx.xx.xx | fab -- sudo cat /etc/shadow
# echo xx.xx.xx.xx | fab -f myfabfile.py test


fabfile.py's commands

env

#coding:utf-8
from fabric.api import env
from fabric.api import run

env.hosts = ['127.0.0.1']
env.user = 'user'
env.password = 'pass'

def test():
    run("hostname")
    run("whoami")

from fabric.api import env

#fab production task
@task
def production():
    env.port = 22
    env.user = 'user01'
    env.key_filename = '~/.ssh/id_rsa_production'
    env.password = 'passphrase-for-key'

@task
def staging():
    env.port = 22
    env.user = 'user01'
    env.password = 'PASSWORD'

@task
def develop():
    env.port = 22
    env.user = 'user01'
    env.key_filename = '~/.ssh/id_rsa_develop'
    env.password = 'passphrase-for-key'

from fabric.api import env

env.hosts = ["192.168.56.101", "192.168.56.102", "192.168.56.103"]

env.user = "user01"
env.password = "password"

env.command_timeout = 3600
env.keepalive = 60
env.skip_bad_hosts = True
env.timeout = 3

from fabric.api import env

env.hosts = ["user1@192.168.56.102", "user2@192.168.56.103"]
env.passwords = {"user1@192.168.56.102:22": "password1",
                 "user2@192.168.56.103:22": "password2", }


local (execute with local server)

#coding:utf-8
from fabric.api import local

def test():
  local('hostname')


run (execute with remote server)

#coding:utf-8
from fabric.api import run

def doCmd():
    run('ls -lh')


sudo

#coding:utf-8
from fabric.api import sudo

def chpasswd_root():
  sudo("echo 'user01:PASS' | chpasswd")

#coding:utf-8
from fabric.api import sudo

def doCmd():
    sudo('/etc/init.d/httpd reload')

#coding:utf-8
from fabric.api import sudo

def install_git():
  sudo("yum -y install git")


put

#coding:utf-8
from fabric.api import put

def doCmd():
    put('/tmp/test.gz', '/tmp')

from fabric.api import put

def scp():
  put('local path', 'remote path')
  put('bin/project.zip', '/tmp/project.zip')
  put('*.py', 'cgi-bin/')
  put('index.html', 'index.html', mode=0755)

from fabric.api import put

def update_sshd():
    put("conf/sshd_config." + env.host, "/etc/ssh/sshd_config", use_sudo=True, mode=0600)
    sudo("chown root.root /etc/ssh/sshd_config")
    sudo("service sshd reload")

get

#coding:utf-8
from fabric.api import get

def doCmd():
    get('/tmp/test.gz', '/tmp')


with cd

#coding:utf-8
from fabric.api import run, cd

def cd_tmp():
    with cd('/tmp'):
         sudo('mkdir test1')  #/tmp/test1
         run('ls')
    run('mkdir test2')       #/home/$USER/test2

def do_something():
    with cd('/tmp'):
         run('pwd')


Tips

Host and Group List

Sample1

#coding:utf-8
from fabric.api import env, run

env.user = 'user01'
env.password = '****'

env.roledefs = {
    'web': ['192.168.0.5', '192.168.0.6'],
    'dns': ['192.168.0.7', '192.168.0.8' ]
    'db': ['test-db1', 'test-db2' ]
    'last-dummy': ['aa.aa.aa' ]
}

env.roledefs['all'] = [h for r in env.roledefs.values() for h in r]

def test():
    run("hostname")
    run("whoami")
    #run("rpm -qa")

fab -R web hostname
fab -R all hostname
fab -R web,dns hostname

Sample2

[user1@localhost ~]$ cat host.list 
#test
192.168.0.1 test-web1 test-web
192.168.0.2 test-web2 test-web
192.168.0.3 test-db1 test-db
192.168.0.4 test-db2 test-db

#Example
192.168.1.1 example-web2 example-web
192.168.1.2 example-web2 example-web
# 


[user1@localhost ~]$ cat host.sh 
#!/bin/sh

LIST=host.list

case "$1" in
   -t | --test )
    cat "${LIST}" |grep -Ev "^#|^$" |grep "$2" 
    ;;
   -a | --all )
    cat "${LIST}" |grep -Ev "^#|^$" |awk '{print $1'}
    ;;
   * )
    cat "${LIST}" |grep -Ev "^#|^$" |grep "$1"  |awk '{print $1'}
    ;;
esac

# 


[user1@localhost ~]$ ./host.sh test-web |fab test


Separate into multiple files

Sample1 : execfile

[user1@localhost fabric]$ cat fabfile.py
from fabric.api import local

execfile("./fabfile2.py")

def test():
  local('hostname')
[user1@localhost fabric]$ 
[user1@localhost fabric]$ cat fabfile2.py 
def test2():
  local('hostname')
[user1@localhost fabric]$ 
[user1@localhost fabric]$ fab --list
Available commands:

    test
    test2
[user1@localhost fabric]$ 

Sample2 import

[user1@localhost fabfile]$ 
[user1@localhost fabfile]$ cat fabfile.py
import test1
[user1@localhost fabfile]$

[user1@localhost fabfile]$ cat test1.py
from fabric.api import local
from fabric.decorators import task

@task
def test():
  local('hostname')
[user1@localhost fabfile]$ 

[user1@localhost fabfile]$ fab -l
Available commands:

    test1.test
[user1@localhost fabfile]$ 


How to change files

import sys
from fabric.api import *
from fabric.contrib import files

def sshd_dnsno():
    files.comment('/etc/ssh/sshd_config', '^UseDNS yes', use_sudo=True)
    files.append('/etc/ssh/sshd_config', 'UseDNS no', use_sudo=True)
    sudo('service ssh restart')

def update_hosts():
    sudo(r'sed -i -E "s/^(127.0.1.1\s+).*/\1$(hostname)/" /etc/hosts')


Output to text

from fabric.api import run
from fabric.api import env
from fabric.api import get

def go_fab():
    temp = run("mktemp")
    run("for i in {1..10000}; do echo $RANDOM >>%s ; done" % (temp))
    run("hostname >>%s" % (temp))
    run("whoami >>%s" % (temp))

    get(temp, "/tmp/%s.log" % (env.host_string))

Refelence:(Japanese)
https://heartbeats.jp/hbblog/2015/07/pythonsshfabric13tips.html

from fabric.api import run, task
from fabric.utils import abort

import os
import sys
import tempfile

def get_exception():
    return sys.exc_info()[1]

@task
def get_rpm():
    rpm_version = run("rpm -qa --queryformat='%{NAME},%{ARCH},%{VERSION}\n'")
    hostname = run("hostname")
    outputdir = '/home/test/output'
    temp = None
    try:
        temp = tempfile.mkstemp(dir=outputdir)
        f = os.fdopen(temp[0], "w")
        f.writelines(rpm_version)
        os.fchmod(temp[0], 0664)
        f.close()
    except Exception:
       e = get_exception()
       if isinstance(temp,list) and os.path.isfile(temp[1]):
       os.remove(temp[1])
       abort(str(e))
    finally:
       os.rename(temp[1], "%s/%s" % (outputdir,hostname))

Refelence:(Japanese)
https://blog.situs.co.jp/tech/%E9%81%8B%E7%94%A8/100%E5%8F%B0%E3%81%AE%E3%82%B5%E3%83%BC%E3%83%90%E6%83%85%E5%A0%B1%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%E3%81%AB%E3%81%AF%E3%80%81fabric%E3%81%8C%E4%BE%BF%E5%88%A9%E3%81%A0%E3%81%A3%E3%81%9F-2/


Return Code and Output

def useradd_user01():
    res = run("id user01", warn_only=True)
    if res.failed is True:
        sudo("useradd user01")
        return

def test01():
    with settings(ok_ret_codes=[0, 24]):
        run("exit 0")
        run("exit 24")
    run("hostname")


Note

from fabric.api import local

def local_ls():
  local('ls /sbin')

from fabric.api import run, sudo, cd

def git_yum_remove():
    sudo('yum -y remove git')

def git_dependency_install():
    sudo("yum -y install curl-devel expat-devel gettext-devel \
                         openssl-devel zlib-devel perl-ExtUtils-MakeMaker")

def git_install_from_tar():
    run("curl -O http://git-core.googlecode.com/files/git-1.8.1.3.tar.gz")
    run("tar zxvf git-1.8.1.3.tar.gz")
    with cd("git-1.8.1.3"):
        run("make prefix=/usr/local all")
        sudo("make prefix=/usr/local install")
    run("rm -rf git-1.8.1.3")

def git_update():
    git_yum_remove()
    git_dependency_install()
    git_install_from_tar()



from fabric.api import *
 
@parallel(pool_size=2)
def edit_hosts():
    sudo('echo "# Do not remove the following line, or various programs" > /etc/hosts')
    sudo('echo "# that require network functionality will fail." >> /etc/hosts')
    sudo('echo "127.0.0.1   localhost.localdomain localhost" >> /etc/hosts')
    sudo('echo "::1 localhost6.localdomain6 localhost6" >> /etc/hosts')
    sudo('echo "" >> /etc/hosts')
    sudo('echo "{host}  `hostname`" >> /etc/hosts'.format(**env))
    sudo('echo "" >> /etc/hosts')
    sudo('echo "# DB" >> /etc/hosts')
    sudo('echo "192.0.2.0   anokonopc" >> /etc/hosts')
 
    sudo('/usr/local/apache/bin/apachectl -k graceful')




Fabric