fab-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Fab-user] Wait for parallel task to complete


From: Morgan Goose
Subject: Re: [Fab-user] Wait for parallel task to complete
Date: Tue, 1 May 2012 16:02:25 -0700

Notice the section in
http://docs.fabfile.org/en/1.4.1/api/core/tasks.html#fabric.tasks.execute
where it mentions that "Any other arguments or keyword arguments will
be passed verbatim into task when it is called, so execute(mytask,
'arg1', kwarg1='value') will (once per host) invoke mytask('arg1',
kwarg1='value')."

It is refering, albeit not clearly, to the fact that any keyword that
is given will be used as if it were a member of the env dict. So you
can use any of these env var names to specify things, eg:
parallel=True; 
http://docs.fabfile.org/en/1.4.1/usage/env.html#full-list-of-env-vars

Also I fumbled the name of the decorator. It's serial:
http://docs.fabfile.org/en/1.4.1/api/core/decorators.html#fabric.decorators.serial

You can also specify custom args to fab tasks:
http://docs.fabfile.org/en/1.4.1/usage/fab.html#per-task-arguments

And with that you could make the deploy task take a role name, or list
of hosts to then use as the lists, local and remote, to use in your
script.

-goose

On Tue, May 1, 2012 at 12:01 PM, anatoly techtonik <address@hidden> wrote:
> Hi Morgan,
>
> I've tried your example, which is:
>
>  local = ['a','b']
>  remote = ['c','d']
>
>  def test:pass
>  def update:pass
>
> address@hidden
> address@hidden
>  def deploy():
>     execute(test, hosts=local+remote)
>     execute(update, hosts=local+remote)
>
> At first it didn't run at all with Fabric 1.4.1, unable to call
> @sequential decorator:
>
>  Traceback (most recent call last):
>    ...
>    File "/checkout83/fabfile.py", line 20, in <module>
>     address@hidden
>  NameError: name 'sequential' is not defined
>
> I commented the @sequential, after which `fab deploy` run sequentially:
>  local test
>  remote test
>  local update
>  remote update
>
> That's much better, but it still impossible to specify hosts from
> command line. `fab -H local deploy` still runs additional command on
> the remote, and `fab -H local,remote deploy` run everything twice on
> both hosts.
>
> I couldn't find parallel among params for execute -
> http://docs.fabfile.org/en/1.4.1/api/core/tasks.html#fabric.tasks.execute
> so I've just decorated functions:
>
>  local = ['a','b']
>  remote = ['c','d']
>
> address@hidden
> address@hidden
>  def test:pass
> address@hidden
> address@hidden
>  def update:pass
>
> address@hidden
>  def deploy():
>     execute(test, hosts=local+remote)
>     execute(update, hosts=local+remote)
>
> I must admit that although not ideally, but this works. I just need to
> make sure that deploy is always called with empty host list and I need
> to find a way to specify hosts from command line for the subtasks.
> --
> anatoly t.
>
>
> On Fri, Apr 27, 2012 at 11:48 PM, Morgan Goose <address@hidden> wrote:
>> The example I gave you and how to run it did all of those things, sans
>> the parallel. Execute has parallel as a param. Use that in your master
>> task's executes, and you'll have everything. If that still isn't what
>> you're looking for, we're going to need more information. Eg, like you
>> did before where you said how you're seeing it run, and how you'd
>> instead like it to run, complete with how you ran it with fab, and how
>> the fabfile looks.
>>
>> -goose
>>
>> On Thu, Apr 26, 2012 at 10:32 PM, anatoly techtonik <address@hidden> wrote:
>>> Thanks for the explanation. I read the tutorial. Still I see I can't
>>> construct the system that will satisfy the following usability
>>> requirements:
>>>
>>>  1. Define (or override) hosts from command line
>>>  2. Execute each scheduled task in parallel
>>>  3. Wait until previous task completes successfully on all servers
>>> before moving to the next one
>>>  4. Ability to run each task separately or use master task as a helper 
>>> command
>>>
>>> Command line hosts (1) is needed to test new nodes and control
>>> deployment from 3rd party application.
>>> Parallel execution (2) and (3) is critical to minimize servers downtime.
>>> Master task (4) is also highly desired, because full deployment process
>>> contains a lot of steps.
>>>
>>> It seems that this could be real with the @mastertask decorator that
>>> would make task run without servers at all. With it the following
>>> could work as expected.
>>>
>>> @task
>>> @parallel
>>> def test:pass
>>>
>>> @task
>>> @parallel
>>> def update:pass
>>>
>>> @mastertask
>>> def deploy():
>>>   execute(test)
>>>   execute(update)
>>>
>>> --
>>> anatoly t.
>>>
>>>
>>> On Fri, Apr 27, 2012 at 1:28 AM, Morgan Goose <address@hidden> wrote:
>>>> I just read that last line, where you said you wanted to run them with
>>>> hosts defined at runtime. You can either use functions to generate the
>>>> hosts lists or with said example i gave change it up to get rid of the
>>>> deploy task, and then run the fabfile like:
>>>>    $ fab -H local,remote test update
>>>>
>>>> As that will be sequential and honor the host list as well. It will
>>>> also run the test on all hosts before moving to the next task listed,
>>>> update.
>>>>
>>>> -goose
>>>>
>>>> On Thu, Apr 26, 2012 at 3:25 PM, Morgan Goose <address@hidden> wrote:
>>>>> First have you read the tutorial? This is the section that will get
>>>>> you in on host list defining, and point you the the more detailed
>>>>> information that I link to below it:
>>>>> http://docs.fabfile.org/en/1.4.1/tutorial.html#defining-connections-beforehand
>>>>> http://docs.fabfile.org/en/1.4.1/usage/execution.html#host-lists
>>>>>
>>>>> As to what you want to do. Each task will loop over it's list of hosts
>>>>> to run on. So top down it's TaskA over all HostListA's hosts. Then if
>>>>> no errors move to the other task with the same or unique host list
>>>>> (defined either globally or per task).
>>>>>
>>>>> From what you're wanting to do you will construct the fabfile like this:
>>>>>
>>>>> local = ['a','b']
>>>>> remote = ['c','d']
>>>>>
>>>>> def test:pass
>>>>> def update:pass
>>>>>
>>>>> @task
>>>>> @sequential
>>>>> def deploy():
>>>>>    execute(test, hosts=local+remote)
>>>>>    execute(update, hosts=local+remote)
>>>>>
>>>>>
>>>>> Then all hosts will have the test task run on them before moving to
>>>>> looping over the two hosts lists and running the update. You then call
>>>>> it simply with:
>>>>>
>>>>> $ fab deploy
>>>>>
>>>>> And you never run the test and update tasks themselves. Nor do you
>>>>> define anything to be parallel. As parallel runs on the task would
>>>>> test on both hosts in parallel, and then deploy to both hosts in
>>>>> parallel. This was, running sequential and explicitly defined to do
>>>>> so, will fail fast on the test hosts if one dies. Because the host
>>>>> list's order is honored.
>>>>>
>>>>> -goose
>>>>>
>>>>> On Wed, Apr 25, 2012 at 1:13 PM, anatoly techtonik <address@hidden> wrote:
>>>>>> On Sat, Apr 21, 2012 at 7:51 PM, Jeff Forcier <address@hidden> wrote:
>>>>>>> On Fri, Apr 20, 2012 at 5:31 AM, anatoly techtonik <address@hidden> 
>>>>>>> wrote:
>>>>>>>
>>>>>>>> Is it possible in fabric to wait until a subtask completes on all
>>>>>>>> servers successfully before moving to next step?
>>>>>>>
>>>>>>> You need to use execute() to treat subroutines as if they were full
>>>>>>> fledged tasks. execute() is the machinery that says "take this
>>>>>>> function and run it once per host in this list of hosts." Right now
>>>>>>> that machinery is just applying implicitly to your deploy() task and
>>>>>>> you're probably using env.hosts to set your host list.
>>>>>>>
>>>>>>> Remove env.hosts and maybe make that host list a role in env.roledefs.
>>>>>>> Then you can do this:
>>>>>>>
>>>>>>>    env.roledefs = {'myrole': ['a', 'b', 'c']}
>>>>>>>
>>>>>>>    def test(): ...
>>>>>>>    def update(): ...
>>>>>>>
>>>>>>>    def deploy():
>>>>>>>        execute(test, role='myrole')
>>>>>>>        execute(update, role='myrole')
>>>>>>>
>>>>>>> That should have the effect you want: "fab deploy" => first test()
>>>>>>> runs once per host, and when it's all done, update() will run once per
>>>>>>> host. deploy() itself will end up running only one time total -- it's
>>>>>>> just a "meta" task now.
>>>>>>
>>>>>> It took time to realize the that execute() iterates over the global
>>>>>> list of hosts. I expected that the following two to be equivalent, but
>>>>>> they were not:
>>>>>>
>>>>>>  1. fab -H local,remote test update
>>>>>>  2. fab -H local,remote deploy
>>>>>>
>>>>>> I used the script without roles:
>>>>>>
>>>>>>  def test(): ...
>>>>>>  def update(): ...
>>>>>>  def deploy():
>>>>>>      execute(test)
>>>>>>      execute(update)
>>>>>>
>>>>>> 1st execution variant is fully synchronous (i.e. next task doesn't
>>>>>> start until previous finishes) and gave the sequence:
>>>>>>
>>>>>>  local test
>>>>>>  local update
>>>>>>  remote test
>>>>>>  remove update
>>>>>>
>>>>>> but the 2nd variant with subtasks was confusing (I indented to see
>>>>>> what's going on):
>>>>>>
>>>>>>  local deploy
>>>>>>    local test
>>>>>>    remote test
>>>>>>    local update
>>>>>>    remote update
>>>>>>  remote deploy
>>>>>>    local test
>>>>>>    remote test
>>>>>>    local update
>>>>>>    remote update
>>>>>>
>>>>>> I found fabric pretty counter-intuitive in this case. I tried to fix
>>>>>> that without roles by explicitly passing current host:
>>>>>>
>>>>>>  def test(): ...
>>>>>>  def update(): ...
>>>>>>  def deploy():
>>>>>>      execute(test, host=env.host_string)
>>>>>>      execute(update, host=env.host_string)
>>>>>>
>>>>>> This gives:
>>>>>>  local deploy
>>>>>>    local test
>>>>>>    local update
>>>>>>  remote deploy
>>>>>>    remote test
>>>>>>    remove update
>>>>>>
>>>>>> Still not the desired behavior. The desired is:
>>>>>>  deploy
>>>>>>    local test
>>>>>>    remote test
>>>>>>    wait
>>>>>>    local update
>>>>>>    remote update
>>>>>>
>>>>>> I've tried using @parallel decorator for deploy task and it seemed to
>>>>>> work fine at first.
>>>>>>  local deploy
>>>>>>  remote deploy
>>>>>>  remote test
>>>>>>  local test
>>>>>>  local update
>>>>>>  remote update
>>>>>>
>>>>>> But the test step didn't not synchronize - local update executed while
>>>>>> remote test was still running. It looks like the roles is the only
>>>>>> chance, but I'd like to avoid hardcoding server names at all costs. Is
>>>>>> it possible?
>>>>>>
>>>>>> --
>>>>>> anatoly t.
>>>>>>
>>>>>> _______________________________________________
>>>>>> Fab-user mailing list
>>>>>> address@hidden
>>>>>> https://lists.nongnu.org/mailman/listinfo/fab-user



reply via email to

[Prev in Thread] Current Thread [Next in Thread]