diff options
14 files changed, 64 insertions, 328 deletions
diff --git a/it/it-tests/src/test/java/it/serverSystem/ServerSystemRestartingOrchestrator.java b/it/it-tests/src/test/java/it/serverSystem/ServerSystemRestartingOrchestrator.java index 8161521a34b..090d38fadd8 100644 --- a/it/it-tests/src/test/java/it/serverSystem/ServerSystemRestartingOrchestrator.java +++ b/it/it-tests/src/test/java/it/serverSystem/ServerSystemRestartingOrchestrator.java @@ -22,17 +22,19 @@ package it.serverSystem; import com.sonar.orchestrator.Orchestrator; import com.sonar.orchestrator.locator.FileLocation; import java.io.File; +import java.util.Map; import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.sonar.wsclient.services.Server; -import org.sonar.wsclient.services.ServerQuery; +import org.sonarqube.ws.client.GetRequest; +import org.sonarqube.ws.client.WsResponse; import util.ItUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; +import static util.ItUtils.newWsClient; /** * This class start a new orchestrator on each test case @@ -77,8 +79,9 @@ public class ServerSystemRestartingOrchestrator { .build(); orchestrator.start(); - Server.Status status = orchestrator.getServer().getAdminWsClient().find(new ServerQuery()).getStatus(); - assertThat(status).isEqualTo(Server.Status.UP); + WsResponse statusResponse = newWsClient(orchestrator).wsConnector().call(new GetRequest("api/system/status")); + Map<String, Object> json = ItUtils.jsonToMap(statusResponse.content()); + assertThat(json.get("status")).isEqualTo("UP"); } // SONAR-4748 diff --git a/it/it-tests/src/test/java/it/serverSystem/ServerSystemTest.java b/it/it-tests/src/test/java/it/serverSystem/ServerSystemTest.java index 1cd6ca181a4..e4f08d62afc 100644 --- a/it/it-tests/src/test/java/it/serverSystem/ServerSystemTest.java +++ b/it/it-tests/src/test/java/it/serverSystem/ServerSystemTest.java @@ -28,13 +28,10 @@ import java.util.Map; import okhttp3.Response; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.StringUtils; import org.json.simple.JSONValue; import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; -import org.sonar.wsclient.services.Server; -import org.sonar.wsclient.services.ServerQuery; import org.sonarqube.ws.MediaTypes; import org.sonarqube.ws.ServerId.ShowWsResponse; import org.sonarqube.ws.client.GetRequest; @@ -44,10 +41,12 @@ import pageobjects.Navigation; import pageobjects.ServerIdPage; import util.ItUtils; +import static org.apache.commons.lang.StringUtils.startsWithAny; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; import static util.ItUtils.call; import static util.ItUtils.newAdminWsClient; +import static util.ItUtils.newWsClient; import static util.selenium.Selenese.runSelenese; public class ServerSystemTest { @@ -62,15 +61,18 @@ public class ServerSystemTest { @Test public void get_sonarqube_version() { - String version = orchestrator.getServer().getWsClient().find(new ServerQuery()).getVersion(); - if (!StringUtils.startsWithAny(version, new String[] {"5.", "6."})) { + Map<String, Object> json = callStatus(); + + String version = (String)json.get("version"); + if (!startsWithAny(version, new String[] {"6."})) { fail("Bad version: " + version); } } @Test public void get_server_status() { - assertThat(orchestrator.getServer().getWsClient().find(new ServerQuery()).getStatus()).isEqualTo(Server.Status.UP); + Map<String, Object> json = callStatus(); + assertThat(json.get("status")).isEqualTo("UP"); } @Test @@ -99,6 +101,11 @@ public class ServerSystemTest { assertThat(serverId).isNotEmpty(); } + private Map<String, Object> callStatus() { + WsResponse statusResponse = newWsClient(orchestrator).wsConnector().call(new GetRequest("api/system/status")); + return ItUtils.jsonToMap(statusResponse.content()); + } + @Test public void display_system_info() { runSelenese(orchestrator, "/serverSystem/ServerSystemTest/system_info.html"); diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/JwtCsrfVerifier.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/JwtCsrfVerifier.java index 18e460a1a32..89bb917aef7 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/authentication/JwtCsrfVerifier.java +++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/JwtCsrfVerifier.java @@ -51,7 +51,6 @@ public class JwtCsrfVerifier { "/api/issues/bulk_change", "/api/projects/create", "/api/properties/create", - "/api/server", "/api/user_properties"); public String generateState(HttpServletRequest request, HttpServletResponse response, int timeoutInSeconds) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/UserSessionInitializer.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/UserSessionInitializer.java index b0fcf8a7a72..c419f034653 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/authentication/UserSessionInitializer.java +++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/UserSessionInitializer.java @@ -64,7 +64,7 @@ public class UserSessionInitializer { "/setup/*", "/sessions/*", "/api/system/db_migration_status", "/api/system/status", "/api/system/migrate_db", - "/api/server/index", "/api/server/setup", "/api/server/version", + "/api/server/version", "/api/users/identity_providers", "/api/l10n/index", LOGIN_URL, LOGOUT_URL, VALIDATE_URL); diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/ServerWs.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/ServerWs.java index 4683e3a2838..9ccf5690922 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/ServerWs.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/ServerWs.java @@ -20,52 +20,38 @@ package org.sonar.server.platform.ws; import com.google.common.io.Resources; -import org.sonar.api.server.ws.RailsHandler; +import org.apache.commons.io.IOUtils; +import org.sonar.api.platform.Server; +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.RequestHandler; +import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; +import org.sonarqube.ws.MediaTypes; -public class ServerWs implements WebService { +public class ServerWs implements WebService, RequestHandler { - @Override - public void define(Context context) { - NewController controller = context.createController("api/server") - .setDescription("Get system properties and upgrade db") - .setSince("2.10"); - - defineIndexAction(controller); - defineSetupAction(controller); + private final Server server; - controller.done(); + public ServerWs(Server server) { + this.server = server; } - private void defineIndexAction(NewController controller) { - NewAction action = controller.createAction("index") - .setDescription("Get the server status:" + - "<ul>" + - "<li>UP</li>" + - "<li>DOWN (generally for database connection failures)</li>" + - "<li>SETUP (if the server must be upgraded)</li>" + - "<li>MIGRATION_RUNNING (the upgrade process is currently running)</li>" + - "</ul>") - .setSince("2.10") - .setHandler(RailsHandler.INSTANCE) - .setInternal(true) - .setResponseExample(Resources.getResource(this.getClass(), "example-index.json")); - - RailsHandler.addFormatParam(action); - } + @Override + public void define(Context context) { + NewController controller = context.createController("api/server"); - private void defineSetupAction(NewController controller) { - NewAction action = controller.createAction("setup") - .setDescription("Upgrade the SonarQube database") + controller.createAction("version") + .setDescription("Version of SonarQube in plain text") .setSince("2.10") - .setPost(true) - .setInternal(true) - .setHandler(RailsHandler.INSTANCE) - .setResponseExample(Resources.getResource(this.getClass(), "example-setup.json")); + .setResponseExample(Resources.getResource(this.getClass(), "example-server-version.txt")) + .setHandler(this); - action.createParam("format") - .setDescription("Response format") - .setPossibleValues("json", "csv", "text"); + controller.done(); } + @Override + public void handle(Request request, Response response) throws Exception { + response.stream().setMediaType(MediaTypes.TXT); + IOUtils.write(server.getVersion(), response.stream().output()); + } } diff --git a/server/sonar-server/src/main/resources/org/sonar/server/platform/ws/example-index.json b/server/sonar-server/src/main/resources/org/sonar/server/platform/ws/example-index.json deleted file mode 100644 index 24651183e08..00000000000 --- a/server/sonar-server/src/main/resources/org/sonar/server/platform/ws/example-index.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "20140507170538", - "version": "4.3", - "status": "UP" -} diff --git a/server/sonar-server/src/main/resources/org/sonar/server/platform/ws/example-server-version.txt b/server/sonar-server/src/main/resources/org/sonar/server/platform/ws/example-server-version.txt new file mode 100644 index 00000000000..67eadace32b --- /dev/null +++ b/server/sonar-server/src/main/resources/org/sonar/server/platform/ws/example-server-version.txt @@ -0,0 +1 @@ +6.3.0.1234 diff --git a/server/sonar-server/src/main/resources/org/sonar/server/platform/ws/example-setup.json b/server/sonar-server/src/main/resources/org/sonar/server/platform/ws/example-setup.json deleted file mode 100644 index e941957681a..00000000000 --- a/server/sonar-server/src/main/resources/org/sonar/server/platform/ws/example-setup.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "status": "ok", - "migration_status": "NO_MIGRATION", - "message": "Database is up-to-date, no migration needed." -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/authentication/JwtCsrfVerifierTest.java b/server/sonar-server/src/test/java/org/sonar/server/authentication/JwtCsrfVerifierTest.java index d3044aa6375..61babbeab1c 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/authentication/JwtCsrfVerifierTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/authentication/JwtCsrfVerifierTest.java @@ -156,7 +156,6 @@ public class JwtCsrfVerifierTest { executeVerifyStateDoesNotFailOnRequest("/api/issues/bulk_change?key=ABCD", "POST"); executeVerifyStateDoesNotFailOnRequest("/api/projects/create?key=ABCD", "POST"); executeVerifyStateDoesNotFailOnRequest("/api/properties/create?key=ABCD", "POST"); - executeVerifyStateDoesNotFailOnRequest("/api/server", "POST"); executeVerifyStateDoesNotFailOnRequest("/api/user_properties", "POST"); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/authentication/UserSessionInitializerTest.java b/server/sonar-server/src/test/java/org/sonar/server/authentication/UserSessionInitializerTest.java index 30857db4154..75097985af9 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/authentication/UserSessionInitializerTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/authentication/UserSessionInitializerTest.java @@ -107,8 +107,6 @@ public class UserSessionInitializerTest { assertPathIsIgnored("/api/system/db_migration_status"); assertPathIsIgnored("/api/system/status"); assertPathIsIgnored("/api/system/migrate_db"); - assertPathIsIgnored("/api/server/index"); - assertPathIsIgnored("/api/server/setup"); assertPathIsIgnored("/api/server/version"); assertPathIsIgnored("/api/users/identity_providers"); assertPathIsIgnored("/api/l10n/index"); diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/ws/ServerWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/ServerWsTest.java index 77c2e9ed6fc..29ca6ee1b7f 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/ws/ServerWsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/ServerWsTest.java @@ -20,45 +20,40 @@ package org.sonar.server.platform.ws; import org.junit.Test; -import org.sonar.api.server.ws.RailsHandler; +import org.sonar.api.platform.Server; import org.sonar.api.server.ws.WebService; import org.sonar.server.ws.WsTester; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class ServerWsTest { - WsTester tester = new WsTester(new ServerWs()); + private Server server = mock(Server.class); + private WsTester tester = new WsTester(new ServerWs(server)); @Test - public void define_controller() { + public void define_version_action() { WebService.Controller controller = tester.controller("api/server"); - assertThat(controller).isNotNull(); - assertThat(controller.since()).isEqualTo("2.10"); - assertThat(controller.description()).isNotEmpty(); - assertThat(controller.actions()).hasSize(2); + assertThat(controller.actions()).hasSize(1); + + WebService.Action versionAction = controller.action("version"); + assertThat(versionAction.since()).isEqualTo("2.10"); + assertThat(versionAction.description()).isNotEmpty(); + assertThat(versionAction.isPost()).isFalse(); } @Test - public void define_index_action() { - WebService.Controller controller = tester.controller("api/server"); - - WebService.Action action = controller.action("index"); - assertThat(action).isNotNull(); - assertThat(action.handler()).isInstanceOf(RailsHandler.class); - assertThat(action.responseExampleAsString()).isNotEmpty(); - assertThat(action.params()).hasSize(1); + public void returns_version_as_plain_text() throws Exception { + when(server.getVersion()).thenReturn("6.4-SNAPSHOT"); + WsTester.Result result = tester.newGetRequest("api/server", "version").execute(); + assertThat(result.outputAsString()).isEqualTo("6.4-SNAPSHOT"); } @Test - public void define_setup_action() { - WebService.Controller controller = tester.controller("api/server"); - - WebService.Action action = controller.action("setup"); - assertThat(action).isNotNull(); - assertThat(action.handler()).isInstanceOf(RailsHandler.class); - assertThat(action.responseExampleAsString()).isNotEmpty(); - assertThat(action.params()).hasSize(1); + public void test_example_of_version() throws Exception { + WebService.Action versionAction = tester.action("api/server", "version"); + assertThat(versionAction.responseExampleAsString()).isEqualTo("6.3.0.1234"); } - } diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api/server_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api/server_controller.rb deleted file mode 100644 index d1b89828235..00000000000 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api/server_controller.rb +++ /dev/null @@ -1,119 +0,0 @@ -# -# SonarQube, open source software quality management tool. -# Copyright (C) 2008-2016 SonarSource -# mailto:contact AT sonarsource DOT com -# -# SonarQube 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. -# -# SonarQube 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 this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -class Api::ServerController < Api::ApiController - - skip_before_filter :check_authentication - - # prevent HTTP proxies from caching server status - before_filter :set_cache_buster, :only => 'index' - - # execute database setup - skip_before_filter :check_database_version, :setup - - def version - render :text => Java::OrgSonarServerPlatform::Platform.getServer().getVersion() - end - - def index - hash={:id => Java::OrgSonarServerPlatform::Platform.getServer().getId(), :version => Java::OrgSonarServerPlatform::Platform.getServer().getVersion()} - complete_with_status(hash) - respond_to do |format| - format.json{ render :json => jsonp(hash) } - format.xml { render :xml => hash.to_xml(:skip_types => true, :root => 'server') } - format.text { render :text => text_not_supported} - end - end - - def setup - verify_post_request - manager=DatabaseMigrationManager.instance - begin - # 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) - manager.start_migration - - operational=manager.is_sonar_access_allowed? - current_status = operational ? "ok" : "ko" - hash={ - # deprecated fields - :status => current_status, - :migration_status => manager.status, - - # correct fields - :operational => operational, - :state => manager.status - } - hash[:message]=manager.message if manager.message - hash[:startedAt]=manager.migration_start_time if manager.migration_start_time - - respond_to do |format| - format.json{ render :json => jsonp(hash) } - format.xml { render :xml => hash.to_xml(:skip_types => true, :root => 'setup') } - format.text { render :text => hash[:status] } - end - rescue => e - hash={ - # deprecated fields - :status => 'ko', - :msg => e.message, - - # correct fields - :message => e.message, - :state => manager.status - } - respond_to do |format| - format.json{ render :json => jsonp(hash) } - format.xml { render :xml => hash.to_xml(:skip_types => true, :root => 'setup') } - format.text { render :text => hash[:status] } - end - end - end - - private - - def server_properties_to_json(properties) - hash={} - properties.each do |prop| - hash[prop[0].to_s]=prop[1].to_s - end - hash - end - - def complete_with_status(hash) - if DatabaseMigrationManager.instance.is_sonar_access_allowed? - hash[:status]='UP' - elsif DatabaseMigrationManager.instance.migration_running? - hash[:status]='MIGRATION_RUNNING' - elsif DatabaseMigrationManager.instance.requires_migration? - hash[:status]='SETUP' - else - # migration failed or not connected to the database - hash[:status]='DOWN' - hash[:status_msg]=DatabaseMigrationManager.instance.message - end - end - - def set_cache_buster - response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate" - response.headers["Pragma"] = "no-cache" - response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT" - end -end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/models/database_migration_manager.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/models/database_migration_manager.rb deleted file mode 100644 index 139da4a8ca2..00000000000 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/models/database_migration_manager.rb +++ /dev/null @@ -1,122 +0,0 @@ -# -# SonarQube, open source software quality management tool. -# Copyright (C) 2008-2016 SonarSource -# mailto:contact AT sonarsource DOT com -# -# SonarQube 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. -# -# SonarQube 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 this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# - -# -# Class that 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 !ActiveRecord::Base.connected? - @status = MIGRATION_FAILED - @message = "Not connected to database." - elsif 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://redirect.sonarsource.com/doc/requirements.html\">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 is_sonar_access_allowed? - @status==NO_MIGRATION || @status==MIGRATION_SUCCEEDED - 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 - requires_migration = false - Thread.exclusive do - requires_migration = requires_migration? - end - - if requires_migration - Thread.new do - begin - @status = MIGRATION_RUNNING - @message = "Database migration is running" - Thread.current[:name] = "Database Upgrade" - @start_time = Time.now - - DatabaseVersion.upgrade_and_start - - @status = MIGRATION_SUCCEEDED - @message = "Migration succeeded." - rescue Exception => e - @status = MIGRATION_FAILED - @message = "Migration failed: " + Api::Utils.exception_message(e) + ".<br/> Please check logs." - Api::Utils.java_facade.logError("Fail to upgrade database\n#{Api::Utils.exception_message(e, :backtrace => true)}") - end - end - end - end - -end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/config/routes.rb b/server/sonar-web/src/main/webapp/WEB-INF/config/routes.rb index 2931db12590..e51f89c25d8 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/config/routes.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/config/routes.rb @@ -8,7 +8,6 @@ ActionController::Routing::Routes.draw do |map| map.connect 'api', :controller => 'api/java_ws', :action => 'redirect_to_ws_listing' - map.connect 'api/server/:action', :controller => 'api/server' map.connect 'api/resoures', :controller => 'api/resources', :action => 'index' map.resources 'properties', :path_prefix => 'api', :controller => 'api/properties', :requirements => { :id => /.*/ } |