Jamis,

I like your solution. That actually how I thought it was working at  
the beginning, and I had started declaring empty roles until I  
realized it was not allowed.

Thank you for everything!

Mathieu


On Jun 6, 2007, at 7:09 AM, Jamis Buck wrote:

>
> Mathieu,
>
> I'm not yet convinced of the need for :if_no_servers_match, but I do
> see your point about the error when a role does not exist. I
> misunderstood your original post in that regard.
>
> I've just committed a changed to Capistrano that allows you to
> declare empty roles, like so:
>
>    role :foo
>
> In this way, you can "pre-declare" all of the roles that you will
> need, and just allow them to remain empty for scenarios where there
> are no machines that match.
>
> Once you've predeclared all of your roles, you can then do as I
> indicated in my last email (which didn't actually work, if the role
> hadn't been declared):
>
>    task :something, :roles => :whatever do
>      next if find_servers_for_task(current_task).empty?
>      # ...
>    end
>
> If you find this pattern to be really frequent in your own recipes,
> you could create your own macro that wraps "task" and adds the check,
> something like:
>
>    def xtask(name, options={}, &block)
>      task(name, options) do
>        next if find_servers_for_task(current_task).empty?
>        block.call
>      end
>    end
>
> (Warning, that's totally untested, and may not actually work as
> written.)
>
> Then, you would define your tasks with "xtask" instead of "task":
>
>    xtask :something, :roles => :whatever do
>      # ...
>    end
>
> - Jamis
>
> On Jun 5, 2007, at 5:58 PM, Mathieu wrote:
>
>>
>> Jamis,
>>
>> Thanks for your quick answer! Your suggestion sounds much simpler
>> than my instance patch ;)
>>
>> In your example, the "something" task is actually executed until
>> there is a call to find_servers.  find_severs calls role_list_from
>> that raises the error when no host is found for one of the roles of
>> the task. I tried to call find_servers_for_task at the beginning of
>> the task, but find_servers_for_task calls find_servers, so I get the
>> exception anyway.
>>
>> I have patched find_servers and execute_task as follow to follow your
>> suggestion of a task option:
>>
>> Index: lib/capistrano/configuration/execution.rb
>> ===================================================================
>> --- lib/capistrano/configuration/execution.rb   (revision 6951)
>> +++ lib/capistrano/configuration/execution.rb   (working copy)
>> @@ -75,6 +75,7 @@
>>         # Executes the task with the given name, including the before
>> and after
>>         # hooks.
>>         def execute_task(task)
>> +        return if find_servers_for_task(task).empty?
>>           logger.debug "executing `#{task.fully_qualified_name}'"
>>           push_task_call_frame(task)
>>           task.namespace.instance_eval(&task.body)
>> Index: lib/capistrano/configuration/servers.rb
>> ===================================================================
>> --- lib/capistrano/configuration/servers.rb     (revision 6951)
>> +++ lib/capistrano/configuration/servers.rb     (working copy)
>> @@ -35,7 +35,12 @@
>>         #   servers = find_servers :hosts => "[EMAIL PROTECTED]"
>>         def find_servers(options={})
>>           hosts  = server_list_from(ENV['HOSTS'] || options[:hosts])
>> -        roles  = role_list_from(ENV['ROLES'] || options[:roles] ||
>> self.roles.keys)
>> +        begin
>> +          roles  = role_list_from(ENV['ROLES'] || options[:roles] ||
>> self.roles.keys)
>> +        rescue ArgumentError => ex
>> +          return [] if options[:if_no_servers_match] == :skip
>> +          raise ex
>> +        end
>>           only   = options[:only] || {}
>>           except = options[:except] || {}
>>
>> What do you think?
>>
>> Mathieu
>>
>> On Jun 5, 2007, at 3:48 PM, Jamis Buck wrote:
>>
>>>
>>> Just to clarify: it _is_ legal to _declare_ a task for a non- 
>>> existant
>>> or empty role. It just currently raises an exception when you try to
>>> execute that task, if no servers exist in that role at the time.
>>>
>>> As for why that is the case, I suppose it's because I couldn't
>>> envision a use case for a task with empty roles, and figured that
>>> more often than not it would indicate a typo on the user's part.  
>>> (The
>>> current behavior has actually caught errors in my recipe files
>>> several times.) You've raised an interesting point, but I wonder if
>>> you could solve it without resorting to hacking Capistrano. Could  
>>> you
>>> just add a check at the beginning of those tasks, which just exited
>>> the task if there were no matching tasks?
>>>
>>>    task :something, :roles => %(this that) do
>>>      next if find_servers_for_task(current_task).empty?
>>>      # ...
>>>    end
>>>
>>> If that becomes a particularly useful idiom, it could maybe be added
>>> to Capistrano directly, via an option to tasks, something like this:
>>>
>>>    task :something, :roles => %(this that), :if_no_servers_match
>>> => :skip do
>>>      # ...
>>>    end
>>>
>>> - Jamis
>>>
>>> On Jun 5, 2007, at 4:36 PM, Mathieu wrote:
>>>
>>>>
>>>> Hello,
>>>>
>>>> We are currently using CfEngine to deploy our complex application
>>>> (complex because a lot of different components to be installed and
>>>> configured according to one or more roles for each host). I ran  
>>>> into
>>>> so many problems with CfEngine (it might be a good tool, but it is
>>>> definitely not the tool for our needs). I would like to replace it
>>>> with Capistrano.
>>>>
>>>> I am using Capistrano (1.99.1) to deploy a complex application on a
>>>> set of hosts. Deploying the application means installing RPM and  
>>>> GEM
>>>> packages, customized configuration (generated previously,  
>>>> customized
>>>> according to hosts roles), and creating several directories,  
>>>> crontab
>>>> entries, etc...
>>>>
>>>> I wrote a set of tasks for deploying each set of components
>>>> (installing dependencies, application components, configuration
>>>> files, system configuration, etc...). Each task handles one or more
>>>> roles. All that is pretty standard I think.
>>>>
>>>> I started facing a problem when I tried to associate tasks with
>>>> roles
>>>> that are not necessarily declared. Capistrano raises an error when
>>>> declaring a task for a role that is not declared or when
>>>> declaring an
>>>> empty role.
>>>>
>>>> Our application is installed of a platform which size may greatly
>>>> differ. We can build a test platform on one single host for
>>>> instance,
>>>> or on twenty hosts for a production platform. Some roles that run
>>>> statistic servers, SIP registrar, etc... are mandatory. Because the
>>>> combinations are numerous, I wanted to handle them in a simple
>>>> way: a
>>>> task linked to a role is executed if at least one host belongs to
>>>> this role, if not it is just discarded.
>>>>
>>>> I am currently patching the Capistrano instance to be able to  
>>>> handle
>>>> this case:
>>>>
>>>>    def instanciate_capistrano
>>>>      cap = Capistrano::Configuration.new
>>>>      cap.logger.level = Capistrano::Logger::INFO
>>>>      cap.set(:password) { Capistrano::CLI.password_prompt }
>>>>      cap.load(File.dirname(__FILE__) + "/../lib/recipes.rb")
>>>>
>>>>      # patch role_list_from to allow empty roles
>>>>      cap.instance_eval do
>>>>        alias orig_role_list_from role_list_from
>>>>        def role_list_from(roles)
>>>>          roles = roles.split(/,/) if String === roles
>>>>          Array(roles).map do |role|
>>>>            role = String === role ? role.strip.to_sym : role
>>>>            role
>>>>          end
>>>>        end
>>>>
>>>>        alias orig_execute_task execute_task
>>>>        def execute_task(task)
>>>>          orig_execute_task(task) unless find_servers_for_task
>>>> (task).empty?
>>>>        end
>>>>
>>>>      end
>>>>      return cap
>>>>    end
>>>>
>>>> I was wondering if some of you guys had already faced the same
>>>> problem, and how you did handle it. Why isn't it allowed to
>>>> declare a
>>>> task for a role that doesn't exist?
>>>>
>>>> Thanks!
>>>>
>>>> Mathieu
>>>>
>>>>
>>>>
>>>>>
>>>
>>>
>>>>
>>
>>
>>>
>
>
> >


--~--~---------~--~----~------------~-------~--~----~
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at http://groups.google.com/group/capistrano
-~----------~----~----~----~------~----~------~--~---

Reply via email to