By the way, the other day, I had the opportunity to have a friend see my post. "Kimoi, the picture is disgusting. Really disgusting? Has anyone ever pointed out?" I received a highly acclaimed comment.
fabric is a simple and very powerful tool.
However, it is also a dangerous tool depending on how it is used. You need to be very careful, especially when used by human debris like me.
Would I like to deploy something strange in the production environment today? Strange people (bosses and others) are watching the handcuffs jerky.
You have to be careful.
However, no matter how careful you are, an error will occur. Therefore, you have to give proper error handling so as not to break various things. If you get an error somewhere after editing the config file, The daemon never started again because I changed only the file, You have to roll back so that it doesn't happen.
Then, they return to their original state and leave as if nothing had happened. It's as if a human like me didn't exist from the beginning.
The irrelevant preface is the worst long, but it's a fabric rollback approach.
The basis of rollback processing when an error occurs in fabric is to wrap it in ʻenv.warn_only = True`. Try not to abort suddenly, and if an error occurs, roll back carefully. That's the one.
with settings(warn_only=True):
backup_important_file()
run('sed -e "s/foo/bar/g" important_file > tmp_file')
run('mv tmp_file important_file')
result = do_something_bad()
if result.return_code != 0:
# Rollbacking…
restore_important_file()
However, there are often multiple tasks performed by fabric.
If the rollback processing required for each task error is common, If you implement it obediently, it looks like this, for example.
env.warn_only=True
def task1():
result = run('run command1')
if result.return_code != 0:
rollback()
def task2():
result = run('run command2')
if result.return_code != 0:
rollback()
def task3():
result = run('run command3')
if result.return_code != 0:
rollback()
def rollback():
# Rollbacking...
restore_everything()
@task
def do_it():
task1()
task2()
task3()
This is often sufficient, but a slightly clearer method is possible.
By preparing a wrapper function and utilizing the context manager, It is possible to combine the rollback processing of multiple tasks.
If the rollback process is common to multiple tasks, This is cleaner.
env.warn_only=False
def task1():
run('run command1')
def task2():
run('run command2')
def task3():
run('run command3')
def rollback():
# Rollbacking...
restore_everything()
@contextmanager
def rollbackwrap():
try:
yield
except SystemExit:
rollback()
abort("Error has occurred while running task!")
@task
def do_it():
with rollbackwrap():
task1()
task2()
task3()
task4()
Where you want to handle errors individually
with settings(warn_only=True):
It would be good to use.
I have referred to the following articles very much. http://awaseroot.wordpress.com/2012/06/05/fabric-wrappers-and-more-error-handling/
Recommended Posts