Python fabric implements remote manipulation and deployment examples

  • 2020-04-02 13:30:12
  • OfStack

Recently took over more and more things, the release and operation of the work is quite mechanical, plus the frequency is quite high, resulting in time waste or advantages. Bug fixing, testing, submit repository (2 minutes), SSH to the test environment pull deployment (2 minutes), rsync to online machine A, B, C, D, E (1 minute), respectively, SSH to ABCDE five machine, one by one to restart (8 to 10 minutes) = 13-15 minutes of depressed, each operation is the same, command, the trouble is in more than one machine, it is difficult to A script in the machine, the main time is wasted in SSH, command, to the written script, can perform A key, take two minutes to see the results

Until, that is, fabric was able to solidify commands for automated deployment or multi-machine operations into a single script, much like some operations tools, mainly because it was simple to use and easy to use, but also because shell commands could be combined, the difference between ancient artifacts and modern weapons

Environment configuration

Install the corresponding packages on the local and target machines (note that both are required)

Sudo easy_install fabric

Current version 1.6 (or with PIP install, same)

Once installed, you can check to see if the installation was successful


[ken@~$] which fab
/usr/local/bin/fab

After loading, you can browse the official documents

Then, you can do it

Hello world
The first simple operation of the machine, there is a preliminary understanding of the example source and official website

Create a new py script: fabfile.py


def hello():
    print("Hello world!")

Command line execution:

[ken@~/tmp/fab$] fab hello
Hello world!

Done.
Note that you may not use fabfile as the file name, but you will need to specify the file at execution time


[ken@~/tmp/fab$] mv fabfile.py test.py
fabfile.py -> test.py
[ken@~/tmp/fab$] fab hello
Fatal error: Couldn't find any fabfiles!
Remember that -f can be used to specify fabfile path, and use -h for help.
Aborting.
[ken@~/tmp/fab$] fab -f test.py hello
Hello world!

Done.
With parameters:

Modify the fabfile.py script:


def hello(name, value):
    print("%s = %s!" % (name, value))

perform


[ken@~/tmp/fab$] fab hello:name=age,value=20
age = 20!
Done.
[ken@~/tmp/fab$] fab hello:age,20
age = 20!

Done.
Perform native operations
Simple local operation:


from fabric.api import local
def lsfab():
    local('cd ~/tmp/fab')
    local('ls')

Results:


[ken@~/tmp/fab$] pwd;ls
/Users/ken/tmp/fab
fabfile.py   fabfile.pyc  test.py      test.pyc
[ken@~/tmp/fab$] fab -f test.py lsfab
[localhost] local: cd ~/tmp/fab
[localhost] local: ls
fabfile.py  fabfile.pyc test.py     test.pyc

Done.
Actual combat begins:

Suppose you submit a settings.py configuration file to the repository each day (no conflicts are considered here)

If manually operated:


cd /home/project/test/conf/
git add settings.py
git commit -m 'daily update settings.py'
git pull origin
git push origin

That is to say, this a few commands you hand knock again every day, the daily job, every day is repeated, the mechanization of the work, let's look at a key to achieve with the fabric how to fix: (actually use a shell script can be done directly, but the advantage of the fab is not here, here behind the main local preparation + remote operation, the operation of the two places, after all, write a script to facilitate maintenance)


from fabric.api import local
def setting_ci():
    local("cd /home/project/test/conf/")
    local("git add settings.py")
    # You know, I'm too lazy to knock... ..

Mashups integrate remote operations
At this point, suppose you go to the /home/ken/project directory on machine A and update the configuration file


#!/usr/bin/env python
# encoding: utf-8
from fabric.api import local,cd,run
env.hosts=['user@ip:port',] #ssh The parameters to use 
env.password = 'pwd'
def setting_ci():
    local('echo "add and commit settings in local"')
    # I'm going to switch over here, you know 
def update_setting_remote():
    print "remote update"
    with cd('~/temp'):   #cd Used to enter a directory 
        run('ls -l | wc -l')  # Remote operation run
def update():
    setting_ci()
    update_setting_remote()

Then, execute it:


[ken@~/tmp/fab$] fab -f deploy.py update
[user@ip:port] Executing task 'update'
[localhost] local: echo "add and commit settings in local"
add and commit settings in local
remote update
[user@ip:port] run: ls -l | wc -l
[user@ip:port] out: 12
[user@ip:port] out:

Done.
Note that if env.password is not declared, an interaction requiring a password pops up when the corresponding machine is executed

Multi-server mashups
Operating on multiple servers requires the configuration of multiple hosts


#!/usr/bin/env python
# encoding: utf-8
from fabric.api import *
# Consistent servers can be placed in a group, and the same group can perform the same set of operations 
env.roledefs = {
            'testserver': ['user1@host1:port1',],  
            'realserver': ['user2@host2:port2', ]
            }
#env.password = ' Do not use this configuration here, it is impossible to require the password is the same, plaintext is not appropriate. Through all ssh We have to do is '
@roles('testserver')
def task1():
    run('ls -l | wc -l')
@roles('realserver')
def task2():
    run('ls ~/temp/ | wc -l')
def dotask():
    execute(task1)
    execute(task2)

Results:


[ken@~/tmp/fab$] fab -f mult.py dotask
[user1@host1:port1] Executing task 'task1'
[user1@host1:port1] run: ls -l | wc -l
[user1@host1:port1] out: 9
[user1@host1:port1] out:
[user2@host2:port2] Executing task 'task2'
[user2@host2:port2] run: ls ~/temp/ | wc -l
[user2@host2:port2] out: 11
[user2@host2:port2] out:

Done.
extension
1. The color

Can print color, more eye-catching and convenient when viewing the operation result information


from fabric.colors import *
def show():
    print green('success')
    print red('fail')
    print yellow('yellow')
#fab -f color.py show

2. Errors and exceptions

About error handling

By default, a set of commands that will not continue to be executed after the last command failed

Failure can also be handled differently, documentation

I haven't used it yet, but I'll use it later

3. Password management

Look at the document

Better password management, brother more soil, did not get through, mainly because the server list changes frequently, my way of handling is:

1. The host, the user, the port, the password configuration list, all are written in a file

Or directly into the script, which is more...


env.hosts = [
'host1',
'host2'

]
env.passwords = { 
'host1': "pwdofhost1",
'host2': "pwdofhost2",
}

  or


env.roledefs = {
'testserver': ['host1', 'host2'],
'realserver': ['host3', ]
}
env.passwords = {
'host1': "pwdofhost1",
'host2': "pwdofhost2",
'host3': "pwdofhost3", 
} 

2. According to the key, it is parsed into a nested map and put into deploy

In addition, the command can actually be solidified into a list of CMDS... .


Related articles: