def setup
begin
- if !DatabaseVersion.production?
- raise "Upgrade is not supported. Please use a production-ready database."
- end
-
- DatabaseVersion.upgrade_and_start unless DatabaseVersion.uptodate?
- hash={:status => 'ok'}
+ # Ask the DB migration manager to start the migration
+ # => No need to check for authorizations (actually everybody can run the upgrade)
+ # nor concurrent calls (this is handled directly by DatabaseMigrationManager)
+ DatabaseMigrationManager.instance.start_migration
+
+ hash={:status => 'ok',
+ :migration_status => DatabaseMigrationManager.instance.status,
+ :message => DatabaseMigrationManager.instance.message}
respond_to do |format|
format.json{ render :json => jsonp(hash) }
format.xml { render :xml => hash.to_xml(:skip_types => true, :root => 'setup') }
verify :method => :post, :only => [ :setup_database ], :redirect_to => { :action => :index }
def index
- if DatabaseVersion.uptodate?
- redirect_to home_path
- elsif ActiveRecord::Base.connected?
- render :template => (DatabaseVersion.production? ? 'setup/form' : 'setup/not_upgradable'), :layout => 'nonav'
- else
- render :template => 'setup/dbdown', :layout => 'nonav'
+ if DatabaseMigrationManager.instance.requires_migration?
+ if ActiveRecord::Base.connected?
+ render :template => 'setup/form', :layout => 'nonav'
+ else
+ render :template => 'setup/dbdown', :layout => 'nonav'
+ end
+ elsif DatabaseMigrationManager.instance.migration_running?
+ render :template => 'setup/migration_running', :layout => 'nonav'
+ elsif DatabaseMigrationManager.instance.migration_failed?
+ render :template => 'setup/failed', :layout => 'nonav'
+ else
+ # migration succeeded, or no need for migration
+ render :template => 'setup/db_uptodate', :layout => 'nonav'
end
end
- def maintenance
- render :template => 'setup/maintenance', :layout => 'nonav'
+ def setup_database
+ # Ask the DB migration manager to start the migration
+ # => No need to check for authorizations (actually everybody can run the upgrade)
+ # nor concurrent calls (this is handled directly by DatabaseMigrationManager)
+ DatabaseMigrationManager.instance.start_migration
+ # and return some text that will actually never be displayed
+ render :text => DatabaseMigrationManager.instance.message
end
- def setup_database
- if !DatabaseVersion.production?
- render :text => 'Upgrade is not supported. Please use a production-ready database.', :status => 500
- else
- # do not forget that this code is also in /api/server/setup (see api/server_controller.rb)
- DatabaseVersion.upgrade_and_start unless DatabaseVersion.uptodate?
- redirect_to home_path
- end
+ def maintenance
+ render :template => 'setup/maintenance', :layout => 'nonav'
end
+
end
--- /dev/null
+#
+# Sonar, entreprise quality control tool.
+# Copyright (C) 2008-2012 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# Sonar is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# Sonar is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with Sonar; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+#
+
+#
+# Class taht centralizes the management the DB migration
+#
+
+require 'singleton'
+require 'thread'
+
+class DatabaseMigrationManager
+
+ # mixin the singleton module to ensure we have only one instance of the class
+ # it will be accessible with "DatabaseMigrationManager.instance"
+ include Singleton
+
+ # the status of the migration
+ @status
+ MIGRATION_NEEDED = "MIGRATION_NEEDED"
+ MIGRATION_RUNNING = "MIGRATION_RUNNING"
+ MIGRATION_FAILED = "MIGRATION_FAILED"
+ MIGRATION_SUCCEEDED = "MIGRATION_SUCCEEDED"
+ NO_MIGRATION = "NO_MIGRATION"
+
+ # the corresponding message that can be given to the user
+ @message
+
+ # the time when the migration was started
+ @start_time
+
+ def initialize
+ if DatabaseVersion.uptodate?
+ @status = NO_MIGRATION
+ @message = "Database is up-to-date, no migration needed."
+ else
+ if DatabaseVersion.production?
+ @status = MIGRATION_NEEDED
+ @message = "Migration required."
+ else
+ @status = MIGRATION_FAILED
+ @message = "Upgrade is not supported. Please use a <a href=\"http://docs.codehaus.org/display/SONAR/Requirements\">production-ready database</a>."
+ end
+ end
+ end
+
+ def message
+ @message
+ end
+
+ def status
+ @status
+ end
+
+ def requires_migration?
+ @status==MIGRATION_NEEDED
+ end
+
+ def migration_running?
+ @status==MIGRATION_RUNNING
+ end
+
+ def migration_failed?
+ @status==MIGRATION_FAILED
+ end
+
+ def migration_start_time
+ @start_time
+ end
+
+ def start_migration
+ # Use an exclusive block of code to ensure that only 1 thread will be able to proceed with the migration
+ can_start_migration = false
+ Thread.exclusive do
+ if requires_migration?
+ @status = MIGRATION_RUNNING
+ @message = "Database migration is currently running."
+ can_start_migration = true
+ end
+ end
+
+ if can_start_migration
+ # launch the upgrade
+ begin
+ @start_time = Time.now
+ DatabaseVersion.upgrade_and_start
+ @status = MIGRATION_SUCCEEDED
+ @message = "The migration succeeded."
+ rescue Exception => e
+ @status = MIGRATION_FAILED
+ @message = "The migration failed: " + e.clean_message + ".<br/> Please check the logs."
+ # rethrow the exception so that it is logged and so that the whole system knows that a problem occured
+ raise
+ end
+ end
+ end
+
+end
--- /dev/null
+<meta http-equiv='refresh' content='5;url=<%= home_path -%>'>
+
+<div class="notice migration" style="padding:10px">
+ <%= image_tag 'accept.png' -%>
+ <b>Database is up-to-date.</b>
+ <br/>
+ <br/>
+ You will be redirected shortly to Sonar.
+ <br/>
+ <i>(if this doesn't happen, you can <a href="<%= home_path -%>">click here to be redirected</a>.)</i>
+</div>
\ No newline at end of file
--- /dev/null
+<div class="warning migration" style="padding:10px">
+ <%= image_tag 'warning.png' -%>
+ <b>Fail to connect to database</b>
+ <br/>
+ <br/>
+ Database connection cannot be established. Please check database status and JDBC settings.
+ <br/>
+ <%= button_to "Try again", { :action => "index" }, :method => :get %>
+</div>
\ No newline at end of file
+++ /dev/null
-<h1>Fail to connect to database</h1>
-<div class="error">
- Database connection cannot be established. Please check database status and JDBC settings.
- <br/><br/>
-<%= button_to "Try again", { :action => "index" }, :method => :get %>
-</div>
\ No newline at end of file
--- /dev/null
+<div class="error migration" style="padding:10px">
+ <%= image_tag 'exclamation.png' -%>
+ <b>Impossible to upgrade database</b>
+ <br/>
+ <br/>
+ <%= DatabaseMigrationManager.instance.message -%>
+</div>
\ No newline at end of file
--- /dev/null
+<div class="admin migration">
+ <h1 class="marginbottom10">Upgrade database</h1>
+ <br/>
+ <h3>Important</h3>
+ <ul>
+ <li>The database upgrade can take several minutes.</li>
+ <li>It is recommended to <b>backup database</b> before upgrading.</li>
+ <li><b>Copy the directory /extensions</b> from previous version before upgrading.</li>
+ </ul>
+ <br/>
+ <%= button_to_remote "Upgrade",
+ :url => { :action => 'setup_database' },
+ :loading => "window.location.reload();" -%>
+</div>
\ No newline at end of file
+++ /dev/null
-<style>
-#setupform {
- padding: 10px;
- border: 2px solid #FFD324;
- background-color: #FFF6B6;
-}
-#setupform td {
- padding-right: 10px;
-
-}
-#setupformlogo {
- float: right;
- padding-left: 20px;
-}
-</style>
-
-<div id="setupform">
-<div id="setupformlogo"><a href="http://www.sonarsource.org"><%= image_tag('sonar.png', :class => 'png') -%></a></div>
-<h1 class="marginbottom10">Upgrade database</h1>
-<br/>
-<h3>Important</h3>
-<p>
- <ul>
- <li><b>Do not refresh this page</b> until the upgrade is finished. It can take several minutes.</li>
- <li>It is recommended to <b>backup database</b> before upgrading.</li>
- <li><b>Copy the directory /extensions</b> from previous version before upgrading.</li>
- </ul>
-</p>
- <br/>
- <form id="submit_form" method="POST" action="<%= url_for :action => 'setup_database' -%>" onsubmit="Form.disable('submit_form');">
- <input type="submit" value="Upgrade" id="submit_setup" />
- </form>
-</div>
\ No newline at end of file
--- /dev/null
+<meta http-equiv='refresh' content='5;'>
+
+<%
+ start_time = DatabaseMigrationManager.instance.migration_start_time
+%>
+
+<div class="admin migration" style="padding:10px">
+ <%= image_tag 'loading.gif' -%>
+ <b>Database upgrade is currently running.</b>
+ <br/>
+ <br/>
+ Started : <%= l start_time -%>
+ <br/>
+ Duration: <%= distance_of_time_in_words(start_time, Time.now) -%>
+</div>
\ No newline at end of file
+++ /dev/null
-<h1>Not supported</h1>
-
-<div class="error">
- Upgrade is not supported. Please use a <a href="http://docs.codehaus.org/display/SONAR/Requirements">production-ready database</a>.
-</div>
\ No newline at end of file
padding: 4px;
}
+/* ------------------- SETUP / MIGRATION PAGES ------------------- */
+.migration {
+ background-image: url("../images/sonar.png");
+ background-repeat: no-repeat;
+ background-position: top right;
+}
+
/* ------------------- LOGIN FORM ------------------- */
#login_form {
border: 1px solid #4b9fd5;