]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10592 add WS api/ce/pause and api/ce/resume
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Wed, 18 Apr 2018 16:26:08 +0000 (18:26 +0200)
committerSonarTech <sonartech@sonarsource.com>
Thu, 10 May 2018 18:20:53 +0000 (20:20 +0200)
server/sonar-server/src/main/java/org/sonar/server/ce/ws/CeWsModule.java
server/sonar-server/src/main/java/org/sonar/server/ce/ws/PauseAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/ce/ws/ResumeAction.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/ce/ws/CeWsModuleTest.java
server/sonar-server/src/test/java/org/sonar/server/ce/ws/PauseActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/ce/ws/ResumeActionTest.java [new file with mode: 0644]
sonar-ws/src/main/java/org/sonarqube/ws/client/ce/CeService.java

index c83157dc1ddf03541cee27c712ed0ab9bc0f84e0..ac415b72a751c97936bc8d7ae9ca1357f33eccdf 100644 (file)
@@ -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 (file)
index 0000000..e725b81
--- /dev/null
@@ -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 (file)
index 0000000..3be2b45
--- /dev/null
@@ -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();
+  }
+}
index e1d039f9f909be9875a8b1adc3849f3d3d5ec06d..a16e0b554fae04a8fdf6c0dacff01702350a7080 100644 (file)
@@ -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 (file)
index 0000000..f740526
--- /dev/null
@@ -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 (file)
index 0000000..733b28c
--- /dev/null
@@ -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();
+  }
+}
index aa49783c8cc1a620efd0f11d01ad8aca1afd7105..c02981e25f011fe64316510450392ed33a7ede5d 100644 (file)
@@ -128,6 +128,7 @@ public class CeService extends BaseService {
   }
 
   /**
+   *
    * This is a GET request.
    * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/ce/info">Further information about this action online (including a response example)</a>
    * @since 7.2
@@ -138,6 +139,30 @@ public class CeService extends BaseService {
       InfoWsResponse.parser());
   }
 
+  /**
+   * This is a POST request.
+   * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/ce/pause">Further information about this action online (including a response example)</a>
+   * @since 7.2
+   */
+  public void pause() {
+    call(
+      new PostRequest(path("pause"))
+        .setMediaType(MediaTypes.JSON)
+      ).content();
+  }
+
+  /**
+   * This is a POST request.
+   * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/ce/resume">Further information about this action online (including a response example)</a>
+   * @since 7.2
+   */
+  public void resume() {
+    call(
+      new PostRequest(path("resume"))
+        .setMediaType(MediaTypes.JSON)
+      ).content();
+  }
+
   /**
    *
    * This is part of the internal API.