Rich Andrews
2013-12-15 19:55:32 UTC
Hello, some guidance would be greatly appreciated. My difficulty is
understanding the design intention with fab.api.Task subclasses. It
appears that a reasonable pattern is to subclass Task, and implement
task-oriented logic in Task.run(). One would then be left with a reusable
Task subclass that may be used with a variety of @tasks.
For example, should a Task subclass be made that implements some
task-oriented logic in run(), it is believed that the Task would then be
utilized as follows:
@task(task_class=CustomTask, myarg='value_a', alias='ata')
def wrapped_function_a(instance):
# logic is in CustomTask.run()
pass
@task(task_class=CustomTask, myarg='value_b', alias='ata')
def wrapped_function_b(instance):
# logic is in CustomTask.run()
pass
Then, CustomTask is instantiated once for each declared @task decorator,
and customtask.run() is called by the fab runtime with the custom args in
@task and then for each host in the specified role. For example, fab ...
-H a,b,c,d would result in four runs of customtask.run()
The desire is that a decorator such as @runs_once could then be stacked.
But what happens in this case is that the customtask.run() is invoked for
each host specified in the role, and the wrapped function is what runs once.
Is there another preferred way to invoke Task subclasses? Or does the
task-oriented logic belong in the function wrapped by @task?
If the behavior described ins't clear, a runnable code example and output
is available below.
Thanks!
--
Python 2.7.4
Fabric 1.8.0
Paramiko 1.12.0
fab_busybox1.py:
#!/bin/env python
from fabric.api import *
from fabric.tasks import Task
class CustomTask(Task):
# init once for all tasks name this class via task_class
def __init__(self, func, myarg, *args, **kwargs):
super(CustomTask, self).__init__(*args, **kwargs)
self.func = func
self.myarg = myarg
# run multiple times for all hosts in roles
def run(self, *args, **kwargs):
print("%s run()" % self)
return self.func(self, *args, **kwargs)
@task(task_class=CustomTask, myarg='value', alias='at')
@runs_once
def wrapped_custom_task(instance):
print("wrapped_custom_task()")
$ fab -f fab_busybox1.py -H a,b,c,d at
[a] Executing task 'at'
<fab_busybox1.CustomTask object at 0x99fdccc> run()
wrapped_custom_task()
[b] Executing task 'at'
<fab_busybox1.CustomTask object at 0x99fdccc> run()
[c] Executing task 'at'
<fab_busybox1.CustomTask object at 0x99fdccc> run()
[d] Executing task 'at'
<fab_busybox1.CustomTask object at 0x99fdccc> run()
understanding the design intention with fab.api.Task subclasses. It
appears that a reasonable pattern is to subclass Task, and implement
task-oriented logic in Task.run(). One would then be left with a reusable
Task subclass that may be used with a variety of @tasks.
For example, should a Task subclass be made that implements some
task-oriented logic in run(), it is believed that the Task would then be
utilized as follows:
@task(task_class=CustomTask, myarg='value_a', alias='ata')
def wrapped_function_a(instance):
# logic is in CustomTask.run()
pass
@task(task_class=CustomTask, myarg='value_b', alias='ata')
def wrapped_function_b(instance):
# logic is in CustomTask.run()
pass
Then, CustomTask is instantiated once for each declared @task decorator,
and customtask.run() is called by the fab runtime with the custom args in
@task and then for each host in the specified role. For example, fab ...
-H a,b,c,d would result in four runs of customtask.run()
The desire is that a decorator such as @runs_once could then be stacked.
But what happens in this case is that the customtask.run() is invoked for
each host specified in the role, and the wrapped function is what runs once.
Is there another preferred way to invoke Task subclasses? Or does the
task-oriented logic belong in the function wrapped by @task?
If the behavior described ins't clear, a runnable code example and output
is available below.
Thanks!
--
Python 2.7.4
Fabric 1.8.0
Paramiko 1.12.0
fab_busybox1.py:
#!/bin/env python
from fabric.api import *
from fabric.tasks import Task
class CustomTask(Task):
# init once for all tasks name this class via task_class
def __init__(self, func, myarg, *args, **kwargs):
super(CustomTask, self).__init__(*args, **kwargs)
self.func = func
self.myarg = myarg
# run multiple times for all hosts in roles
def run(self, *args, **kwargs):
print("%s run()" % self)
return self.func(self, *args, **kwargs)
@task(task_class=CustomTask, myarg='value', alias='at')
@runs_once
def wrapped_custom_task(instance):
print("wrapped_custom_task()")
$ fab -f fab_busybox1.py -H a,b,c,d at
[a] Executing task 'at'
<fab_busybox1.CustomTask object at 0x99fdccc> run()
wrapped_custom_task()
[b] Executing task 'at'
<fab_busybox1.CustomTask object at 0x99fdccc> run()
[c] Executing task 'at'
<fab_busybox1.CustomTask object at 0x99fdccc> run()
[d] Executing task 'at'
<fab_busybox1.CustomTask object at 0x99fdccc> run()