DB-Konfiguration im Team - JRuby mit JNDI

Rails stellt einen einfachen Zugriff auf alle Konfigurationsdaten zur Verfügung. So stehen auch unsere Datenbank-Zugänge in der database.yml. Dies ist wunderbar, wenn man schnell ein Projekt aufsetzen will und anschließend allein mit seinem eigenen Webserver entwickelt. Doch was ist, wenn ein etwas größeres Team an einer Anwendung entwickeln möchte, aber nicht jedes Mitglied ein Login-Passwort Paar der Art "test" - "test" auf seiner lokalen Test-Datenbank vergeben möchte?
Hier bietet Doug Alcorn eine elegante Lösung, in dem er Blöcke innerhalb der YAML-Datei verwendet: Er definiert einen Standard-Loginblock, den er dann in die jeweilige Datenbank-Konfiguration für Development, Test und Production einfließen lässt. Allerdings wird vorher noch der Inhalt einer zweiten Datei eingefügt, die jeder Entwickler in sein config-Verzeichnis legen kann. In dieser kann der Loginblock beliebig überschrieben werden.
Das sieht dann in der database.yml so aus:
login: &login
  username: defaultuser
  password: defaultpassword

<%= file = File.join(RAILS_ROOT, "config", "dblogin.yml")
    IO.read(file) if File.exist?(file) %>

development:
  adapter: mysql
  host: localhost
  database: projectdb
  <<: *login
Die Entwicklerdatei (im Beispiel dblogin.yml) enthält die eigentlichen Logindaten:
login: &login
  username: entwickler
  password: entwicklerpasswort
Natürlich kann man das auf andere Einstellungen erweitern. Haben die verschiedenen Datenbanken unterschiedliche Logins, können mehrere Blöcke definiert und in der dblogin.yml überschrieben werden. Nutzt man dann noch die ignore-Option des Versionsverwaltungssystems seiner Wahl, hat jeder Entwickler seinen eigenen DB-Zugang, ohne ihn bei jeder Konfigurations-Änderung neu eingeben zu müssen.


Verwendet man JRuby on Rails, kann die Anwendung mittels Warbler in eine WAR-Datei gepackt und dann einfach auf einen Webserver gelegt werden. In unserem Beispiel ist dies ein Tomcat 6.0. Hier stehen wir nun schnell vor einem ähnlich gelagerten Problem: Unsere database.yml liegt innerhalb der WAR-Datei und diese muss dadurch zur Build-Zeit wissen, welche Datenbank-Zugriffsdaten sie benötigt. In größeren Firmen kann das sogar schon bei Testservern problematisch sein, ganz zu schweigen von den Produktivumgebungen, da hier nur die IT-Abteilung Zugriff hat und die Anwendungsentwickler eher selten die Passwörter kennen. Dank JRuby heißt die Lösung hier JNDI ("Java Naming and Directory Interface"). Mit nur wenigen Konfigurationsänderungen machen wir unsere Anwendung und den Tomcat miteinander bekannt und überlassen die DB-Konfiguration den Server-Admins. Vier kleine Schritte müssen dafür getan werden.

1. database.yml

Der Eintrag für die Datenbank wird wesentlich kürzer. Anstatt server, login, passwort, port usw. eingeben zu müssen, benötigen wir für die jeweilige Umgebung nur noch 2 Zeilen:
production:
  adapter: jdbc
  jndi: java:comp/env/jdbc/jndiname
Zusätzliche Einstellungen wie z.B. das Encoding können weiter genutzt werden.

2. Warbler

Die Konfiguration von Warbler muss angepasst werden (config/warble.rb). Dabei ist darauf zu achten, dass für den JNDI-Zugriff der gleiche Name wie in der database.yml verwendet wird ("jdbc/jndiname"). Außerdem benötigt man in der WAR-Datei noch das gem „activerecord-jdbc-adaper":
config.webxml.jndi = 'jdbc/jndiname'					
config.gems        << 'activerecord-jdbc-adapter'
Datenbankspezifische gems wie „activerecord-jdbcmysql-adapter" oder „jdbc-mysql" brauchen wir eventuell noch lokal, können aber in der WAR getrost darauf verzichten, da die Anwendung gar nicht mehr weiß, auf welcher Datenbank sie arbeitet.

3. Tomcat

Anschließend müssen wir Tomcat noch beibringen, auf den JNDI-Namen zu hören. Dazu tragen wir in den entsprechenden Context (bei uns reichte der allgemeine Context in conf/context.xml) folgendes ein:
<Resource name="jdbc/jndiname" 
            auth="Container"
            type="javax.sql.DataSource"
            username="..."
            password="..."
            driverClassName="com.mysql.jdbc.Driver"
            url="jdbc:mysql://localhost:3306/db_name" 
            maxActive="8"
            maxIdle="4" />
Auch hier muss wieder der gleiche Ressourcenname wie oben eingetragen werden. Für andere Webserver sieht das natürlich ähnlich aus.

4. Datenbank-Treiber

Zu guter Letzt müssen wir noch sicherstellen, dass Tomcat den Treiber, den wir unter driverClassName angegeben hat, auch kennt. Dafür gibt's vom Datenbank-Hersteller Pakete, die im Tomcat-Verzeichnis unter /lib abgelegt werden können. Den MySQL-Treiber findet man z.B. unter diesem Link.

Nun muss die WAR-Datei nicht mehr angepasst werden, falls der Datenbank-Server sich einmal ändert.


weitere Links
Doug Alcorn - config/database.yml goodness for teams
JNDI
Warbler-Plugin
Tomcat 6.0
MySQL-JDBC-Treiber 5.1