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()