Issue with specifying a machine as "spare"

4 views
Skip to first unread message

Mike Papper

unread,
Nov 30, 2009, 4:43:30 PM11/30/09
to capis...@googlegroups.com
Hi all,

I wish to specify an app server as "spare" - to be out of the load
balancer rotation. I specified as so:

role :app, '192.168.10.99', :spare => true # machines out of load
balancer rotation

The task is like this:

namespace :loadbalancer do
desc 'Remove "spare" machines from load balancer rotation by
removing public/healthcheck/balancer (to be run just before
apache:reload)'
task :set, :roles => :app, :only => { :spare => true } do
run("rm -f #{release_path}/public/healthcheck/balancer")
end
end

----------------------
The problem is that in some environments (we use what I think is
called multistage) there is no spare machine (i..e, staging) and so I
would configure no machine as designated as spare:

role :app, '192.168.10.99'

When I do this I see this error:

`deploy:loadbalancer:set' is only run for servers matching
{:roles=>:app, :only=>{:spare=>true}}, but no servers matched

----------------------
So, I designated a "blank" machine as spare:
role :app, '', :spare => true # NO machines out of load balancer
rotation

When I run the task, I know see this command being run:
servers: ["192.168.10.90", ""]
followed by an error indiocating it could not ssh into machine due to
an authentication error.
In other words, cap is trying to shh into a blank IP address.
--------------------

Seems like there should be a way to have 'spare' specified in some
configs and not in others - any one know how?

Mike

Lee Hambley

unread,
Nov 30, 2009, 5:33:47 PM11/30/09
to capis...@googlegroups.com
Mike,

Presumably, you are doing this with the capistrano-ext multistage, not homegrown - and you are using seperate deploy.rb files, the standard way to do this is simply not to define the before/after() call in the stage environments that don't use the spare server.

Alternately you might be able to use find_servers() (see the API docs) - to conditionally call the after/before() setup line... but really, only chain the task in the environments that require it.

(and why not provision your spare server, but take it out of the load balancer config using some other process...)

-- Lee Hambley

Twitter: @leehambley | @capistranorb

Mike Papper

unread,
Nov 30, 2009, 6:01:12 PM11/30/09
to capis...@googlegroups.com
Hi,

Home-grown or not I dont know for sure. I do see
    require 'capistrano/ext/multistage'
in the deploy.rb. And we have a single deploy.rb file (in ~rails/config) and multiple configuration files in config/deploy/*.rb.

The tasks that we run are pretty much the same for each environment and so in the main deploy.rb we have:

    before 'deploy:apache:reload', 'deploy:loadbalancer:set' # remove spares from load balancer rotation (breaks if no machine specified as spare)
    before 'deploy:web:enable', 'deploy:apache:reload'

So, every environment shares these sets of dependencies. Here is a sample environment-specific deploy config file:

    set :rails_env, 'staging'
    set :use_sudo, false
    role :app, '192.168.10.20', '192.168.10.21'
    role :web, '192.168.10.20', '192.168.10.21'
    role :db, '192.168.10.20', :primary => true, :no_release => true

I would like to add this:
    role :web, '192.168.10.99', :spare => true

--------------------
When one specifies the db role, is it always strictly necessary to specify :primary for at least one machine?

From your reply, it seems like it is possible to place environment-specific directives in the config file, for example, is this possible:
    ...
    role :web, '192.168.10.99', :spare => true
    before 'deploy:apache:reload', 'deploy:loadbalancer:set' # moved from deploy.rb
    ...

Mike

--
* You received this message because you are subscribed to the Google Groups "Capistrano" group.
* To post to this group, send email to capis...@googlegroups.com
* To unsubscribe from this group, send email to capistrano+...@googlegroups.com For more options, visit this group at http://groups.google.com/group/capistrano?hl=en

Lee Hambley

unread,
Nov 30, 2009, 6:10:46 PM11/30/09
to capis...@googlegroups.com
Primary DB server is where migrations are run. if deploying standard Rails stuff

I suggest making some mix-ins, and mixing them into your stages, your layout - I would expect should look something like this

Capfile
config/
config/deploy.rb
config/stages/
config/stages/production.rb
config/stages/staging.rb

Anything that's universal should be in deploy.rb - stage specifics in production/staging.rb -- if one of your stages doesn't implement some behaviour, then you need to take it out of deploy.rb.

There's no reason you can't add a `config/cap-load-balancer-features.rb` and load() that in your production/staging.rb files, if you don't want to duplicate code.

(sorry, your last email wasn't very coherent, or I am too tired to be supporting :) - I hope my reply answered/helped - if not, post back, and I'll try again in the morning! GMT+1 )

Richie Vos

unread,
Dec 1, 2009, 2:25:21 PM12/1/09
to Capistrano

On my project we do this sort of thing 2 different ways.

The preferred way is what Lee's talking about, where we manage
environment specific tasks with after/before hooks in the stage files
(we do the load of a separate cap file as well).

But if we have something that strategy feels weird for (whether it's
ok for it to not match anything, or it'd be a pain to do it as a
hook), we use the following:

http://gist.github.com/246376
module Capistrano
class Configuration
module Namespaces
def skippable_task(name, *args, &block)
task name, *args do
if find_servers_for_task(current_task).empty?
logger.info "skipping #{current_task.fully_qualified_name}
since it matches no servers"
else
block.call
end
end
end
end
end
end

You just need to put that in a file and require it somewhere in your
deploy. Then, for tasks that you want to skip instead of saying:
task :some_task, :roles => :app do
# ...
end

you'd say:
skippable_task :some_task, :roles => :app do
#...
end

The exact cases we use this for are when the task we want to skip is
nested deep in something else, and it'd be confusing to have to
remember exactly which hook to embed where.
Reply all
Reply to author
Forward
0 new messages