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
-~----------~----~----~----~------~----~------~--~---