Dynamic (runtime) role

375 views
Skip to first unread message

ky

unread,
Sep 14, 2007, 11:46:32 PM9/14/07
to Capistrano
I use Amazon's EC2 for my production system. Currently I'm writing a
recipe to spawn a new server instance and massage it into a fresh,
clean, staging instance. My recipes all set, except one thing: EC2
provides a dynamic, unpredictable server name (something like
ec2-67-202-12-42.z-1.compute-1.amazonaws.com). I'd like to connect to
this machine thru capistrano (and give it a better dns name, amongst
other things) -- but how?

Roles apparently cannot be set within a task dynamically at runtime --
this message told me so: "/usr/local/lib/ruby/gems/1.8/gems/
capistrano-2.0.0/lib/capistrano/configuration/namespaces.rb:170:in
`role': roles cannot be defined in a namespace (NotImplementedError)"

Has anyone encountered this problem? If so, what solution do you
suggest?

Michael Bushkov

unread,
Sep 15, 2007, 5:41:51 AM9/15/07
to capis...@googlegroups.com
Hi,
Actually you can set roles dynamically. There are 2 ways:
1) You can define you role as a block:
set(:myrole) { (fetch(:remote, nil) == nil) ? :local : :app }

The code inside the block can do actually anything.
Then you can use your role in tasks this way:
task :check_app_status, :roles => myrole do

The important thing here is that you must place "set(:myrole)" statement
strictly before the definition of any task that uses "myrole".

2) The dirtier but more dynamic solution:
parent.roles[:myrole] = [] #clearing the role servers list
parent.role :myrole, server_host #appending the hostname to the role

Hope this would help.
--
Cheers,
Michael

ky

unread,
Sep 15, 2007, 10:31:20 AM9/15/07
to Capistrano
Thanks for the help -- however, I don't think either of these
solutions will work for my problem.

The first solution dynamically sets a variable to a symbol -- the
symbol can be used to look up statically declared host-roles.
However, I have a dynamic host.

The second solution throws this error: /usr/local/lib/ruby/gems/1.8/
gems/capistrano-2.0.0/lib/capistrano/configuration/connections.rb:
121:in `execute_on_servers': undefined method `host' for
"ec2-67-202-12-42.z-1.compute-1.amazonaws.com":String (NoMethodError).

I could keep hacking, but I figured it'd be wiser to get a Community
Approved Solution (tm).

Michael Bushkov

unread,
Sep 15, 2007, 10:53:45 AM9/15/07
to capis...@googlegroups.com
ky wrote:
>
> I could keep hacking, but I figured it'd be wiser to get a Community
> Approved Solution (tm).
>
Yup, that's the option :) Actually maybe the simplest solution for you
will be to place the code that will discover the hostname into the
/etc/capistrano.conf, because it is executed prior to any recipe:
..
.. #discover dynamic host name, put it into 'dhname' variable
..
set :dynamic_host, dhname

and then in one of your recipies you can have the following task definition:
task :check_app_status, :roles => dynamic_host do
..
end

In this case the task's role will be the 'dynamic_host' contents.

>
> The second solution throws this error: /usr/local/lib/ruby/gems/1.8/
> gems/capistrano-2.0.0/lib/capistrano/configuration/connections.rb:
> 121:in `execute_on_servers': undefined method `host' for
> "ec2-67-202-12-42.z-1.compute-1.amazonaws.com":String (NoMethodError).

Sorry, the right variant is the:


arent.roles[:myrole] = [] #clearing the role servers list

parent.role :myrole, Capistrano::ServerDefinition.new(server_host)

--
Cheers,
Michael

ky

unread,
Sep 19, 2007, 10:23:23 AM9/19/07
to Capistrano
Thanks Michael.
In the end this worked:

parent.roles[:myrole] =
[Capistrano::ServerDefinition.new(my_staging_name)]

This is definately not part of the api, but at this time its the only
way I've found to make it work. Any cleaner solutions welcome.

Reply all
Reply to author
Forward
0 new messages