Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making nested calls to "execute" with Python's Fabric library

Tags:

python

fabric

Python's Fabric provides the ability to invoke fabric functions outside of the fab utility using the execute function. A contextual problem arises when an execute function is invoked within another function that was called using execute. Fabric loses the context of the outer execute when the inner execute is invoked and never recovers it. For example:

env.roledefs = {
    'webservers': ['web1','web2'],
    'load_balancer': ['lb1']
}

@roles('webserver')
def deploy_code():
    #ship over tar.gz of code to unpack.
    ...
    execute(remove_webserver_from_load_balancer, sHost=env.host_string)
    ...
    #shutdown webserver, unpack files, and restart web server
    ...
    execute(add_webserver_to_load_balancer, sHost=env.host_string)

@roles('load_balancer')
def remove_webserver_from_load_balancer(sHost=None):
   ssh("remove_host %s" % sHost)

execute(deploy_code)

After the first call to execute, Fabric completely loses its context and executes all further commands within the deploy_code function with host_string='lb1' instead of 'web1'. How can I get it to remember it?

I came up with this hack, but I feel like it could break on future releases:

 with settings(**env):
     execute(remove_webserver_from_load_balancer, sHost=env.host_string)

This effectively saves all state and restores it after the call, but seems like an unintended use of the function. Is there a better way to tell Fabric that it's in a nested execute and to use a settings stack or an equivalent method to remember state?

Thanks!

like image 648
adowds Avatar asked Jan 19 '12 03:01

adowds


1 Answers

Your not using fabric right. As you'd just call fab deploy_code instead of running the fabfile like it's python. I'd suggest going through the tutorial for a better idea on how to structure your fabfile.

Anyhow though, you can look here for how to use execute(), and here for more of the specifics.

You have a typo in that you've dropped the 's' from the webservers role. Which might account for you not having a good host string when you want it on the second task.

But that aside, you can also set roles and hosts in the execute() command itself.

like image 177
Morgan Avatar answered Oct 11 '22 21:10

Morgan