]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-3218 / SONAR-3146 Improve the Sonar migration service
authorFabrice Bellingard <bellingard@gmail.com>
Sun, 20 May 2012 14:48:03 +0000 (16:48 +0200)
committerFabrice Bellingard <bellingard@gmail.com>
Mon, 21 May 2012 09:35:55 +0000 (11:35 +0200)
- Offers better mechanism to prevent any parallel executions
- Provides information on the time already spent
- Adapt UI & WS to use this mechanism

12 files changed:
sonar-server/src/main/webapp/WEB-INF/app/controllers/api/server_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/controllers/setup_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/models/database_migration_manager.rb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/setup/db_uptodate.html.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/setup/dbdown.html.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/setup/dbdown.rhtml [deleted file]
sonar-server/src/main/webapp/WEB-INF/app/views/setup/failed.html.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/setup/form.html.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/setup/form.rhtml [deleted file]
sonar-server/src/main/webapp/WEB-INF/app/views/setup/migration_running.html.erb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/setup/not_upgradable.html.erb [deleted file]
sonar-server/src/main/webapp/stylesheets/style.css

index 7ab010d6465f3d3062efe5792c6c7c0e553b4b17..e81924ec968d0de0338182b338101edc8819312d 100644 (file)
@@ -66,12 +66,14 @@ class Api::ServerController < Api::ApiController
 
   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') }
index a3d79c8e4f529b7b3e25d3af9c6dcf13b27dc683..2cac046bdbc919fd9dae3b3d8978c531d4092e8b 100644 (file)
@@ -25,26 +25,33 @@ class SetupController < ApplicationController
   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
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/database_migration_manager.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/database_migration_manager.rb
new file mode 100644 (file)
index 0000000..4f3072c
--- /dev/null
@@ -0,0 +1,114 @@
+#
+# 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
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/setup/db_uptodate.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/setup/db_uptodate.html.erb
new file mode 100644 (file)
index 0000000..7029eda
--- /dev/null
@@ -0,0 +1,11 @@
+<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
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/setup/dbdown.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/setup/dbdown.html.erb
new file mode 100644 (file)
index 0000000..c98fee7
--- /dev/null
@@ -0,0 +1,9 @@
+<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
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/setup/dbdown.rhtml b/sonar-server/src/main/webapp/WEB-INF/app/views/setup/dbdown.rhtml
deleted file mode 100644 (file)
index fe37862..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-<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
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/setup/failed.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/setup/failed.html.erb
new file mode 100644 (file)
index 0000000..5c4306f
--- /dev/null
@@ -0,0 +1,7 @@
+<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
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/setup/form.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/setup/form.html.erb
new file mode 100644 (file)
index 0000000..51052b9
--- /dev/null
@@ -0,0 +1,14 @@
+<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
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/setup/form.rhtml b/sonar-server/src/main/webapp/WEB-INF/app/views/setup/form.rhtml
deleted file mode 100644 (file)
index 3e765f9..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-<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
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/setup/migration_running.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/setup/migration_running.html.erb
new file mode 100644 (file)
index 0000000..cee75c5
--- /dev/null
@@ -0,0 +1,15 @@
+<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
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/setup/not_upgradable.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/setup/not_upgradable.html.erb
deleted file mode 100644 (file)
index bd3c0f1..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<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
index 6a4174cc180f6e941d1a5ceaa9b13afeb0e73a3f..6889c3946440236566c179f8b8d576633397cdcf 100644 (file)
@@ -522,6 +522,13 @@ h4, .h4 {
   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;