Skip to content

Commit e584280

Browse files
review comments
1 parent 9d10321 commit e584280

8 files changed

Lines changed: 68 additions & 7 deletions

File tree

‎api/src/main/java/org/apache/cloudstack/api/command/user/job/ListAsyncJobsCmd.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public class ListAsyncJobsCmd extends BaseListAccountResourcesCmd {
4646
@Parameter(name = ApiConstants.START_DATE, type = CommandType.DATE, description = "The start date from which the async jobs should be listed. Only jobs created on or after this date will be included. (use format \"yyyy-MM-dd'T'HH:mm:ss'+'SSSS\")")
4747
private Date startDate;
4848

49-
@Parameter(name = ApiConstants.END_DATE, type = CommandType.DATE, description = "The end date up to which the async jobs should be listed. Only jobs created on or before this date will be included. (use format \"yyyy-MM-dd'T'HH:mm:ss'+'SSSS\")")
49+
@Parameter(name = ApiConstants.END_DATE, type = CommandType.DATE, description = "The end date up to which the async jobs should be listed. Only jobs created on or before this date will be included. (use format \"yyyy-MM-dd'T'HH:mm:ss'+'SSSS\")", since = "24.0")
5050
private Date endDate;
5151

5252
@Parameter(name = ApiConstants.MANAGEMENT_SERVER_ID, type = CommandType.UUID, entityType = ManagementServerResponse.class, description = "The id of the management server", since="4.19")

‎engine/orchestration/src/main/java/com/cloud/agent/manager/AgentAttache.java‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,9 +247,13 @@ protected boolean cancelRunning(final long seq) {
247247
/** Job-cancel path; distinct from cancel(seq), which is also the timeout path and never reaches the hypervisor. */
248248
public boolean cancelExecution(final long seq) {
249249
_cancelledSequences.add(seq);
250-
final boolean stopped = cancelRunning(seq);
250+
if (!cancelRunning(seq)) {
251+
// refused: the command runs on and its sender must see the real answer
252+
_cancelledSequences.remove(seq);
253+
return false;
254+
}
251255
cancel(seq);
252-
return stopped;
256+
return true;
253257
}
254258

255259
protected synchronized int findRequest(final Request req) {

‎engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2123,7 +2123,8 @@ protected void runInContext() {
21232123
logger.info("Job-{} on {} {} was cancelled, stopping its in-flight commands",
21242124
job.getId(), job.getInstanceType(), job.getInstanceId());
21252125
if (!cancelJobExecution(job.getId(), "Job was cancelled")) {
2126-
logger.warn("Not every in-flight command of cancelled job-{} could be stopped; the rest will run to completion", job.getId());
2126+
logger.warn("Not every in-flight command of cancelled job-{} could be stopped; retrying on the next check", job.getId());
2127+
continue;
21272128
}
21282129
}
21292130
asyncJobManager.finalizeCancelledJob(job.getId());

‎engine/orchestration/src/main/java/com/cloud/agent/manager/DirectAgentAttache.java‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,10 @@ private synchronized void scheduleFromQueue() {
248248
Task task = tasks.remove();
249249
Future<?> future = _agentMgr.getDirectAgentPool().submit(task);
250250
_taskFutures.put(task._req.getSequence(), future);
251+
if (future.isDone()) {
252+
// the task may have finished (and cleaned up) before the future was recorded
253+
_taskFutures.remove(task._req.getSequence());
254+
}
251255
}
252256
}
253257

‎engine/orchestration/src/test/java/com/cloud/agent/manager/AgentManagerImplTest.java‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,17 @@
3131
import com.cloud.host.dao.HostDetailsDao;
3232
import com.cloud.hypervisor.Hypervisor;
3333
import com.cloud.utils.Pair;
34+
import org.apache.cloudstack.framework.jobs.AsyncJobManager;
35+
import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO;
3436
import org.junit.Assert;
3537
import org.junit.Before;
3638
import org.junit.Test;
3739
import org.mockito.Mockito;
3840

3941
import java.util.ArrayList;
42+
import java.util.Collections;
4043
import java.util.HashMap;
44+
import java.util.HashSet;
4145
import java.util.Map;
4246

4347
public class AgentManagerImplTest {
@@ -172,4 +176,41 @@ public void testGetHostSshPortWithKVMHostCustomPort() {
172176
int hostSshPort = mgr.getHostSshPort(host);
173177
Assert.assertEquals(3922, hostSshPort);
174178
}
179+
180+
private AsyncJobManager cancelledJobOnThisServer(final long jobId) {
181+
final AsyncJobManager asyncJobManager = Mockito.mock(AsyncJobManager.class);
182+
mgr.asyncJobManager = asyncJobManager;
183+
final AsyncJobVO job = new AsyncJobVO();
184+
job.setId(jobId);
185+
Mockito.when(asyncJobManager.listCancelledJobsExecutingOn(mgr._nodeId)).thenReturn(Collections.singletonList(job));
186+
return asyncJobManager;
187+
}
188+
189+
@Test
190+
public void testCancelledJobWithoutInFlightCommandsIsFinalisedAtOnce() {
191+
final AsyncJobManager asyncJobManager = cancelledJobOnThisServer(42L);
192+
193+
mgr.new CancelledJobsCheckTask().runInContext();
194+
195+
Mockito.verify(asyncJobManager).finalizeCancelledJob(42L);
196+
Assert.assertTrue(mgr.isJobCancelled(42L));
197+
}
198+
199+
@Test
200+
public void testCancelledJobStaysAssignedUntilItsCommandCanBeStopped() throws Exception {
201+
final AsyncJobManager asyncJobManager = cancelledJobOnThisServer(42L);
202+
final AgentAttache attache = Mockito.mock(AgentAttache.class);
203+
Mockito.doReturn(attache).when(mgr).getAttache(1L);
204+
mgr._jobToHostIdAndReqSequenceMap.put(42L, new HashSet<>(Collections.singleton(new Pair<>(1L, 11L))));
205+
206+
Mockito.when(attache.isExecutionCancellable(11L)).thenReturn(false);
207+
mgr.new CancelledJobsCheckTask().runInContext();
208+
Mockito.verify(asyncJobManager, Mockito.never()).finalizeCancelledJob(Mockito.anyLong());
209+
Mockito.verify(attache, Mockito.never()).cancelExecution(Mockito.anyLong());
210+
211+
Mockito.when(attache.isExecutionCancellable(11L)).thenReturn(true);
212+
Mockito.when(attache.cancelExecution(11L)).thenReturn(true);
213+
mgr.new CancelledJobsCheckTask().runInContext();
214+
Mockito.verify(asyncJobManager).finalizeCancelledJob(42L);
215+
}
175216
}

‎engine/orchestration/src/test/java/com/cloud/agent/manager/DirectAgentAttacheTest.java‎

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.mockito.Mockito;
2929
import org.mockito.junit.MockitoJUnitRunner;
3030

31+
import com.cloud.agent.Listener;
3132
import com.cloud.agent.api.CheckHealthCommand;
3233
import com.cloud.agent.transport.Request;
3334
import com.cloud.hypervisor.Hypervisor;
@@ -86,28 +87,32 @@ public void testCancelQueuedTaskDropsItBeforeItReachesTheResource() throws Excep
8687
@Test
8788
public void testCancelRunningTaskStopsTheResourceThenTheThread() throws Exception {
8889
final Request request = submitRunning(101L);
90+
directAgentAttache.registerListener(101L, waiter());
8991
Mockito.doReturn(true).when(_resource).isRequestSequenceCancellable(101L);
9092
Mockito.doReturn(true).when(_resource).cancelRequestSequence(101L);
9193

9294
Assert.assertTrue(directAgentAttache.isExecutionCancellable(101L));
93-
directAgentAttache.cancelExecution(101L);
95+
Assert.assertTrue(directAgentAttache.cancelExecution(101L));
9496

9597
Mockito.verify(_resource).cancelRequestSequence(101L);
9698
Mockito.verify(runningTask).cancel(true);
9799
Assert.assertTrue(request.isCancelled());
100+
Assert.assertFalse(directAgentAttache._waitForList.containsKey(101L));
98101
}
99102

100103
@Test
101104
public void testCancelLeavesNonCancellableRunningTaskAlone() throws Exception {
102105
final Request request = submitRunning(303L);
106+
directAgentAttache.registerListener(303L, waiter());
103107
Mockito.doReturn(false).when(_resource).isRequestSequenceCancellable(303L);
104108

105109
Assert.assertFalse(directAgentAttache.isExecutionCancellable(303L));
106-
directAgentAttache.cancelExecution(303L);
110+
Assert.assertFalse(directAgentAttache.cancelExecution(303L));
107111

108112
Mockito.verify(_resource, Mockito.never()).cancelRequestSequence(Mockito.anyLong());
109113
Mockito.verify(runningTask, Mockito.never()).cancel(Mockito.anyBoolean());
110114
Assert.assertFalse(request.isCancelled());
115+
Assert.assertTrue(directAgentAttache._waitForList.containsKey(303L));
111116
}
112117

113118
@Test
@@ -121,6 +126,12 @@ private Request newRequest(final long seq) {
121126
return request;
122127
}
123128

129+
private Listener waiter() {
130+
final Listener listener = Mockito.mock(Listener.class);
131+
Mockito.when(listener.getTimeout()).thenReturn(-1);
132+
return listener;
133+
}
134+
124135
private Request submitRunning(final long seq) throws Exception {
125136
Mockito.doReturn(2).when(_agentMgr).getDirectAgentThreadCap();
126137
Mockito.doReturn(directAgentPool).when(_agentMgr).getDirectAgentPool();

‎server/src/main/java/com/cloud/usage/UsageServiceImpl.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,7 @@ private UsageJobResponse createUsageJobResponse(UsageJobVO job) {
566566
jobResponse.setScheduled(job.getScheduled());
567567
jobResponse.setStartDate(job.getStartDate());
568568
jobResponse.setEndDate(job.getEndDate());
569+
jobResponse.setExecutionTime(job.getExecTime());
569570
jobResponse.setSuccess(job.getSuccess());
570571
jobResponse.setHeartbeat(job.getHeartbeat());
571572
jobResponse.setObjectName("usagejobs");

‎ui/src/config/section/activity.js‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ export default {
2121
name: 'activity',
2222
title: 'label.activity',
2323
icon: 'AuditOutlined',
24-
permission: ['listEvents'],
2524
children: [
2625
{
2726
name: 'jobs',

0 commit comments

Comments
 (0)