From 6bf8a78f319ad666cb31d2100910dd34e5fcaf13 Mon Sep 17 00:00:00 2001 From: Aurelien Poscia Date: Wed, 21 Dec 2022 09:06:32 +0100 Subject: [PATCH] SONAR-14128 Store and provide node name of CE Task in /api/ce/activity --- server/sonar-ce-common/build.gradle | 1 + .../java/org/sonar/ce/queue/CeQueueImpl.java | 9 ++- .../org/sonar/ce/queue/CeQueueImplTest.java | 64 +++++++++++++++++-- .../sonar/ce/queue/InternalCeQueueImpl.java | 7 +- .../ce/queue/InternalCeQueueImplTest.java | 43 +++++++++++-- .../java/org/sonar/db/ce/CeActivityDto.java | 18 +++++- .../org/sonar/db/ce/CeActivityMapper.xml | 3 + server/sonar-db-dao/src/schema/schema-sq.ddl | 3 +- .../org/sonar/db/ce/CeActivityDaoTest.java | 3 + .../org/sonar/db/ce/CeActivityDtoTest.java | 17 +++++ .../MigrationConfigurationModule.java | 2 + .../AddNodeNameColumnToCeActivityTable.java | 51 +++++++++++++++ .../db/migration/version/v99/DbVersion99.java | 31 +++++++++ ...ddNodeNameColumnToCeActivityTableTest.java | 53 +++++++++++++++ .../version/v99/DbVersion99Test.java | 40 ++++++++++++ .../schema.sql | 25 ++++++++ .../org/sonar/server/platform/WebServer.java | 5 +- .../sonar/server/platform/WebServerImpl.java | 10 +++ .../server/platform/WebServerImplTest.java | 36 +++++++++++ .../platform/serverid/ServerIdManager.java | 3 +- .../org/sonar/server/ce/ws/TaskFormatter.java | 1 + .../projectdump/ExportSubmitterImplTest.java | 4 +- .../server/ce/ws/ActivityActionTest.java | 4 ++ .../sonar/server/ce/ws/CancelActionTest.java | 4 +- .../sonar/server/ce/ws/TaskFormatterTest.java | 3 + sonar-ws/src/main/protobuf/ws-ce.proto | 1 + 26 files changed, 418 insertions(+), 23 deletions(-) create mode 100644 server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v99/AddNodeNameColumnToCeActivityTable.java create mode 100644 server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v99/DbVersion99.java create mode 100644 server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v99/AddNodeNameColumnToCeActivityTableTest.java create mode 100644 server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v99/DbVersion99Test.java create mode 100644 server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v99/AddNodeNameColumnToCeActivityTableTest/schema.sql diff --git a/server/sonar-ce-common/build.gradle b/server/sonar-ce-common/build.gradle index 20e6562ad0b..124c2af585c 100644 --- a/server/sonar-ce-common/build.gradle +++ b/server/sonar-ce-common/build.gradle @@ -50,6 +50,7 @@ dependencies { testImplementation 'org.assertj:assertj-core' testImplementation 'org.assertj:assertj-guava' testImplementation 'org.hamcrest:hamcrest-all' + testImplementation 'org.mockito:mockito-core' testImplementation project(':sonar-plugin-api-impl') testImplementation testFixtures(project(':server:sonar-server-common')) } diff --git a/server/sonar-ce-common/src/main/java/org/sonar/ce/queue/CeQueueImpl.java b/server/sonar-ce-common/src/main/java/org/sonar/ce/queue/CeQueueImpl.java index b207dd7e410..b8dc9456d7a 100644 --- a/server/sonar-ce-common/src/main/java/org/sonar/ce/queue/CeQueueImpl.java +++ b/server/sonar-ce-common/src/main/java/org/sonar/ce/queue/CeQueueImpl.java @@ -49,6 +49,7 @@ import org.sonar.db.ce.CeTaskCharacteristicDto; import org.sonar.db.ce.DeleteIf; import org.sonar.db.component.ComponentDto; import org.sonar.db.user.UserDto; +import org.sonar.server.platform.WebServer; import org.sonar.server.property.InternalProperties; import static com.google.common.base.Preconditions.checkState; @@ -68,11 +69,13 @@ public class CeQueueImpl implements CeQueue { private final System2 system2; private final DbClient dbClient; private final UuidFactory uuidFactory; + protected final WebServer webServer; - public CeQueueImpl(System2 system2, DbClient dbClient, UuidFactory uuidFactory) { + public CeQueueImpl(System2 system2, DbClient dbClient, UuidFactory uuidFactory, WebServer webServer) { this.system2 = system2; this.dbClient = dbClient; this.uuidFactory = uuidFactory; + this.webServer = webServer; } @Override @@ -243,6 +246,7 @@ public class CeQueueImpl implements CeQueue { private void cancelImpl(DbSession dbSession, CeQueueDto q) { CeActivityDto activityDto = new CeActivityDto(q); + activityDto.setNodeName(webServer.getNodeName().orElse(null)); activityDto.setStatus(CeActivityDto.Status.CANCELED); remove(dbSession, q, activityDto); } @@ -251,13 +255,14 @@ public class CeQueueImpl implements CeQueue { public void fail(DbSession dbSession, CeQueueDto task, @Nullable String errorType, @Nullable String errorMessage) { checkState(IN_PROGRESS.equals(task.getStatus()), "Task is not in-progress and can't be marked as failed [uuid=%s]", task.getUuid()); CeActivityDto activityDto = new CeActivityDto(task); + activityDto.setNodeName(webServer.getNodeName().orElse(null)); activityDto.setStatus(CeActivityDto.Status.FAILED); activityDto.setErrorType(errorType); activityDto.setErrorMessage(errorMessage); updateExecutionFields(activityDto); remove(dbSession, task, activityDto); } - + protected long updateExecutionFields(CeActivityDto activityDto) { Long startedAt = activityDto.getStartedAt(); if (startedAt == null) { diff --git a/server/sonar-ce-common/src/test/java/org/sonar/ce/queue/CeQueueImplTest.java b/server/sonar-ce-common/src/test/java/org/sonar/ce/queue/CeQueueImplTest.java index 3aa74acca40..548bf5da50b 100644 --- a/server/sonar-ce-common/src/test/java/org/sonar/ce/queue/CeQueueImplTest.java +++ b/server/sonar-ce-common/src/test/java/org/sonar/ce/queue/CeQueueImplTest.java @@ -43,6 +43,7 @@ import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTesting; import org.sonar.db.user.UserDto; import org.sonar.db.user.UserTesting; +import org.sonar.server.platform.WebServer; import static com.google.common.collect.ImmutableList.of; import static java.util.Arrays.asList; @@ -52,12 +53,15 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.catchThrowable; import static org.assertj.core.api.Assertions.tuple; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import static org.sonar.ce.queue.CeQueue.SubmitOption.UNIQUE_QUEUE_PER_MAIN_COMPONENT; public class CeQueueImplTest { private static final String WORKER_UUID = "workerUuid"; private static final long NOW = 1_450_000_000_000L; + private static final String NODE_NAME = "nodeName1"; private System2 system2 = new TestSystem2().setNow(NOW); @@ -68,7 +72,9 @@ public class CeQueueImplTest { private UuidFactory uuidFactory = new SequenceUuidFactory(); - private CeQueue underTest = new CeQueueImpl(system2, db.getDbClient(), uuidFactory); + private WebServer nodeInformationProvider = mock(WebServer.class); + + private CeQueue underTest = new CeQueueImpl(system2, db.getDbClient(), uuidFactory, nodeInformationProvider); @Test public void submit_returns_task_populated_from_CeTaskSubmit_and_creates_CeQueue_row() { @@ -382,11 +388,37 @@ public class CeQueueImplTest { underTest.cancel(db.getSession(), queueDto); - Optional activity = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), task.getUuid()); + Optional activity = findCeActivityDtoInDb(task); assertThat(activity).isPresent(); assertThat(activity.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED); } + @Test + public void cancel_pending_whenNodeNameProvided_setItInCeActivity() { + when(nodeInformationProvider.getNodeName()).thenReturn(Optional.of(NODE_NAME)); + CeTask task = submit(CeTaskTypes.REPORT, newComponent(randomAlphabetic(12))); + CeQueueDto queueDto = db.getDbClient().ceQueueDao().selectByUuid(db.getSession(), task.getUuid()).get(); + + underTest.cancel(db.getSession(), queueDto); + + Optional activity = findCeActivityDtoInDb(task); + assertThat(activity).isPresent(); + assertThat(activity.get().getNodeName()).isEqualTo(NODE_NAME); + } + + @Test + public void cancel_pending_whenNodeNameNOtProvided_setNulInCeActivity() { + when(nodeInformationProvider.getNodeName()).thenReturn(Optional.empty()); + CeTask task = submit(CeTaskTypes.REPORT, newComponent(randomAlphabetic(12))); + CeQueueDto queueDto = db.getDbClient().ceQueueDao().selectByUuid(db.getSession(), task.getUuid()).get(); + + underTest.cancel(db.getSession(), queueDto); + + Optional activity = findCeActivityDtoInDb(task); + assertThat(activity).isPresent(); + assertThat(activity.get().getNodeName()).isNull(); + } + @Test public void fail_to_cancel_if_in_progress() { CeTask task = submit(CeTaskTypes.REPORT, newComponent(randomAlphabetic(11))); @@ -408,11 +440,11 @@ public class CeQueueImplTest { int canceledCount = underTest.cancelAll(); assertThat(canceledCount).isEqualTo(2); - Optional ceActivityInProgress = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), pendingTask1.getUuid()); + Optional ceActivityInProgress = findCeActivityDtoInDb(pendingTask1); assertThat(ceActivityInProgress.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED); - Optional ceActivityPending1 = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), pendingTask2.getUuid()); + Optional ceActivityPending1 = findCeActivityDtoInDb(pendingTask2); assertThat(ceActivityPending1.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED); - Optional ceActivityPending2 = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), inProgressTask.getUuid()); + Optional ceActivityPending2 = findCeActivityDtoInDb(inProgressTask); assertThat(ceActivityPending2).isNotPresent(); } @@ -430,7 +462,7 @@ public class CeQueueImplTest { @Test public void pauseWorkers_marks_workers_as_pausing_if_some_tasks_in_progress() { CeTask task = submit(CeTaskTypes.REPORT, newComponent(randomAlphabetic(12))); - db.getDbClient().ceQueueDao().tryToPeek(session, task.getUuid(), WORKER_UUID); + db.getDbClient().ceQueueDao().tryToPeek(session, task.getUuid(), WORKER_UUID); // task is in-progress assertThat(underTest.getWorkersPauseStatus()).isEqualTo(CeQueue.WorkersPauseStatus.RESUMED); @@ -477,13 +509,31 @@ public class CeQueueImplTest { underTest.fail(db.getSession(), queueDto, "TIMEOUT", "Failed on timeout"); - Optional activity = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), task.getUuid()); + Optional activity = findCeActivityDtoInDb(task); assertThat(activity).isPresent(); assertThat(activity.get().getStatus()).isEqualTo(CeActivityDto.Status.FAILED); assertThat(activity.get().getErrorType()).isEqualTo("TIMEOUT"); assertThat(activity.get().getErrorMessage()).isEqualTo("Failed on timeout"); assertThat(activity.get().getExecutedAt()).isEqualTo(NOW); assertThat(activity.get().getWorkerUuid()).isEqualTo(WORKER_UUID); + assertThat(activity.get().getNodeName()).isNull(); + } + + @Test + public void fail_in_progress_task_whenNodeNameProvided_setsItInCeActivityDto() { + when(nodeInformationProvider.getNodeName()).thenReturn(Optional.of(NODE_NAME)); + CeTask task = submit(CeTaskTypes.REPORT, newComponent(randomAlphabetic(12))); + CeQueueDto queueDto = db.getDbClient().ceQueueDao().tryToPeek(db.getSession(), task.getUuid(), WORKER_UUID).get(); + + underTest.fail(db.getSession(), queueDto, "TIMEOUT", "Failed on timeout"); + + Optional activity = findCeActivityDtoInDb(task); + assertThat(activity).isPresent(); + assertThat(activity.get().getNodeName()).isEqualTo(NODE_NAME); + } + + private Optional findCeActivityDtoInDb(CeTask task) { + return db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), task.getUuid()); } @Test diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/queue/InternalCeQueueImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/queue/InternalCeQueueImpl.java index 92a076aff6f..a95a102f4a5 100644 --- a/server/sonar-ce/src/main/java/org/sonar/ce/queue/InternalCeQueueImpl.java +++ b/server/sonar-ce/src/main/java/org/sonar/ce/queue/InternalCeQueueImpl.java @@ -47,6 +47,7 @@ import org.sonar.db.ce.CeQueueDao; import org.sonar.db.ce.CeQueueDto; import org.sonar.db.ce.CeTaskCharacteristicDto; import org.sonar.db.component.ComponentDto; +import org.sonar.server.platform.WebServer; import static com.google.common.base.Preconditions.checkArgument; import static java.lang.String.format; @@ -65,8 +66,8 @@ public class InternalCeQueueImpl extends CeQueueImpl implements InternalCeQueue private final NextPendingTaskPicker nextPendingTaskPicker; public InternalCeQueueImpl(System2 system2, DbClient dbClient, UuidFactory uuidFactory, CEQueueStatus queueStatus, - ComputeEngineStatus computeEngineStatus, NextPendingTaskPicker nextPendingTaskPicker) { - super(system2, dbClient, uuidFactory); + ComputeEngineStatus computeEngineStatus, NextPendingTaskPicker nextPendingTaskPicker, WebServer webServer) { + super(system2, dbClient, uuidFactory, webServer); this.dbClient = dbClient; this.queueStatus = queueStatus; this.computeEngineStatus = computeEngineStatus; @@ -113,6 +114,7 @@ public class InternalCeQueueImpl extends CeQueueImpl implements InternalCeQueue CeQueueDto queueDto = dbClient.ceQueueDao().selectByUuid(dbSession, task.getUuid()) .orElseThrow(() -> new IllegalStateException("Task does not exist anymore: " + task)); CeActivityDto activityDto = new CeActivityDto(queueDto); + activityDto.setNodeName(webServer.getNodeName().orElse(null)); activityDto.setStatus(status); executionTimeInMs = updateExecutionFields(activityDto); updateTaskResult(activityDto, taskResult); @@ -176,6 +178,7 @@ public class InternalCeQueueImpl extends CeQueueImpl implements InternalCeQueue List wornOutTasks = dbClient.ceQueueDao().selectWornout(dbSession); wornOutTasks.forEach(queueDto -> { CeActivityDto activityDto = new CeActivityDto(queueDto); + activityDto.setNodeName(webServer.getNodeName().orElse(null)); activityDto.setStatus(CeActivityDto.Status.CANCELED); updateExecutionFields(activityDto); remove(dbSession, queueDto, activityDto); diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/queue/InternalCeQueueImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/queue/InternalCeQueueImplTest.java index c488e4db934..445b29ec849 100644 --- a/server/sonar-ce/src/test/java/org/sonar/ce/queue/InternalCeQueueImplTest.java +++ b/server/sonar-ce/src/test/java/org/sonar/ce/queue/InternalCeQueueImplTest.java @@ -48,6 +48,7 @@ import org.sonar.db.ce.CeTaskTypes; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTesting; import org.sonar.db.user.UserDto; +import org.sonar.server.platform.WebServer; import static java.util.Arrays.asList; import static java.util.Collections.emptyMap; @@ -68,6 +69,7 @@ public class InternalCeQueueImplTest { private static final String AN_ANALYSIS_UUID = "U1"; private static final String WORKER_UUID_1 = "worker uuid 1"; private static final String WORKER_UUID_2 = "worker uuid 2"; + private static final String NODE_NAME = "nodeName1"; private System2 system2 = new AlwaysIncreasingSystem2(); @@ -81,13 +83,15 @@ public class InternalCeQueueImplTest { private ComputeEngineStatus computeEngineStatus = mock(ComputeEngineStatus.class); private Configuration config = mock(Configuration.class); private NextPendingTaskPicker nextPendingTaskPicker = new NextPendingTaskPicker(config, db.getDbClient()); + private WebServer nodeInformationProvider = mock(WebServer.class); private InternalCeQueue underTest = new InternalCeQueueImpl(system2, db.getDbClient(), uuidFactory, queueStatus, - computeEngineStatus, nextPendingTaskPicker); + computeEngineStatus, nextPendingTaskPicker, nodeInformationProvider); @Before public void setUp() { when(config.getBoolean(any())).thenReturn(Optional.of(false)); when(computeEngineStatus.getStatus()).thenReturn(STARTED); + when(nodeInformationProvider.getNodeName()).thenReturn(Optional.of(NODE_NAME)); } @Test @@ -210,6 +214,32 @@ public class InternalCeQueueImplTest { assertThat(history.get().getAnalysisUuid()).isEqualTo("U1"); } + @Test + public void remove_sets_nodeName_in_CeActivity_when_nodeInformationProvider_defines_node_name() { + when(nodeInformationProvider.getNodeName()).thenReturn(Optional.of(NODE_NAME)); + CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); + + Optional peek = underTest.peek(WORKER_UUID_2, true); + underTest.remove(peek.get(), CeActivityDto.Status.SUCCESS, newTaskResult(AN_ANALYSIS_UUID), null); + + Optional history = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), task.getUuid()); + assertThat(history).isPresent(); + assertThat(history.get().getNodeName()).isEqualTo(NODE_NAME); + } + + @Test + public void remove_do_not_set_nodeName_in_CeActivity_when_nodeInformationProvider_does_not_define_node_name() { + when(nodeInformationProvider.getNodeName()).thenReturn(Optional.empty()); + CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); + + Optional peek = underTest.peek(WORKER_UUID_2, true); + underTest.remove(peek.get(), CeActivityDto.Status.SUCCESS, newTaskResult(AN_ANALYSIS_UUID), null); + + Optional history = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), task.getUuid()); + assertThat(history).isPresent(); + assertThat(history.get().getNodeName()).isNull(); + } + @Test public void remove_saves_error_message_and_stacktrace_when_exception_is_provided() { Throwable error = new NullPointerException("Fake NPE to test persistence to DB"); @@ -248,7 +278,7 @@ public class InternalCeQueueImplTest { db.getDbClient().ceQueueDao().deleteByUuid(db.getSession(), task.getUuid()); db.commit(); - InternalCeQueueImpl underTest = new InternalCeQueueImpl(system2, db.getDbClient(), null, queueStatus, null, null); + InternalCeQueueImpl underTest = new InternalCeQueueImpl(system2, db.getDbClient(), null, queueStatus, null, null, nodeInformationProvider); try { underTest.remove(task, CeActivityDto.Status.SUCCESS, null, null); @@ -265,7 +295,7 @@ public class InternalCeQueueImplTest { CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); db.getDbClient().ceQueueDao().deleteByUuid(db.getSession(), task.getUuid()); db.commit(); - InternalCeQueueImpl underTest = new InternalCeQueueImpl(system2, db.getDbClient(), null, queueStatusMock, null, null); + InternalCeQueueImpl underTest = new InternalCeQueueImpl(system2, db.getDbClient(), null, queueStatusMock, null, null, nodeInformationProvider); try { underTest.remove(task, CeActivityDto.Status.FAILED, null, null); @@ -277,16 +307,19 @@ public class InternalCeQueueImplTest { @Test public void cancelWornOuts_does_not_update_queueStatus() { + CEQueueStatus queueStatusMock = mock(CEQueueStatus.class); CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); db.executeUpdateSql("update ce_queue set status = 'PENDING', started_at = 123 where uuid = '" + task.getUuid() + "'"); db.commit(); - InternalCeQueueImpl underTest = new InternalCeQueueImpl(system2, db.getDbClient(), null, queueStatusMock, null, null); + InternalCeQueueImpl underTest = new InternalCeQueueImpl(system2, db.getDbClient(), null, queueStatusMock, null, null, nodeInformationProvider); underTest.cancelWornOuts(); - assertThat(db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), task.getUuid())).isPresent(); + Optional ceActivityDto = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), task.getUuid()); + assertThat(ceActivityDto).isPresent(); + assertThat(ceActivityDto.get().getNodeName()).isEqualTo(NODE_NAME); verifyNoInteractions(queueStatusMock); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeActivityDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeActivityDto.java index 32114fbbfe3..f107fdb45eb 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeActivityDto.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeActivityDto.java @@ -30,7 +30,8 @@ import static java.lang.String.format; public class CeActivityDto { - private static final int MAX_SIZE_ERROR_MESSAGE = 1000; + private static final int ERROR_MESSAGE_MAX_SIZE = 1000; + private static final int NODE_NAME_MAX_SIZE = 100; public enum Status { SUCCESS, FAILED, CANCELED @@ -105,6 +106,8 @@ public class CeActivityDto { */ private int warningCount = 0; + private String nodeName; + CeActivityDto() { // required for MyBatis } @@ -287,7 +290,7 @@ public class CeActivityDto { } public CeActivityDto setErrorMessage(@Nullable String errorMessage) { - this.errorMessage = ensureNotTooBig(removeCharZeros(errorMessage), MAX_SIZE_ERROR_MESSAGE); + this.errorMessage = ensureNotTooBig(removeCharZeros(errorMessage), ERROR_MESSAGE_MAX_SIZE); return this; } @@ -331,10 +334,21 @@ public class CeActivityDto { return this; } + @CheckForNull + public String getNodeName() { + return nodeName; + } + + public CeActivityDto setNodeName(@Nullable String nodeName) { + this.nodeName = ensureNotTooBig(nodeName, NODE_NAME_MAX_SIZE); + return this; + } + @Override public String toString() { return "CeActivityDto{" + "uuid='" + uuid + '\'' + + ", nodeName='" + nodeName + '\'' + ", componentUuid='" + componentUuid + '\'' + ", mainComponentUuid='" + mainComponentUuid + '\'' + ", analysisUuid='" + analysisUuid + '\'' + diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/ce/CeActivityMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/ce/CeActivityMapper.xml index 261f886da0a..0ad2f5d286b 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/ce/CeActivityMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/ce/CeActivityMapper.xml @@ -21,6 +21,7 @@ ca.uuid, + ca.node_name as nodeName, ca.task_type as taskType, ca.component_uuid as componentUuid, ca.main_component_uuid as mainComponentUuid, @@ -175,6 +176,7 @@ insert into ce_activity ( uuid, + node_name, component_uuid, main_component_uuid, analysis_uuid, @@ -199,6 +201,7 @@ ) values ( #{uuid,jdbcType=VARCHAR}, + #{nodeName,jdbcType=VARCHAR}, #{componentUuid,jdbcType=VARCHAR}, #{mainComponentUuid,jdbcType=VARCHAR}, #{analysisUuid,jdbcType=VARCHAR}, diff --git a/server/sonar-db-dao/src/schema/schema-sq.ddl b/server/sonar-db-dao/src/schema/schema-sq.ddl index eb1660e6ef6..0cc0c1c8c34 100644 --- a/server/sonar-db-dao/src/schema/schema-sq.ddl +++ b/server/sonar-db-dao/src/schema/schema-sq.ddl @@ -136,7 +136,8 @@ CREATE TABLE "CE_ACTIVITY"( "ERROR_TYPE" CHARACTER VARYING(20), "WORKER_UUID" CHARACTER VARYING(40), "CREATED_AT" BIGINT NOT NULL, - "UPDATED_AT" BIGINT NOT NULL + "UPDATED_AT" BIGINT NOT NULL, + "NODE_NAME" CHARACTER VARYING(100) ); ALTER TABLE "CE_ACTIVITY" ADD CONSTRAINT "PK_CE_ACTIVITY" PRIMARY KEY("UUID"); CREATE INDEX "CE_ACTIVITY_COMPONENT" ON "CE_ACTIVITY"("COMPONENT_UUID" NULLS FIRST); diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/ce/CeActivityDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/ce/CeActivityDaoTest.java index f6d28d0b87a..d6f59435edd 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/ce/CeActivityDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/ce/CeActivityDaoTest.java @@ -71,6 +71,7 @@ public class CeActivityDaoTest { private static final String COMPONENT_1 = randomAlphabetic(14); private static final long INITIAL_TIME = 1_450_000_000_000L; + private static final String NODE_NAME = "node1"; private final TestSystem2 system2 = new TestSystem2().setNow(INITIAL_TIME); @@ -93,6 +94,7 @@ public class CeActivityDaoTest { assertThat(saved).isPresent(); CeActivityDto dto = saved.get(); assertThat(dto.getUuid()).isEqualTo("TASK_1"); + assertThat(dto.getNodeName()).isEqualTo(NODE_NAME); assertThat(dto.getMainComponentUuid()).isEqualTo(MAINCOMPONENT_1); assertThat(dto.getComponentUuid()).isEqualTo(COMPONENT_1); assertThat(dto.getStatus()).isEqualTo(SUCCESS); @@ -858,6 +860,7 @@ public class CeActivityDaoTest { CeQueueDto ceQueueDto = db.getDbClient().ceQueueDao().selectByUuid(dbSession, uuid).get(); CeActivityDto dto = new CeActivityDto(ceQueueDto); + dto.setNodeName(NODE_NAME); dto.setStatus(status); dto.setStartedAt(1_500_000_000_000L); dto.setExecutedAt(1_500_000_000_500L); diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/ce/CeActivityDtoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/ce/CeActivityDtoTest.java index b57f5825ac8..f9215e29076 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/ce/CeActivityDtoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/ce/CeActivityDtoTest.java @@ -26,6 +26,7 @@ import java.util.Random; import org.junit.Test; import org.junit.runner.RunWith; +import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -33,6 +34,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; @RunWith(DataProviderRunner.class) public class CeActivityDtoTest { private static final String STR_40_CHARS = "0123456789012345678901234567890123456789"; + private static final String STR_100_CHARS = randomAlphabetic(100); private CeActivityDto underTest = new CeActivityDto(); @Test @@ -99,6 +101,21 @@ public class CeActivityDtoTest { .hasMessage("Value is too long for column CE_ACTIVITY.MAIN_COMPONENT_UUID: " + str_41_chars); } + @Test + public void setNodeName_accepts_null_empty_and_string_100_chars_or_less() { + underTest.setNodeName(null); + underTest.setNodeName(""); + underTest.setNodeName("bar"); + underTest.setNodeName(STR_100_CHARS); + assertThat(underTest.getNodeName()).isEqualTo(STR_100_CHARS); + } + + @Test + public void setNodeName_ifMoreThan100chars_truncates() { + underTest.setNodeName(STR_100_CHARS + "This should be truncated"); + assertThat(underTest.getNodeName()).isEqualTo(STR_100_CHARS); + } + @Test @UseDataProvider("stringsWithChar0") public void setStacktrace_filters_out_char_zero(String withChar0, String expected) { diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/MigrationConfigurationModule.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/MigrationConfigurationModule.java index 1208b855f29..cf8c29ce3bc 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/MigrationConfigurationModule.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/MigrationConfigurationModule.java @@ -37,6 +37,7 @@ import org.sonar.server.platform.db.migration.version.v95.DbVersion95; import org.sonar.server.platform.db.migration.version.v96.DbVersion96; import org.sonar.server.platform.db.migration.version.v97.DbVersion97; import org.sonar.server.platform.db.migration.version.v98.DbVersion98; +import org.sonar.server.platform.db.migration.version.v99.DbVersion99; public class MigrationConfigurationModule extends Module { @Override @@ -54,6 +55,7 @@ public class MigrationConfigurationModule extends Module { DbVersion96.class, DbVersion97.class, DbVersion98.class, + DbVersion99.class, // migration steps MigrationStepRegistryImpl.class, diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v99/AddNodeNameColumnToCeActivityTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v99/AddNodeNameColumnToCeActivityTable.java new file mode 100644 index 00000000000..042605d88fc --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v99/AddNodeNameColumnToCeActivityTable.java @@ -0,0 +1,51 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 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.db.migration.version.v99; + +import com.google.common.annotations.VisibleForTesting; +import java.sql.Connection; +import java.sql.SQLException; +import org.sonar.db.Database; +import org.sonar.db.DatabaseUtils; +import org.sonar.server.platform.db.migration.def.VarcharColumnDef; +import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder; +import org.sonar.server.platform.db.migration.step.DdlChange; + +class AddNodeNameColumnToCeActivityTable extends DdlChange { + @VisibleForTesting + static final String TABLE_NAME = "ce_activity"; + @VisibleForTesting + static final String COLUMN_NAME = "node_name"; + + public AddNodeNameColumnToCeActivityTable(Database db) { + super(db); + } + + @Override + public void execute(Context context) throws SQLException { + try (Connection c = getDatabase().getDataSource().getConnection()) { + if (!DatabaseUtils.tableColumnExists(c, TABLE_NAME, COLUMN_NAME)) { + context.execute(new AddColumnsBuilder(getDialect(), TABLE_NAME) + .addColumn(VarcharColumnDef.newVarcharColumnDefBuilder(COLUMN_NAME).setLimit(100).setIsNullable(true).build()) + .build()); + } + } + } +} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v99/DbVersion99.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v99/DbVersion99.java new file mode 100644 index 00000000000..1d345f5b118 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v99/DbVersion99.java @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 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.db.migration.version.v99; + +import org.sonar.server.platform.db.migration.step.MigrationStepRegistry; +import org.sonar.server.platform.db.migration.version.DbVersion; + +public class DbVersion99 implements DbVersion { + @Override + public void addSteps(MigrationStepRegistry registry) { + registry + .add(6800, "Add node_name column to ce_activity table", AddNodeNameColumnToCeActivityTable.class); + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v99/AddNodeNameColumnToCeActivityTableTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v99/AddNodeNameColumnToCeActivityTableTest.java new file mode 100644 index 00000000000..927e9d57666 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v99/AddNodeNameColumnToCeActivityTableTest.java @@ -0,0 +1,53 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 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.db.migration.version.v99; + +import java.sql.SQLException; +import java.sql.Types; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.db.CoreDbTester; + +import static org.sonar.server.platform.db.migration.version.v99.AddNodeNameColumnToCeActivityTable.COLUMN_NAME; +import static org.sonar.server.platform.db.migration.version.v99.AddNodeNameColumnToCeActivityTable.TABLE_NAME; + +public class AddNodeNameColumnToCeActivityTableTest { + + @Rule + public final CoreDbTester db = CoreDbTester.createForSchema(AddNodeNameColumnToCeActivityTableTest.class, "schema.sql"); + + private final AddNodeNameColumnToCeActivityTable underTest = new AddNodeNameColumnToCeActivityTable(db.database()); + + @Test + public void migration_should_add_column() throws SQLException { + db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME); + underTest.execute(); + db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, Types.VARCHAR, null, true); + } + + @Test + public void migration_should_be_reentrant() throws SQLException { + db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME); + underTest.execute(); + // re-entrant + underTest.execute(); + db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, Types.VARCHAR, null, true); + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v99/DbVersion99Test.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v99/DbVersion99Test.java new file mode 100644 index 00000000000..ce39f82e710 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v99/DbVersion99Test.java @@ -0,0 +1,40 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 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.db.migration.version.v99; + +import org.junit.Test; + +import static org.sonar.server.platform.db.migration.version.DbVersionTestUtils.verifyMigrationNotEmpty; +import static org.sonar.server.platform.db.migration.version.DbVersionTestUtils.verifyMinimumMigrationNumber; + +public class DbVersion99Test { + private final DbVersion99 underTest = new DbVersion99(); + + @Test + public void migrationNumber_starts_at_6800() { + verifyMinimumMigrationNumber(underTest, 6800); + } + + @Test + public void verify_migration_is_not_empty() { + verifyMigrationNotEmpty(underTest); + } + +} diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v99/AddNodeNameColumnToCeActivityTableTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v99/AddNodeNameColumnToCeActivityTableTest/schema.sql new file mode 100644 index 00000000000..578f6db77d0 --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v99/AddNodeNameColumnToCeActivityTableTest/schema.sql @@ -0,0 +1,25 @@ + +CREATE TABLE "CE_ACTIVITY"( + "UUID" CHARACTER VARYING(40) NOT NULL, + "TASK_TYPE" CHARACTER VARYING(15) NOT NULL, + "MAIN_COMPONENT_UUID" CHARACTER VARYING(40), + "COMPONENT_UUID" CHARACTER VARYING(40), + "STATUS" CHARACTER VARYING(15) NOT NULL, + "MAIN_IS_LAST" BOOLEAN NOT NULL, + "MAIN_IS_LAST_KEY" CHARACTER VARYING(55) NOT NULL, + "IS_LAST" BOOLEAN NOT NULL, + "IS_LAST_KEY" CHARACTER VARYING(55) NOT NULL, + "SUBMITTER_UUID" CHARACTER VARYING(255), + "SUBMITTED_AT" BIGINT NOT NULL, + "STARTED_AT" BIGINT, + "EXECUTED_AT" BIGINT, + "EXECUTION_COUNT" INTEGER NOT NULL, + "EXECUTION_TIME_MS" BIGINT, + "ANALYSIS_UUID" CHARACTER VARYING(50), + "ERROR_MESSAGE" CHARACTER VARYING(1000), + "ERROR_STACKTRACE" CHARACTER LARGE OBJECT, + "ERROR_TYPE" CHARACTER VARYING(20), + "WORKER_UUID" CHARACTER VARYING(40), + "CREATED_AT" BIGINT NOT NULL, + "UPDATED_AT" BIGINT NOT NULL +); diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/platform/WebServer.java b/server/sonar-server-common/src/main/java/org/sonar/server/platform/WebServer.java index e82e99fac26..97b7ffee737 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/platform/WebServer.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/platform/WebServer.java @@ -19,6 +19,7 @@ */ package org.sonar.server.platform; +import java.util.Optional; import org.sonar.api.ce.ComputeEngineSide; import org.sonar.api.server.ServerSide; @@ -27,7 +28,7 @@ import org.sonar.api.server.ServerSide; public interface WebServer { /** - * WebServer is standalone when property {@link org.sonar.process.ProcessProperties.Property#CLUSTER_ENABLED} is {@code false} or + * Node is standalone when property {@link org.sonar.process.ProcessProperties.Property#CLUSTER_ENABLED} is {@code false} or * undefined. */ boolean isStandalone(); @@ -40,4 +41,6 @@ public interface WebServer { */ boolean isStartupLeader(); + Optional getNodeName(); + } diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/platform/WebServerImpl.java b/server/sonar-server-common/src/main/java/org/sonar/server/platform/WebServerImpl.java index e1a8ac107b0..07f37975002 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/platform/WebServerImpl.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/platform/WebServerImpl.java @@ -19,24 +19,29 @@ */ package org.sonar.server.platform; +import java.util.Optional; import org.sonar.api.config.Configuration; import org.sonar.api.utils.log.Loggers; import static org.sonar.process.ProcessProperties.Property.CLUSTER_ENABLED; +import static org.sonar.process.ProcessProperties.Property.CLUSTER_NODE_NAME; import static org.sonar.process.ProcessProperties.Property.CLUSTER_WEB_STARTUP_LEADER; public class WebServerImpl implements WebServer { private final boolean clusterEnabled; private final boolean startupLeader; + private final String nodeName; public WebServerImpl(Configuration config) { this.clusterEnabled = config.getBoolean(CLUSTER_ENABLED.getKey()).orElse(false); if (this.clusterEnabled) { this.startupLeader = config.getBoolean(CLUSTER_WEB_STARTUP_LEADER.getKey()).orElse(false); + this.nodeName = config.get(CLUSTER_NODE_NAME.getKey()).orElse(CLUSTER_NODE_NAME.getDefaultValue()); Loggers.get(WebServerImpl.class).info("Cluster enabled (startup {})", startupLeader ? "leader" : "follower"); } else { this.startupLeader = true; + this.nodeName = null; } } @@ -49,4 +54,9 @@ public class WebServerImpl implements WebServer { public boolean isStartupLeader() { return startupLeader; } + + @Override + public Optional getNodeName() { + return Optional.ofNullable(nodeName); + } } diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/platform/WebServerImplTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/platform/WebServerImplTest.java index 168ed9bd234..9b1998a1236 100644 --- a/server/sonar-server-common/src/test/java/org/sonar/server/platform/WebServerImplTest.java +++ b/server/sonar-server-common/src/test/java/org/sonar/server/platform/WebServerImplTest.java @@ -69,4 +69,40 @@ public class WebServerImplTest { assertThat(underTest.isStartupLeader()).isFalse(); } + @Test + public void getNodeName_whenNotACluster_isEmpty() { + settings.setProperty("sonar.cluster.enabled", "false"); + settings.setProperty("sonar.cluster.node.name", "nameIgnored"); + + WebServerImpl underTest = new WebServerImpl(settings.asConfig()); + + assertThat(underTest.getNodeName()).isEmpty(); + } + + @Test + public void getNodeName_whenClusterAndNameNotDefined_fallbacksToDefaultName() { + settings.setProperty("sonar.cluster.enabled", "true"); + settings.removeProperty("sonar.cluster.node.name"); + + WebServerImpl underTest = new WebServerImpl(settings.asConfig()); + + assertThat(underTest.getNodeName()).isNotEmpty(); + String nodeNameFirstCallToGetNodeName = underTest.getNodeName().get(); + assertThat(nodeNameFirstCallToGetNodeName).startsWith("sonarqube-"); + String nodeNameSecondCallToGetNodeName = underTest.getNodeName().get(); + assertThat(nodeNameFirstCallToGetNodeName).isEqualTo(nodeNameSecondCallToGetNodeName); + } + + @Test + public void getNodeName_whenClusterAndNameDefined_returnName() { + String nodeName = "nodeName1"; + settings.setProperty("sonar.cluster.enabled", "true"); + settings.setProperty("sonar.cluster.node.name", nodeName); + + WebServerImpl underTest = new WebServerImpl(settings.asConfig()); + + assertThat(underTest.getNodeName()).isNotEmpty(); + assertThat(underTest.getNodeName().get()).startsWith(nodeName); + } + } diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/serverid/ServerIdManager.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/serverid/ServerIdManager.java index 33afdd866c4..3f017c59115 100644 --- a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/serverid/ServerIdManager.java +++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/serverid/ServerIdManager.java @@ -47,7 +47,8 @@ public class ServerIdManager implements Startable { private final SonarRuntime runtime; private final WebServer webServer; - public ServerIdManager(ServerIdChecksum serverIdChecksum, ServerIdFactory serverIdFactory, DbClient dbClient, SonarRuntime runtime, WebServer webServer) { + public ServerIdManager(ServerIdChecksum serverIdChecksum, ServerIdFactory serverIdFactory, + DbClient dbClient, SonarRuntime runtime, WebServer webServer) { this.serverIdChecksum = serverIdChecksum; this.serverIdFactory = serverIdFactory; this.dbClient = dbClient; diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/TaskFormatter.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/TaskFormatter.java index f91adf41bf3..94640a00cde 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/TaskFormatter.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/TaskFormatter.java @@ -107,6 +107,7 @@ public class TaskFormatter { builder.setId(dto.getUuid()); builder.setStatus(Ce.TaskStatus.valueOf(dto.getStatus().name())); builder.setType(dto.getTaskType()); + ofNullable(dto.getNodeName()).ifPresent(builder::setNodeName); ofNullable(dto.getComponentUuid()).ifPresent(uuid -> setComponent(builder, uuid, cache).setComponentId(uuid)); String analysisUuid = dto.getAnalysisUuid(); ofNullable(analysisUuid).ifPresent(builder::setAnalysisId); diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/projectdump/ExportSubmitterImplTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/projectdump/ExportSubmitterImplTest.java index af26afe7ec8..5255dd6d7f7 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/projectdump/ExportSubmitterImplTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/projectdump/ExportSubmitterImplTest.java @@ -29,10 +29,12 @@ import org.sonar.db.DbClient; import org.sonar.db.DbTester; import org.sonar.db.ce.CeQueueDto; import org.sonar.db.component.ComponentDto; +import org.sonar.server.platform.WebServer; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.tuple; +import static org.mockito.Mockito.mock; public class ExportSubmitterImplTest { @@ -43,7 +45,7 @@ public class ExportSubmitterImplTest { public DbTester db = DbTester.create(system2); private final DbClient dbClient = db.getDbClient(); - private final CeQueue ceQueue = new CeQueueImpl(system2, db.getDbClient(), UuidFactoryFast.getInstance()); + private final CeQueue ceQueue = new CeQueueImpl(system2, db.getDbClient(), UuidFactoryFast.getInstance(), mock(WebServer.class)); private final ExportSubmitterImpl underTest = new ExportSubmitterImpl(ceQueue, dbClient); diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/ws/ActivityActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/ws/ActivityActionTest.java index 19d6da98d65..bbaf0f2a348 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/ws/ActivityActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/ws/ActivityActionTest.java @@ -84,6 +84,7 @@ import static org.sonar.server.ce.ws.CeWsParameters.PARAM_TYPE; public class ActivityActionTest { private static final long EXECUTED_AT = System2.INSTANCE.now(); + private static final String NODE_NAME = "nodeName1"; @Rule public UserSessionRule userSession = UserSessionRule.standalone(); @@ -111,6 +112,7 @@ public class ActivityActionTest { Task task = activityResponse.getTasks(0); assertThat(task.getId()).isEqualTo("T2"); assertThat(task.getStatus()).isEqualTo(Ce.TaskStatus.FAILED); + assertThat(task.getNodeName()).isEqualTo(NODE_NAME); assertThat(task.getComponentId()).isEqualTo(project2.uuid()); assertThat(task.hasAnalysisId()).isFalse(); assertThat(task.getExecutionTimeMs()).isEqualTo(500L); @@ -118,6 +120,7 @@ public class ActivityActionTest { task = activityResponse.getTasks(1); assertThat(task.getId()).isEqualTo("T1"); + assertThat(task.getNodeName()).isEqualTo(NODE_NAME); assertThat(task.getStatus()).isEqualTo(Ce.TaskStatus.SUCCESS); assertThat(task.getComponentId()).isEqualTo(project1.uuid()); assertThat(task.getWarningCount()).isZero(); @@ -678,6 +681,7 @@ public class ActivityActionTest { activityDto.setStatus(status); activityDto.setExecutionTimeMs(500L); activityDto.setExecutedAt(EXECUTED_AT); + activityDto.setNodeName(NODE_NAME); activityDto.setAnalysisUuid(analysis == null ? null : analysis.getUuid()); db.getDbClient().ceActivityDao().insert(db.getSession(), activityDto); db.commit(); diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/ws/CancelActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/ws/CancelActionTest.java index 057c44514bf..6086a1219b6 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/ws/CancelActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/ws/CancelActionTest.java @@ -36,12 +36,14 @@ import org.sonar.db.ce.CeQueueDto; import org.sonar.db.ce.CeTaskTypes; import org.sonar.db.component.ComponentDto; import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.platform.WebServer; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.WsActionTester; import static java.util.Collections.emptyMap; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; public class CancelActionTest { @@ -51,7 +53,7 @@ public class CancelActionTest { public DbTester db = DbTester.create(); private System2 system2 = new TestSystem2(); - private CeQueue queue = new CeQueueImpl(system2, db.getDbClient(), UuidFactoryFast.getInstance()); + private CeQueue queue = new CeQueueImpl(system2, db.getDbClient(), UuidFactoryFast.getInstance(), mock(WebServer.class)); private CancelAction underTest = new CancelAction(userSession, db.getDbClient(), queue); private WsActionTester tester = new WsActionTester(underTest); diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/ws/TaskFormatterTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/ws/TaskFormatterTest.java index e59f4b394bc..be88d5fdea8 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/ws/TaskFormatterTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/ws/TaskFormatterTest.java @@ -49,6 +49,7 @@ import static org.sonar.db.ce.CeQueueTesting.makeInProgress; public class TaskFormatterTest { + private static final String NODE_NAME = "nodeName1"; @Rule public DbTester db = DbTester.create(System2.INSTANCE); @@ -187,6 +188,7 @@ public class TaskFormatterTest { assertThat(wsTask.getType()).isEqualTo(CeTaskTypes.REPORT); assertThat(wsTask.getId()).isEqualTo("UUID"); + assertThat(wsTask.getNodeName()).isEqualTo(NODE_NAME); assertThat(wsTask.getStatus()).isEqualTo(Ce.TaskStatus.FAILED); assertThat(wsTask.getSubmittedAt()).isEqualTo(DateUtils.formatDateTime(new Date(1_450_000_000_000L))); assertThat(wsTask.getSubmitterLogin()).isEqualTo(user.getLogin()); @@ -282,6 +284,7 @@ public class TaskFormatterTest { testActivityDto.setWarningCount(warningCount); return testActivityDto .setStatus(status) + .setNodeName(NODE_NAME) .setExecutionTimeMs(500L) .setAnalysisUuid("U1"); } diff --git a/sonar-ws/src/main/protobuf/ws-ce.proto b/sonar-ws/src/main/protobuf/ws-ce.proto index b685fbcf3cc..c094aca171c 100644 --- a/sonar-ws/src/main/protobuf/ws-ce.proto +++ b/sonar-ws/src/main/protobuf/ws-ce.proto @@ -134,6 +134,7 @@ message Task { optional string pullRequestTitle = 25; optional int32 warningCount = 26; repeated string warnings = 27; + optional string nodeName = 28; } enum TaskStatus { -- 2.39.5