Usar diferentes base de datos y único codigo fuente

Hola a todos,

hemos desarrollado una sencilla aplicación de ingresos y gastos para
un departamento de mi empresa. Mantenemos el código con svn y
desplegamos con capistrano.

Ahora otro departamento está interesado en la misma aplicación con las
mismas especificaciones. El problema es que debemos desplegarla en el
mismo servidor con una base de datos diferente por un tema legal.
¿alguna idea de como hacerlo?

De momento hemos conseguido encontrar la forma de desplegar dos
aplicaciones con el mismo código en el mismo servidor a través de
capistrano. Se puede ver en el siguiente código:

task :scenario_a do
set :deploy_to, “/path/to/scenario_a”
role :web, “scenario_a.web”
role :app, “scenario_a.app”
end
task :scenario_b do
set :deploy_to, “/path/to/scenario_b”
role :web, “scenario_b.web”
role :app, “scenario_b.app”
end

De esta forma podemos hacer “$ cap scenario_a deploy” o “$ cap
scenario_b deploy” y desplegar ambas aplicaciones con el mismo código.
Ahí viene el problema, ambos comparten el mismo “database.yml” y es lo
que no me interesa.

¿alguna idea? ¿otra aproximación?

EL problema es que tienes el database.yml en el repositorio y eso no
debes
hacerlo nunca. Para esto, capistrano te crea el directorio shared, ahi
debes
poner los archivos que sean comunes entre versiones y que no se
descargan
del repo.Puedes crear un directorio shared/config y meter ahi el
database.yml para cada aplicación. Luego configuras capistrano para que
en
cada deploy te haga un enlasce simbolico del archivo
current/config/database.yml hacia shared/config/database.yml

task :after_symlink do
run “ln -nfs #{shared_path}/config/database.yml
#{release_path}/config/database.yml”
end

2009/3/17 Gonzalo C. [email protected]

Gracias Emili por tu respuesta,

efectivamente estoy viendo que el problema va por ahí. En la lista de
capistrano sugieren la misma solución que propones tú para un problema
similar.

http://groups.google.com/group/capistrano/browse_thread/thread/be821ff5d3961293/125984ce4fa73a36?lnk=gst&q=database.yml#125984ce4fa73a36

Primero recomiendan poner el database.yml en la lista de ignore del svn
para que no se actulice cada vez. Además añaden otra tarea adicional
para crear un archivo shared/resources/database.yml automáticamente en
al hacer el cap setup. Finalmente meten una tarea que enlaza el archivo
en cada release. Pego aquí el código entero a excepción de lo del svn.

For each developer, they can have their own database.yml
with their dev information. For your production servers, and assuming
you are using capistrano, you can add this to your capistrano.rake file
(or to your own recipe file) to do the following:

desc “create a shared/resources directory for common, non-svn files
(like database.yml)”
task :after_setup, :roles => [:app, :db, :web] do
run <<-CMD
mkdir -p -m 777 #{shared_path}/resources &&
mkdir -p -m 777 #{shared_db} &&
touch #{shared_path}/resources/database.yml
chmod 600 #{shared_path}/resources/database.yml
CMD
end

desc “create a symlink for the database.yml file for the current
project (since it isn’t in source control)”
task :after_update_code, :roles => [:app, :db, :web] do
run <<-CMD
ln -nfs #{shared_path}/resources/database.yml
#{release_path}/config/database.yml
CMD
end

and then put the information you need for your production environment
in the #{shared_path}/resources/database.yml

otra opción parecida si no te apetece estar poniendo cosas a mano en el
servidor y te apetece tener los ficheros bajo control, es tener los
ficheros
de configuración de la base de datos renombrados y estos sí tenerlos en
svn
en plan:
database.yml.site1
database.yml.site2

luego tu database.yml local no lo tendrías en el svn tal como ha
comentado
Emili, ya que dos desarrolladores no tienen por qué estar trabajando
sobre
la misma db

luego a la hora de hacer el deploy le pasas como parámetro el nombre del
site(o lo pides por consola) y al finalizarlo, simplemente renombras el
fichero pertinente(o haces un enlace, lo que más rabia te dé)

2009/3/17 Gonzalo C. [email protected]

2009/3/17 Gonzalo C. [email protected]

Ahora otro departamento está interesado en la misma aplicación con las
mismas especificaciones. El problema es que debemos desplegarla en el
mismo servidor con una base de datos diferente por un tema legal.
¿alguna idea de como hacerlo?

Pues visto que es el mismo servidor y la misma aplicación, un simple
before_filter basado en dominio que establezca la conexión

class ApplicationController < ActionController::Base

before_filter :set_database

def set_database
ActiveRecord::Base.establish_connection(ENV[‘domain’].split[1].to_sym)
end

end

y en el config/database.yml una base de datos por cada dominio.
ENV[“domain”] no creo que sea correcto.

Aunque ahora me entra la duda de si este método es válido con los pool
de
conexiones.

Hola Guillermo,

el inconveniente que le veo a tu propuesta es precisamente el incluir
información de la conexión de base de datos en los ordenadores de
desarrollo. Como comentaban en la lista de capistrano eso es un problema
serio de seguridad ya que cualquier persona con acceso a los ordenadores
de desarrollo o al svn podría ganar acceso a la BD de producción. El
otro método propuesto, aunque algo más confuso al principio, la verdad
es que se despliega fácilmente y se pueden incluir nuevos proyectos con
facilidad.

En cualquier caso gracias por explicar cómo se puede cambiar de base de
datos en el ámbito de aplicación. Era algo que quería saber.

Saludos

Guillermo wrote:

2009/3/17 Gonzalo C. [email protected]

Ahora otro departamento está interesado en la misma aplicación con las
mismas especificaciones. El problema es que debemos desplegarla en el
mismo servidor con una base de datos diferente por un tema legal.
¿alguna idea de como hacerlo?

Pues visto que es el mismo servidor y la misma aplicación, un simple
before_filter basado en dominio que establezca la conexión

class ApplicationController < ActionController::Base

before_filter :set_database

def set_database
ActiveRecord::Base.establish_connection(ENV[‘domain’].split[1].to_sym)
end

end

y en el config/database.yml una base de datos por cada dominio.
ENV[“domain”] no creo que sea correcto.

Aunque ahora me entra la duda de si este método es válido con los pool
de
conexiones.

Gracias a todos, ya lo he solucionado.

El método seguido es el que digo arriba. Aquí está el código que estoy
usando para el capistrano. Espero que le sirva a alguien más.

#Archivo deploy.rb
#Aquí mi repositorio (eliminando lo que no podéis ver)
set :repository,
“svn+ssh://xxxxx@[ip_servidor_repos]/home/xxxxx/repos/nombre_proyecto”

selector de despliegue según escenario

task :nombre_proyecto_a do
set :application, “nombre_proyecto_a”
set :deploy_to, “/home/xxxxx/apps/#{application}”
end

task :nombre_proyecto_b do
set :application, “nombre_proyecto_b”
set :deploy_to, “/home/xxxxx/apps/#{application}”
end

role :app, “[ip_servidor]”
role :web, “[ip_servidor]”
role :db, “[ip_servidor]”, :primary => true

set :use_sudo, false

namespace :deploy do
#esto correponde a mi conf de passenger
desc “Restart Application”
task :restart, :roles => :app do
run “touch #{current_path}/tmp/restart.txt”
end

#esto genera en enlace de la versión actual al archivo de conf

de la base de datos

desc “create a symlink for the database.yml file for the current
project”
task :after_update_code, :roles => [:app, :db, :web] do
run <<-CMD
ln -nfs #{shared_path}/resources/database.yml
#{release_path}/config/database.yml
CMD
end
end

desc “create a shared/resources directory for common, non-svn files
(like database.yml)”
task :after_setup, :roles => [:app, :db, :web] do
run <<-CMD
mkdir -p -m 777 #{shared_path}/resources &&
touch #{shared_path}/resources/database.yml
chmod 600 #{shared_path}/resources/database.yml
CMD
end

Primero habría que hacer “$cap nombre_proyecto_a deploy:setup” y editar
el archivo
“/home/xxxxx/apps/nombre_proyecto_a/shared/resources/database.yml” con
los valores correspondientes a la BD que queramos usar. Después ya
podemos hacer los deploys con “$cap nombre_proyecto_a deploy”. Lo mimso
para nombre_proyecto_b.

Ale, hasta otra

Guillermo wrote:

2009/3/18 Gonzalo C. [email protected]

Hola Guillermo,

el inconveniente que le veo a tu propuesta es precisamente el incluir
información de la conexión de base de datos en los ordenadores de
desarrollo.

No. Siempre puedes tener un config/database.yml en el repo, y un hook de
capistrano before :update_code, que haga vínculo simbólico al
config/database.yml. Si no me equivoco, lo que se comentaba en mensajes
anteriores. Una solución no quita la otra.

Tienes toda la razón, yo mismo comentaba que una opción era hacer que
svn ignorara el database.yml. Así permitimos además que cada
desarrollador tenga su propia configuración de base de datos.

Mi propuesta lo que evita es cargar la memoria de la máquina, ya que
solo
tienes que tener un appserver para las dos applicaciones.

Muy interesante la reflexión, a tener en cuenta.

Como comentaban en la lista de capistrano eso es un problema
serio de seguridad

Me hace gracia eso, proteger el config/database, cuando mucha gente que
me
lo ha comentado:
a) Tiene puesto a mano db_password en capistrano
b) Tiene puesto password en capistrano y una máquina con sudo.
c) Accede por ssh por un sistema de llaves pero con una phrase nula.
d) Tiene habilitado el acceso a la granja de producción desde fuera de
la
oficina.

Hombre, en lista lo comentaban desde el punto de vista de un auditor de
seguridad que jamás permitiría eso. Y malas costumbres las hay a
montones.

se pueden incluir nuevos proyectos con facilidad.

Y cada uno de ellos come más memoria. No digo que sea malo, pero
prefiero
tener 6 mongrels con capacidad de atender cualquier petición, a tener
que
tener 3 mongrel por cada aplicación (suponiendo que son 2). Eso es para
estudiar el entorno al completo. Pongamos que crece y la requiren más
departamentos. Para una misma máquina a 200 Megas por app, 200*6= 1,2
Gigas,
por lo que no se pueden poner más apps sin poner más memoria (suponiendo
que
tiene dos gigas). El rendimiento será mejor si esos 6 son capaces de
procesar cualquier petición, ha tener 2 por cada uno o incluso 1 por
cada
uno.

Como te comentaba antes, me parece una reflexión muy interesante y la
tendré en cuenta. Mis usuarios acceden al mismo código.

En cualquier caso gracias por explicar cómo se puede cambiar de base de

datos en el ámbito de aplicación. Era algo que quería saber.

De nada, pero esto era antes de meter Threads y el correspondiente pool
de
conexiones. No se si ahora mismo seguirá funcionando. No lo he
investigado.

Saludos.

Gracias por el comentario. Muy ilustrativo. ¡Cada día esto más encantado
con Rails y con este foro!

Saludos

2009/3/18 Gonzalo C. [email protected]

Hola Guillermo,

el inconveniente que le veo a tu propuesta es precisamente el incluir
información de la conexión de base de datos en los ordenadores de
desarrollo.

No. Siempre puedes tener un config/database.yml en el repo, y un hook de
capistrano before :update_code, que haga vínculo simbólico al
config/database.yml. Si no me equivoco, lo que se comentaba en mensajes
anteriores. Una solución no quita la otra.

Mi propuesta lo que evita es cargar la memoria de la máquina, ya que
solo
tienes que tener un appserver para las dos applicaciones.

Como comentaban en la lista de capistrano eso es un problema
serio de seguridad

Me hace gracia eso, proteger el config/database, cuando mucha gente que
me
lo ha comentado:
a) Tiene puesto a mano db_password en capistrano
b) Tiene puesto password en capistrano y una máquina con sudo.
c) Accede por ssh por un sistema de llaves pero con una phrase nula.
d) Tiene habilitado el acceso a la granja de producción desde fuera de
la
oficina.

se pueden incluir nuevos proyectos con facilidad.

Y cada uno de ellos come más memoria. No digo que sea malo, pero
prefiero
tener 6 mongrels con capacidad de atender cualquier petición, a tener
que
tener 3 mongrel por cada aplicación (suponiendo que son 2). Eso es para
estudiar el entorno al completo. Pongamos que crece y la requiren más
departamentos. Para una misma máquina a 200 Megas por app, 200*6= 1,2
Gigas,
por lo que no se pueden poner más apps sin poner más memoria (suponiendo
que
tiene dos gigas). El rendimiento será mejor si esos 6 son capaces de
procesar cualquier petición, ha tener 2 por cada uno o incluso 1 por
cada
uno.

En cualquier caso gracias por explicar cómo se puede cambiar de base de

datos en el ámbito de aplicación. Era algo que quería saber.

De nada, pero esto era antes de meter Threads y el correspondiente pool
de
conexiones. No se si ahora mismo seguirá funcionando. No lo he
investigado.

Saludos.

Tengo una aplicacion que corre sobre Ruby on Rails framework. Estoy
construyendo un nuevo plugin y necesito que este se conecte a otra base
de datos y ejecute algunas funciones en el lenguaje plpgsql. Utilizo
Postgresql como gestor de base de datos. ¿Que puedo hacer para
conectarme a esta otra base de datos?