Sfoglia il codice sorgente

SONAR-15688 add prometheus web API endpoint

tags/9.3.0.51899
Pierre 2 anni fa
parent
commit
05f25e35b7
22 ha cambiato i file con 774 aggiunte e 3 eliminazioni
  1. 2
    0
      build.gradle
  2. 2
    1
      server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/UserSessionInitializer.java
  3. 53
    0
      server/sonar-webserver-auth/src/main/java/org/sonar/server/user/BearerPasscode.java
  4. 1
    0
      server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/UserSessionInitializerTest.java
  5. 71
    0
      server/sonar-webserver-auth/src/test/java/org/sonar/server/user/BearerPasscodeTest.java
  6. 4
    0
      server/sonar-webserver-webapi/build.gradle
  7. 55
    0
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/monitoring/MetricsAction.java
  8. 43
    0
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/monitoring/MonitoringWs.java
  9. 26
    0
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/monitoring/MonitoringWsAction.java
  10. 38
    0
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/monitoring/MonitoringWsModule.java
  11. 80
    0
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/SafeModeMonitoringMetricAction.java
  12. 8
    0
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/SafemodeSystemWsModule.java
  13. 3
    0
      server/sonar-webserver-webapi/src/main/resources/org/sonar/server/monitoring/monitoring-metrics.txt
  14. 118
    0
      server/sonar-webserver-webapi/src/test/java/org/sonar/server/monitoring/MetricsActionTest.java
  15. 36
    0
      server/sonar-webserver-webapi/src/test/java/org/sonar/server/monitoring/MonitoringWsModuleTest.java
  16. 56
    0
      server/sonar-webserver-webapi/src/test/java/org/sonar/server/monitoring/MonitoringWsTest.java
  17. 106
    0
      server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/SafeModeMonitoringMetricActionTest.java
  18. 1
    2
      server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/SafemodeSystemWsModuleTest.java
  19. 2
    0
      server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
  20. 8
    0
      sonar-ws/src/main/java/org/sonarqube/ws/client/DefaultWsClient.java
  21. 3
    0
      sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java
  22. 58
    0
      sonar-ws/src/main/java/org/sonarqube/ws/client/monitoring/MonitoringService.java

+ 2
- 0
build.gradle Vedi File

@@ -344,6 +344,8 @@ subprojects {
}
dependency 'com.auth0:java-jwt:3.18.2'
dependency 'io.netty:netty-all:4.1.70.Final'
dependency 'io.prometheus:simpleclient_common:0.12.0'
dependency 'io.prometheus:simpleclient_servlet:0.12.0'
dependency 'com.sun.mail:javax.mail:1.5.6'
dependency 'javax.annotation:javax.annotation-api:1.3.2'
dependency 'javax.servlet:javax.servlet-api:3.1.0'

+ 2
- 1
server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/UserSessionInitializer.java Vedi File

@@ -63,7 +63,8 @@ public class UserSessionInitializer {
"/api/ce/info", "/api/ce/pause",
"/api/ce/resume", "/api/system/health",
"/api/system/analytics", "/api/system/migrate_es",
"/api/system/liveness");
"/api/system/liveness",
"/api/monitoring/metrics");

private static final UrlPattern URL_PATTERN = UrlPattern.builder()
.includes("/*")

+ 53
- 0
server/sonar-webserver-auth/src/main/java/org/sonar/server/user/BearerPasscode.java Vedi File

@@ -0,0 +1,53 @@
/*
* SonarQube
* Copyright (C) 2009-2021 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program 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.
*
* This program 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.
*/
package org.sonar.server.user;

import java.util.Optional;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.config.Configuration;
import org.sonar.api.server.ws.Request;

import static org.sonar.process.ProcessProperties.Property.WEB_SYSTEM_PASS_CODE;

public class BearerPasscode {

public static final String PASSCODE_HTTP_HEADER = "Authorization";

private final Configuration configuration;

public BearerPasscode(Configuration configuration) {
this.configuration = configuration;
}

public boolean isValid(Request request) {
Optional<String> passcodeOpt = configuration.get(WEB_SYSTEM_PASS_CODE.getKey()).map(StringUtils::trimToNull);

if (passcodeOpt.isEmpty()) {
return false;
}

String configuredPasscode = passcodeOpt.get();
return request.header(PASSCODE_HTTP_HEADER)
.map(s -> s.replace("Bearer ", ""))
.map(configuredPasscode::equals)
.orElse(false);
}

}

+ 1
- 0
server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/UserSessionInitializerTest.java Vedi File

@@ -104,6 +104,7 @@ public class UserSessionInitializerTest {
assertPathIsIgnoredWithAnonymousAccess("/api/ce/resume");
assertPathIsIgnoredWithAnonymousAccess("/api/system/health");
assertPathIsIgnoredWithAnonymousAccess("/api/system/liveness");
assertPathIsIgnoredWithAnonymousAccess("/api/monitoring/metrics");

// exclude static resources
assertPathIsIgnored("/css/style.css");

+ 71
- 0
server/sonar-webserver-auth/src/test/java/org/sonar/server/user/BearerPasscodeTest.java Vedi File

@@ -0,0 +1,71 @@
/*
* SonarQube
* Copyright (C) 2009-2021 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program 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.
*
* This program 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.
*/
package org.sonar.server.user;

import org.junit.Test;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.impl.ws.SimpleGetRequest;

import static org.assertj.core.api.Assertions.assertThat;

public class BearerPasscodeTest {

private final MapSettings settings = new MapSettings();
private final BearerPasscode underTest = new BearerPasscode(settings.asConfig());

@Test
public void isValid_is_true_if_request_header_matches_configured_passcode() {
verifyIsValid(true, "foo", "foo");
}

@Test
public void isValid_is_false_if_request_header_matches_configured_passcode_with_different_case() {
verifyIsValid(false, "foo", "FOO");
}

@Test
public void isValid_is_false_if_request_header_does_not_match_configured_passcode() {
verifyIsValid(false, "foo", "bar");
}

@Test
public void isValid_is_false_if_request_header_is_defined_but_passcode_is_not_configured() {
verifyIsValid(false, null, "foo");
}

@Test
public void isValid_is_false_if_request_header_is_empty() {
verifyIsValid(false, "foo", "");
}

private void verifyIsValid(boolean expectedResult, String configuredPasscode, String token) {
configurePasscode(configuredPasscode);

SimpleGetRequest request = new SimpleGetRequest();
request.setHeader("Authorization", "Bearer " + token);

assertThat(underTest.isValid(request)).isEqualTo(expectedResult);
}

private void configurePasscode(String propertyValue) {
settings.setProperty("sonar.web.systemPasscode", propertyValue);
}

}

+ 4
- 0
server/sonar-webserver-webapi/build.gradle Vedi File

@@ -9,6 +9,10 @@ dependencies {

compile 'com.google.guava:guava'
compile 'com.github.everit-org.json-schema:org.everit.json.schema'

compile 'io.prometheus:simpleclient_common'
compile 'io.prometheus:simpleclient_servlet'

compile project(':server:sonar-ce-common')
compile project(':server:sonar-ce-task')
compile project(':server:sonar-db-dao')

+ 55
- 0
server/sonar-webserver-webapi/src/main/java/org/sonar/server/monitoring/MetricsAction.java Vedi File

@@ -0,0 +1,55 @@
/*
* SonarQube
* Copyright (C) 2009-2021 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program 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.
*
* This program 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.
*/
package org.sonar.server.monitoring;

import org.sonar.api.server.ws.WebService;
import org.sonar.server.platform.ws.SafeModeMonitoringMetricAction;
import org.sonar.server.user.BearerPasscode;
import org.sonar.server.user.SystemPasscode;
import org.sonar.server.user.UserSession;

public class MetricsAction extends SafeModeMonitoringMetricAction {

private final UserSession userSession;

public MetricsAction(SystemPasscode systemPasscode, BearerPasscode bearerPasscode, UserSession userSession) {
super(systemPasscode, bearerPasscode);
this.userSession = userSession;
}

@Override
public void define(WebService.NewController context) {
context.createAction("metrics")
.setSince("9.3")
.setDescription("Return monitoring metrics in Prometheus format. \n" +
"Support content type 'text/plain' (default) and 'application/openmetrics-text'.\n" +
"this endpoint can be access using a Bearer token, that needs to be defined in sonar.properties with the 'sonar.web.systemPasscode' key.")
.setResponseExample(getClass().getResource("monitoring-metrics.txt"))
.setHandler(this);

isWebUpGauge.set(0D);
}

@Override
public boolean isSystemAdmin() {
return userSession.isSystemAdministrator();
}

}

+ 43
- 0
server/sonar-webserver-webapi/src/main/java/org/sonar/server/monitoring/MonitoringWs.java Vedi File

@@ -0,0 +1,43 @@
/*
* SonarQube
* Copyright (C) 2009-2021 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program 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.
*
* This program 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.
*/
package org.sonar.server.monitoring;

import org.sonar.api.server.ws.WebService;

public class MonitoringWs implements WebService {
private final MonitoringWsAction[] actions;

public MonitoringWs(MonitoringWsAction... actions) {
this.actions = actions;
}

@Override
public void define(Context context) {
NewController controller = context.createController("api/monitoring")
.setDescription("Monitoring")
.setSince("9.3");

for (MonitoringWsAction action : actions) {
action.define(controller);
}

controller.done();
}
}

+ 26
- 0
server/sonar-webserver-webapi/src/main/java/org/sonar/server/monitoring/MonitoringWsAction.java Vedi File

@@ -0,0 +1,26 @@
/*
* SonarQube
* Copyright (C) 2009-2021 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program 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.
*
* This program 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.
*/
package org.sonar.server.monitoring;

import org.sonar.server.ws.WsAction;

public interface MonitoringWsAction extends WsAction {

}

+ 38
- 0
server/sonar-webserver-webapi/src/main/java/org/sonar/server/monitoring/MonitoringWsModule.java Vedi File

@@ -0,0 +1,38 @@
/*
* SonarQube
* Copyright (C) 2009-2021 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program 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.
*
* This program 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.
*/
package org.sonar.server.monitoring;

import org.sonar.core.platform.Module;
import org.sonar.server.user.BearerPasscode;

public class MonitoringWsModule extends Module {

public MonitoringWsModule() {
// nothing to do
}

@Override
protected void configureModule() {
add(
BearerPasscode.class,
MonitoringWs.class,
MetricsAction.class);
}
}

+ 80
- 0
server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/SafeModeMonitoringMetricAction.java Vedi File

@@ -0,0 +1,80 @@
/*
* SonarQube
* Copyright (C) 2009-2021 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program 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.
*
* This program 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.
*/
package org.sonar.server.platform.ws;

import com.google.common.net.HttpHeaders;
import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.Gauge;
import io.prometheus.client.exporter.common.TextFormat;
import java.io.OutputStreamWriter;
import java.io.Writer;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.monitoring.MonitoringWsAction;
import org.sonar.server.user.BearerPasscode;
import org.sonar.server.user.SystemPasscode;

import static java.nio.charset.StandardCharsets.UTF_8;

public class SafeModeMonitoringMetricAction implements MonitoringWsAction {

protected static final Gauge isWebUpGauge = Gauge.build().name("is_web_up").help("Tells whether web service is up").register();

private final SystemPasscode systemPasscode;
private final BearerPasscode bearerPasscode;

public SafeModeMonitoringMetricAction(SystemPasscode systemPasscode, BearerPasscode bearerPasscode) {
this.systemPasscode = systemPasscode;
this.bearerPasscode = bearerPasscode;
}

@Override
public void define(WebService.NewController context) {
context.createAction("metrics").setHandler(this);
isWebUpGauge.set(0D);
}

@Override
public void handle(Request request, Response response) throws Exception {

if (!systemPasscode.isValid(request) && !isSystemAdmin() && !bearerPasscode.isValid(request)) {
throw new ForbiddenException("Insufficient privileges");
}

String requestContentType = request.getHeaders().get("accept");
String contentType = TextFormat.chooseContentType(requestContentType);

response.setHeader(HttpHeaders.CONTENT_TYPE, contentType);
response.stream().setStatus(200);

try (Writer writer = new OutputStreamWriter(response.stream().output(), UTF_8)) {
TextFormat.writeFormat(contentType, writer, CollectorRegistry.defaultRegistry.metricFamilySamples());
writer.flush();
}
}

public boolean isSystemAdmin() {
// No authenticated user in safe mode
return false;
}

}

+ 8
- 0
server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/SafemodeSystemWsModule.java Vedi File

@@ -20,6 +20,8 @@
package org.sonar.server.platform.ws;

import org.sonar.core.platform.Module;
import org.sonar.server.monitoring.MonitoringWs;
import org.sonar.server.user.BearerPasscode;

public class SafemodeSystemWsModule extends Module {
@Override
@@ -28,11 +30,17 @@ public class SafemodeSystemWsModule extends Module {
StatusAction.class,
MigrateDbAction.class,
DbMigrationStatusAction.class,

HealthActionSupport.class,
SafeModeHealthAction.class,
SafeModeLivenessCheckerImpl.class,
LivenessActionSupport.class,
SafeModeLivenessAction.class,

MonitoringWs.class,
BearerPasscode.class,
SafeModeMonitoringMetricAction.class,

SystemWs.class);
}
}

+ 3
- 0
server/sonar-webserver-webapi/src/main/resources/org/sonar/server/monitoring/monitoring-metrics.txt Vedi File

@@ -0,0 +1,3 @@
# HELP is_web_up Tells whether web service is up
# TYPE is_web_up gauge
is_web_up 0.0

+ 118
- 0
server/sonar-webserver-webapi/src/test/java/org/sonar/server/monitoring/MetricsActionTest.java Vedi File

@@ -0,0 +1,118 @@
/*
* SonarQube
* Copyright (C) 2009-2021 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program 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.
*
* This program 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.
*/
package org.sonar.server.monitoring;

import org.assertj.core.api.Assertions;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.server.ws.WebService;
import org.sonar.db.DbTester;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.user.BearerPasscode;
import org.sonar.server.user.SystemPasscode;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.TestResponse;
import org.sonar.server.ws.WsActionTester;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.server.tester.UserSessionRule.standalone;

public class MetricsActionTest {

@Rule
public UserSessionRule userSession = standalone();

@Rule
public DbTester db = DbTester.create();

private final BearerPasscode bearerPasscode = mock(BearerPasscode.class);
private final SystemPasscode systemPasscode = mock(SystemPasscode.class);

private final MetricsAction underTest = new MetricsAction(systemPasscode, bearerPasscode, userSession);
private final WsActionTester ws = new WsActionTester(underTest);

@Test
public void test_definition() {
WebService.Action definition = ws.getDef();
assertThat(definition.isInternal()).isFalse();
assertThat(definition.isPost()).isFalse();
assertThat(definition.responseExampleAsString()).isNotEmpty();
assertThat(definition.params()).isEmpty();
}

@Test
public void no_authentication_throw_insufficient_privileges_error() {
TestRequest request = ws.newRequest();
Assertions.assertThatThrownBy(request::execute)
.hasMessage("Insufficient privileges")
.isInstanceOf(ForbiddenException.class);
}

@Test
public void authenticated_non_global_admin_is_forbidden() {
userSession.logIn();

TestRequest testRequest = ws.newRequest();
Assertions.assertThatThrownBy(testRequest::execute)
.hasMessage("Insufficient privileges")
.isInstanceOf(ForbiddenException.class);
}

@Test
public void authentication_passcode_is_allowed() {
when(systemPasscode.isValid(any())).thenReturn(true);

TestResponse response = ws.newRequest().execute();
String content = response.getInput();
assertThat(content)
.contains("# HELP is_web_up Tells whether web service is up")
.contains("# TYPE is_web_up gauge")
.contains("is_web_up 0.0");
}

@Test
public void authentication_bearer_passcode_is_allowed() {
when(bearerPasscode.isValid(any())).thenReturn(true);

TestResponse response = ws.newRequest().execute();
String content = response.getInput();
assertThat(content)
.contains("# HELP is_web_up Tells whether web service is up")
.contains("# TYPE is_web_up gauge")
.contains("is_web_up 0.0");
}

@Test
public void authenticated_global_admin_is_allowed() {
userSession.logIn().setSystemAdministrator();

TestResponse response = ws.newRequest().execute();
String content = response.getInput();
assertThat(content)
.contains("# HELP is_web_up Tells whether web service is up")
.contains("# TYPE is_web_up gauge")
.contains("is_web_up 0.0");
}

}

+ 36
- 0
server/sonar-webserver-webapi/src/test/java/org/sonar/server/monitoring/MonitoringWsModuleTest.java Vedi File

@@ -0,0 +1,36 @@
/*
* SonarQube
* Copyright (C) 2009-2021 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program 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.
*
* This program 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.
*/
package org.sonar.server.monitoring;

import org.junit.Test;
import org.sonar.core.platform.ComponentContainer;

import static org.assertj.core.api.Assertions.assertThat;

public class MonitoringWsModuleTest {

@Test
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new MonitoringWsModule().configure(container);
assertThat(container.size()).isPositive();
}

}

+ 56
- 0
server/sonar-webserver-webapi/src/test/java/org/sonar/server/monitoring/MonitoringWsTest.java Vedi File

@@ -0,0 +1,56 @@
/*
* SonarQube
* Copyright (C) 2009-2021 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program 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.
*
* This program 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.
*/
package org.sonar.server.monitoring;

import org.junit.Test;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;

import static org.assertj.core.api.Assertions.assertThat;

public class MonitoringWsTest {

private final MonitoringWs underTest = new MonitoringWs(new MonitoringWsAction() {
@Override
public void handle(Request request, Response response) {
// nothing to do
}

@Override
public void define(WebService.NewController context) {
context.createAction("foo").setHandler(this);
}
});

@Test
public void define_controller() {
WebService.Context context = new WebService.Context();

underTest.define(context);

WebService.Controller controller = context.controller("api/monitoring");
assertThat(controller).isNotNull();
assertThat(controller.description()).isNotEmpty();
assertThat(controller.since()).isEqualTo("9.3");
assertThat(controller.actions()).hasSize(1);
}

}

+ 106
- 0
server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/SafeModeMonitoringMetricActionTest.java Vedi File

@@ -0,0 +1,106 @@
/*
* SonarQube
* Copyright (C) 2009-2021 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program 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.
*
* This program 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.
*/
package org.sonar.server.platform.ws;

import org.assertj.core.api.Assertions;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.db.DbTester;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.user.BearerPasscode;
import org.sonar.server.user.SystemPasscode;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.TestResponse;
import org.sonar.server.ws.WsActionTester;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.server.tester.UserSessionRule.standalone;

public class SafeModeMonitoringMetricActionTest {

@Rule
public UserSessionRule userSession = standalone();

@Rule
public DbTester db = DbTester.create();

private final BearerPasscode bearerPasscode = mock(BearerPasscode.class);
private final SystemPasscode systemPasscode = mock(SystemPasscode.class);

private final SafeModeMonitoringMetricAction safeModeMonitoringMetricAction = new SafeModeMonitoringMetricAction(systemPasscode, bearerPasscode);
private final WsActionTester ws = new WsActionTester(safeModeMonitoringMetricAction);

@Test
public void no_authentication_throw_insufficient_privileges_error() {
TestRequest request = ws.newRequest();
Assertions.assertThatThrownBy(request::execute)
.hasMessage("Insufficient privileges")
.isInstanceOf(ForbiddenException.class);
}

@Test
public void authenticated_non_global_admin_is_forbidden() {
userSession.logIn();

TestRequest testRequest = ws.newRequest();
Assertions.assertThatThrownBy(testRequest::execute)
.hasMessage("Insufficient privileges")
.isInstanceOf(ForbiddenException.class);
}

@Test
public void authentication_passcode_is_allowed() {
when(systemPasscode.isValid(any())).thenReturn(true);

TestResponse response = ws.newRequest().execute();
String content = response.getInput();
assertThat(content)
.contains("# HELP is_web_up Tells whether web service is up")
.contains("# TYPE is_web_up gauge")
.contains("is_web_up 0.0");
}

@Test
public void authentication_bearer_passcode_is_allowed() {
when(bearerPasscode.isValid(any())).thenReturn(true);

TestResponse response = ws.newRequest().execute();
String content = response.getInput();
assertThat(content)
.contains("# HELP is_web_up Tells whether web service is up")
.contains("# TYPE is_web_up gauge")
.contains("is_web_up 0.0");
}

@Test
public void authenticated_global_admin_is_not_allowed_in_safe_mode() {
userSession.logIn().setSystemAdministrator();

TestRequest testRequest = ws.newRequest();
Assertions.assertThatThrownBy(testRequest::execute)
.hasMessage("Insufficient privileges")
.isInstanceOf(ForbiddenException.class);
}

}

+ 1
- 2
server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/SafemodeSystemWsModuleTest.java Vedi File

@@ -23,14 +23,13 @@ import org.junit.Test;
import org.sonar.core.platform.ComponentContainer;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;

public class SafemodeSystemWsModuleTest {
@Test
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new SafemodeSystemWsModule().configure(container);
assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 9);
assertThat(container.size()).isPositive();
}

}

+ 2
- 0
server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java Vedi File

@@ -121,6 +121,7 @@ import org.sonar.server.measure.ws.MeasuresWsModule;
import org.sonar.server.metric.MetricFinder;
import org.sonar.server.metric.UnanalyzedLanguageMetrics;
import org.sonar.server.metric.ws.MetricsWsModule;
import org.sonar.server.monitoring.MonitoringWsModule;
import org.sonar.server.newcodeperiod.ws.NewCodePeriodsWsModule;
import org.sonar.server.notification.NotificationModule;
import org.sonar.server.notification.ws.NotificationWsModule;
@@ -268,6 +269,7 @@ public class PlatformLevel4 extends PlatformLevel {
ServerWs.class,
IndexDefinitions.class,
WebAnalyticsLoaderImpl.class,
MonitoringWsModule.class,

// batch
BatchWsModule.class,

+ 8
- 0
sonar-ws/src/main/java/org/sonarqube/ws/client/DefaultWsClient.java Vedi File

@@ -40,6 +40,7 @@ import org.sonarqube.ws.client.l10n.L10nService;
import org.sonarqube.ws.client.languages.LanguagesService;
import org.sonarqube.ws.client.measures.MeasuresService;
import org.sonarqube.ws.client.metrics.MetricsService;
import org.sonarqube.ws.client.monitoring.MonitoringService;
import org.sonarqube.ws.client.navigation.NavigationService;
import org.sonarqube.ws.client.newcodeperiods.NewCodePeriodsService;
import org.sonarqube.ws.client.notifications.NotificationsService;
@@ -104,6 +105,7 @@ class DefaultWsClient implements WsClient {
private final LanguagesService languagesService;
private final MeasuresService measuresService;
private final MetricsService metricsService;
private final MonitoringService monitoringService;
private final NavigationService navigationService;
private final NewCodePeriodsService newCodePeriodsService;
private final NotificationsService notificationsService;
@@ -161,6 +163,7 @@ class DefaultWsClient implements WsClient {
this.languagesService = new LanguagesService(wsConnector);
this.measuresService = new MeasuresService(wsConnector);
this.metricsService = new MetricsService(wsConnector);
this.monitoringService = new MonitoringService(wsConnector);
this.navigationService = new NavigationService(wsConnector);
this.newCodePeriodsService = new NewCodePeriodsService(wsConnector);
this.notificationsService = new NotificationsService(wsConnector);
@@ -298,6 +301,11 @@ class DefaultWsClient implements WsClient {
return metricsService;
}

@Override
public MonitoringService monitoring() {
return monitoringService;
}

@Override
public NavigationService navigation() {
return navigationService;

+ 3
- 0
sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java Vedi File

@@ -40,6 +40,7 @@ import org.sonarqube.ws.client.l10n.L10nService;
import org.sonarqube.ws.client.languages.LanguagesService;
import org.sonarqube.ws.client.measures.MeasuresService;
import org.sonarqube.ws.client.metrics.MetricsService;
import org.sonarqube.ws.client.monitoring.MonitoringService;
import org.sonarqube.ws.client.navigation.NavigationService;
import org.sonarqube.ws.client.newcodeperiods.NewCodePeriodsService;
import org.sonarqube.ws.client.notifications.NotificationsService;
@@ -202,4 +203,6 @@ public interface WsClient {
BatchService batch();

SecurityReportsService securityReports();

MonitoringService monitoring();
}

+ 58
- 0
sonar-ws/src/main/java/org/sonarqube/ws/client/monitoring/MonitoringService.java Vedi File

@@ -0,0 +1,58 @@
/*
* SonarQube
* Copyright (C) 2009-2021 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program 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.
*
* This program 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.
*/
package org.sonarqube.ws.client.monitoring;

import javax.annotation.Generated;
import org.sonarqube.ws.client.BaseService;
import org.sonarqube.ws.client.GetRequest;
import org.sonarqube.ws.client.WsConnector;

/**
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/monitoring">Further information about this web service online</a>
*/
@Generated("sonar-ws-generator")
public class MonitoringService extends BaseService {

private String bearerToken;

public MonitoringService(WsConnector wsConnector) {
super(wsConnector, "api/monitoring");
}

/**
*
* This is a GET request.
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/monitoring/metrics">Further information about this action online (including a response example)</a>
* @since 9.3
* @return
*/
public String metrics(String mediaType) {
GetRequest request = new GetRequest(path("metrics")).setMediaType(mediaType);
if (bearerToken != null && !bearerToken.isEmpty()) {
request.setHeader("Authorization", "Bearer " + bearerToken);
}
return call(request).content();
}

public MonitoringService withBearerToken(String bearerToken) {
this.bearerToken = bearerToken;
return this;
}
}

Loading…
Annulla
Salva