From baa5c72513957ca1600d10f2508378239c52bf29 Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Wed, 18 Apr 2018 18:26:08 +0200 Subject: [PATCH] SONAR-10592 add WS api/ce/pause and api/ce/resume --- .../org/sonar/server/ce/ws/CeWsModule.java | 3 +- .../org/sonar/server/ce/ws/PauseAction.java | 61 ++++++++++++ .../org/sonar/server/ce/ws/ResumeAction.java | 61 ++++++++++++ .../sonar/server/ce/ws/CeWsModuleTest.java | 2 +- .../sonar/server/ce/ws/PauseActionTest.java | 99 +++++++++++++++++++ .../sonar/server/ce/ws/ResumeActionTest.java | 99 +++++++++++++++++++ .../org/sonarqube/ws/client/ce/CeService.java | 25 +++++ 7 files changed, 348 insertions(+), 2 deletions(-) create mode 100644 server/sonar-server/src/main/java/org/sonar/server/ce/ws/PauseAction.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/ce/ws/ResumeAction.java create mode 100644 server/sonar-server/src/test/java/org/sonar/server/ce/ws/PauseActionTest.java create mode 100644 server/sonar-server/src/test/java/org/sonar/server/ce/ws/ResumeActionTest.java diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/CeWsModule.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/CeWsModule.java index c83157dc1dd..ac415b72a75 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/CeWsModule.java +++ b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/CeWsModule.java @@ -33,7 +33,8 @@ public class CeWsModule extends Module { ComponentAction.class, InfoAction.class, IsQueueEmptyWs.class, - ComponentAction.class, + PauseAction.class, + ResumeAction.class, SubmitAction.class, TaskFormatter.class, TaskAction.class, diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/PauseAction.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/PauseAction.java new file mode 100644 index 00000000000..e725b817715 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/PauseAction.java @@ -0,0 +1,61 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.ce.ws; + +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.Response; +import org.sonar.api.server.ws.WebService; +import org.sonar.ce.queue.CeQueue; +import org.sonar.server.user.AbstractUserSession; +import org.sonar.server.user.SystemPasscode; +import org.sonar.server.user.SystemPasscodeImpl; +import org.sonar.server.user.UserSession; + +public class PauseAction implements CeWsAction { + + private final UserSession userSession; + private final SystemPasscode systemPasscode; + private final CeQueue ceQueue; + + public PauseAction(UserSession userSession, SystemPasscode systemPasscode, CeQueue ceQueue) { + this.userSession = userSession; + this.systemPasscode = systemPasscode; + this.ceQueue = ceQueue; + } + + @Override + public void define(WebService.NewController controller) { + controller.createAction("pause") + .setDescription("Requests pause of Compute Engine workers. Requires the system administration permission or " + + "system passcode (see " + SystemPasscodeImpl.PASSCODE_CONF_PROPERTY + " in sonar.properties).") + .setSince("7.2") + .setHandler(this) + .setPost(true); + } + + @Override + public void handle(Request request, Response response) throws Exception { + if (!userSession.isSystemAdministrator() && !systemPasscode.isValid(request)) { + throw AbstractUserSession.insufficientPrivilegesException(); + } + + ceQueue.pauseWorkers(); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ResumeAction.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ResumeAction.java new file mode 100644 index 00000000000..3be2b45e512 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ResumeAction.java @@ -0,0 +1,61 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.ce.ws; + +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.Response; +import org.sonar.api.server.ws.WebService; +import org.sonar.ce.queue.CeQueue; +import org.sonar.server.user.AbstractUserSession; +import org.sonar.server.user.SystemPasscode; +import org.sonar.server.user.SystemPasscodeImpl; +import org.sonar.server.user.UserSession; + +public class ResumeAction implements CeWsAction { + + private final UserSession userSession; + private final SystemPasscode systemPasscode; + private final CeQueue ceQueue; + + public ResumeAction(UserSession userSession, SystemPasscode systemPasscode, CeQueue ceQueue) { + this.userSession = userSession; + this.systemPasscode = systemPasscode; + this.ceQueue = ceQueue; + } + + @Override + public void define(WebService.NewController controller) { + controller.createAction("resume") + .setDescription("Resumes pause of Compute Engine workers. Requires the system administration permission or " + + "system passcode (see " + SystemPasscodeImpl.PASSCODE_CONF_PROPERTY + " in sonar.properties).") + .setSince("7.2") + .setHandler(this) + .setPost(true); + } + + @Override + public void handle(Request request, Response response) throws Exception { + if (!userSession.isSystemAdministrator() && !systemPasscode.isValid(request)) { + throw AbstractUserSession.insufficientPrivilegesException(); + } + + ceQueue.resumeWorkers(); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/CeWsModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/CeWsModuleTest.java index e1d039f9f90..a16e0b554fa 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/CeWsModuleTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/CeWsModuleTest.java @@ -31,6 +31,6 @@ public class CeWsModuleTest { public void verify_count_of_added_components() { ComponentContainer container = new ComponentContainer(); new CeWsModule().configure(container); - assertThat(container.size()).isEqualTo(13 + COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER); + assertThat(container.size()).isEqualTo(15 + COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/PauseActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/PauseActionTest.java new file mode 100644 index 00000000000..f7405267870 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/PauseActionTest.java @@ -0,0 +1,99 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.ce.ws; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.server.ws.WebService; +import org.sonar.ce.queue.CeQueue; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.user.SystemPasscode; +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.verify; +import static org.mockito.Mockito.when; + +public class PauseActionTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + + private SystemPasscode passcode = mock(SystemPasscode.class); + private CeQueue ceQueue = mock(CeQueue.class); + private PauseAction underTest = new PauseAction(userSession, passcode, ceQueue); + private WsActionTester ws = new WsActionTester(underTest); + + @Test + public void test_definition() { + WebService.Action def = ws.getDef(); + assertThat(def.key()).isEqualTo("pause"); + assertThat(def.isInternal()).isFalse(); + assertThat(def.isPost()).isTrue(); + assertThat(def.params()).isEmpty(); + assertThat(def.responseExampleAsString()).isNull(); + } + + @Test + public void pause_workers() { + userSession.logIn().setSystemAdministrator(); + + ws.newRequest().execute(); + + verify(ceQueue).pauseWorkers(); + } + + @Test + public void throw_ForbiddenException_if_not_system_administrator() { + userSession.logIn().setNonSystemAdministrator(); + + expectedException.expect(ForbiddenException.class); + expectedException.expectMessage("Insufficient privileges"); + + ws.newRequest().execute(); + } + + @Test + public void throw_ForbiddenException_if_invalid_passcode() { + userSession.anonymous(); + when(passcode.isValid(any())).thenReturn(false); + + expectedException.expect(ForbiddenException.class); + expectedException.expectMessage("Insufficient privileges"); + + ws.newRequest().execute(); + } + + @Test + public void authenticate_with_passcode() { + userSession.anonymous(); + when(passcode.isValid(any())).thenReturn(true); + + ws.newRequest().execute(); + + verify(ceQueue).pauseWorkers(); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ResumeActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ResumeActionTest.java new file mode 100644 index 00000000000..733b28c043c --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ResumeActionTest.java @@ -0,0 +1,99 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.ce.ws; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.server.ws.WebService; +import org.sonar.ce.queue.CeQueue; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.user.SystemPasscode; +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.verify; +import static org.mockito.Mockito.when; + +public class ResumeActionTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + + private SystemPasscode passcode = mock(SystemPasscode.class); + private CeQueue ceQueue = mock(CeQueue.class); + private ResumeAction underTest = new ResumeAction(userSession, passcode, ceQueue); + private WsActionTester ws = new WsActionTester(underTest); + + @Test + public void test_definition() { + WebService.Action def = ws.getDef(); + assertThat(def.key()).isEqualTo("resume"); + assertThat(def.isInternal()).isFalse(); + assertThat(def.isPost()).isTrue(); + assertThat(def.params()).isEmpty(); + assertThat(def.responseExampleAsString()).isNull(); + } + + @Test + public void resume_workers() { + userSession.logIn().setSystemAdministrator(); + + ws.newRequest().execute(); + + verify(ceQueue).resumeWorkers(); + } + + @Test + public void throw_ForbiddenException_if_not_system_administrator() { + userSession.logIn().setNonSystemAdministrator(); + + expectedException.expect(ForbiddenException.class); + expectedException.expectMessage("Insufficient privileges"); + + ws.newRequest().execute(); + } + + @Test + public void throw_ForbiddenException_if_invalid_passcode() { + userSession.anonymous(); + when(passcode.isValid(any())).thenReturn(false); + + expectedException.expect(ForbiddenException.class); + expectedException.expectMessage("Insufficient privileges"); + + ws.newRequest().execute(); + } + + @Test + public void authenticate_with_passcode() { + userSession.anonymous(); + when(passcode.isValid(any())).thenReturn(true); + + ws.newRequest().execute(); + + verify(ceQueue).resumeWorkers(); + } +} diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/ce/CeService.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/ce/CeService.java index aa49783c8cc..c02981e25f0 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/ce/CeService.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/ce/CeService.java @@ -128,6 +128,7 @@ public class CeService extends BaseService { } /** + * * This is a GET request. * @see Further information about this action online (including a response example) * @since 7.2 @@ -138,6 +139,30 @@ public class CeService extends BaseService { InfoWsResponse.parser()); } + /** + * This is a POST request. + * @see Further information about this action online (including a response example) + * @since 7.2 + */ + public void pause() { + call( + new PostRequest(path("pause")) + .setMediaType(MediaTypes.JSON) + ).content(); + } + + /** + * This is a POST request. + * @see Further information about this action online (including a response example) + * @since 7.2 + */ + public void resume() { + call( + new PostRequest(path("resume")) + .setMediaType(MediaTypes.JSON) + ).content(); + } + /** * * This is part of the internal API. -- 2.39.5