Fix issues in VM Scheduler (#7782)

This commit is contained in:
Vishesh 2023-09-18 17:41:06 +05:30 committed by GitHub
parent 4eb110af73
commit d25521e96f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 47 additions and 63 deletions

View File

@ -127,7 +127,7 @@ public class VMScheduleManagerImpl extends MutualExclusiveIdsManagerBase impleme
return Transaction.execute((TransactionCallback<VMScheduleResponse>) status -> { return Transaction.execute((TransactionCallback<VMScheduleResponse>) status -> {
VMScheduleVO vmSchedule = vmScheduleDao.persist(new VMScheduleVO(cmd.getVmId(), finalDescription, cronExpression.toString(), timeZoneId, finalAction, finalStartDate, finalEndDate, cmd.getEnabled())); VMScheduleVO vmSchedule = vmScheduleDao.persist(new VMScheduleVO(cmd.getVmId(), finalDescription, cronExpression.toString(), timeZoneId, finalAction, finalStartDate, finalEndDate, cmd.getEnabled()));
vmScheduler.scheduleNextJob(vmSchedule); vmScheduler.scheduleNextJob(vmSchedule, new Date());
CallContext.current().setEventResourceId(vm.getId()); CallContext.current().setEventResourceId(vm.getId());
CallContext.current().setEventResourceType(ApiCommandResourceType.VirtualMachine); CallContext.current().setEventResourceType(ApiCommandResourceType.VirtualMachine);
return createResponse(vmSchedule); return createResponse(vmSchedule);

View File

@ -32,5 +32,5 @@ public interface VMScheduler extends Manager, Scheduler {
void updateScheduledJob(VMScheduleVO vmSchedule); void updateScheduledJob(VMScheduleVO vmSchedule);
Date scheduleNextJob(VMScheduleVO vmSchedule); Date scheduleNextJob(VMScheduleVO vmSchedule, Date timestamp);
} }

View File

@ -96,20 +96,11 @@ public class VMSchedulerImpl extends ManagerBase implements VMScheduler {
@Override @Override
public void updateScheduledJob(VMScheduleVO vmSchedule) { public void updateScheduledJob(VMScheduleVO vmSchedule) {
removeScheduledJobs(Longs.asList(vmSchedule.getId())); removeScheduledJobs(Longs.asList(vmSchedule.getId()));
scheduleNextJob(vmSchedule); scheduleNextJob(vmSchedule, new Date());
}
public Date scheduleNextJob(Long vmScheduleId) {
VMScheduleVO vmSchedule = vmScheduleDao.findById(vmScheduleId);
if (vmSchedule != null) {
return scheduleNextJob(vmSchedule);
}
LOGGER.debug(String.format("VM Schedule [id=%s] is removed. Not scheduling next job.", vmScheduleId));
return null;
} }
@Override @Override
public Date scheduleNextJob(VMScheduleVO vmSchedule) { public Date scheduleNextJob(VMScheduleVO vmSchedule, Date timestamp) {
if (!vmSchedule.getEnabled()) { if (!vmSchedule.getEnabled()) {
LOGGER.debug(String.format("VM Schedule [id=%s] for VM [id=%s] is disabled. Not scheduling next job.", vmSchedule.getUuid(), vmSchedule.getVmId())); LOGGER.debug(String.format("VM Schedule [id=%s] for VM [id=%s] is disabled. Not scheduling next job.", vmSchedule.getUuid(), vmSchedule.getVmId()));
return null; return null;
@ -127,7 +118,12 @@ public class VMSchedulerImpl extends ManagerBase implements VMScheduler {
return null; return null;
} }
ZonedDateTime now = ZonedDateTime.now(vmSchedule.getTimeZoneId()); ZonedDateTime now;
if (timestamp != null) {
now = ZonedDateTime.ofInstant(timestamp.toInstant(), vmSchedule.getTimeZoneId());
} else {
now = ZonedDateTime.now(vmSchedule.getTimeZoneId());
}
ZonedDateTime zonedStartDate = ZonedDateTime.ofInstant(startDate.toInstant(), vmSchedule.getTimeZoneId()); ZonedDateTime zonedStartDate = ZonedDateTime.ofInstant(startDate.toInstant(), vmSchedule.getTimeZoneId());
ZonedDateTime zonedEndDate = null; ZonedDateTime zonedEndDate = null;
if (endDate != null) { if (endDate != null) {
@ -178,8 +174,7 @@ public class VMSchedulerImpl extends ManagerBase implements VMScheduler {
// Adding 1 minute to currentTimestamp to ensure that // Adding 1 minute to currentTimestamp to ensure that
// jobs which were to be run at current time, doesn't cause issues // jobs which were to be run at current time, doesn't cause issues
currentTimestamp = DateUtils.addMinutes(new Date(), 1); currentTimestamp = DateUtils.addMinutes(new Date(), 1);
scheduleNextJobs(currentTimestamp);
scheduleNextJobs();
final TimerTask schedulerPollTask = new ManagedContextTimerTask() { final TimerTask schedulerPollTask = new ManagedContextTimerTask() {
@Override @Override
@ -193,7 +188,7 @@ public class VMSchedulerImpl extends ManagerBase implements VMScheduler {
}; };
vmSchedulerTimer = new Timer("VMSchedulerPollTask"); vmSchedulerTimer = new Timer("VMSchedulerPollTask");
vmSchedulerTimer.schedule(schedulerPollTask, 5000L, 60 * 1000L); vmSchedulerTimer.scheduleAtFixedRate(schedulerPollTask, 5000L, 60 * 1000L);
return true; return true;
} }
@ -207,7 +202,7 @@ public class VMSchedulerImpl extends ManagerBase implements VMScheduler {
try { try {
if (scanLock.lock(30)) { if (scanLock.lock(30)) {
try { try {
scheduleNextJobs(); scheduleNextJobs(currentTimestamp);
} finally { } finally {
scanLock.unlock(); scanLock.unlock();
} }
@ -236,10 +231,10 @@ public class VMSchedulerImpl extends ManagerBase implements VMScheduler {
} }
} }
private void scheduleNextJobs() { private void scheduleNextJobs(Date timestamp) {
for (final VMScheduleVO schedule : vmScheduleDao.listAllActiveSchedules()) { for (final VMScheduleVO schedule : vmScheduleDao.listAllActiveSchedules()) {
try { try {
scheduleNextJob(schedule); scheduleNextJob(schedule, timestamp);
} catch (Exception e) { } catch (Exception e) {
LOGGER.warn("Error in scheduling next job for schedule " + schedule.getUuid(), e); LOGGER.warn("Error in scheduling next job for schedule " + schedule.getUuid(), e);
} }

View File

@ -89,22 +89,22 @@ public class VMSchedulerImplTest {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
PowerMockito.mockStatic(ActionEventUtils.class); PowerMockito.mockStatic(ActionEventUtils.class);
Mockito.when(ActionEventUtils.onScheduledActionEvent(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString(), Mockito.when(ActionEventUtils.onScheduledActionEvent(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString(),
Mockito.anyString(), Mockito.anyLong(), Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyLong())).thenReturn(1L); Mockito.anyString(), Mockito.anyLong(), Mockito.anyString(), Mockito.anyBoolean(),
Mockito.anyLong()))
.thenReturn(1L);
Mockito.when(ActionEventUtils.onCompletedActionEvent(Mockito.anyLong(), Mockito.anyLong(), Mockito.any(), Mockito.when(ActionEventUtils.onCompletedActionEvent(Mockito.anyLong(), Mockito.anyLong(), Mockito.any(),
Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyString(), Mockito.anyBoolean(),
Mockito.anyString(), Mockito.anyString(),
Mockito.anyLong(), Mockito.anyString(), Mockito.anyLong())).thenReturn(1L); Mockito.anyLong(), Mockito.anyString(), Mockito.anyLong())).thenReturn(1L);
} }
private void prepareMocksForProcessJob(VirtualMachine vm, VMScheduledJob vmScheduledJob, VirtualMachine.State vmState, VMSchedule.Action action, Long executeJobReturnValue) { @Test
Mockito.when(vm.getState()).thenReturn(vmState); public void testProcessJobRunning() {
Mockito.when(vmScheduledJob.getAction()).thenReturn(action); executeProcessJobWithVMStateAndActionNonSkipped(VirtualMachine.State.Running, VMSchedule.Action.STOP);
executeProcessJobWithVMStateAndActionNonSkipped(VirtualMachine.State.Running, VMSchedule.Action.FORCE_STOP);
if (executeJobReturnValue != null) { executeProcessJobWithVMStateAndActionNonSkipped(VirtualMachine.State.Running, VMSchedule.Action.REBOOT);
Mockito.doReturn(executeJobReturnValue).when(vmScheduler).executeStartVMJob(Mockito.any(VirtualMachine.class), Mockito.anyLong()); executeProcessJobWithVMStateAndActionNonSkipped(VirtualMachine.State.Running, VMSchedule.Action.FORCE_REBOOT);
Mockito.doReturn(executeJobReturnValue).when(vmScheduler).executeStopVMJob(Mockito.any(VirtualMachine.class), Mockito.anyBoolean(), Mockito.anyLong()); executeProcessJobWithVMStateAndActionNonSkipped(VirtualMachine.State.Stopped, VMSchedule.Action.START);
Mockito.doReturn(executeJobReturnValue).when(vmScheduler).executeRebootVMJob(Mockito.any(VirtualMachine.class), Mockito.anyBoolean(), Mockito.anyLong());
}
} }
private void executeProcessJobWithVMStateAndActionNonSkipped(VirtualMachine.State state, VMSchedule.Action action) { private void executeProcessJobWithVMStateAndActionNonSkipped(VirtualMachine.State state, VMSchedule.Action action) {
@ -125,13 +125,20 @@ public class VMSchedulerImplTest {
Assert.assertEquals(expectedValue, jobId); Assert.assertEquals(expectedValue, jobId);
} }
@Test private void prepareMocksForProcessJob(VirtualMachine vm, VMScheduledJob vmScheduledJob,
public void testProcessJobRunning() { VirtualMachine.State vmState, VMSchedule.Action action,
executeProcessJobWithVMStateAndActionNonSkipped(VirtualMachine.State.Running, VMSchedule.Action.STOP); Long executeJobReturnValue) {
executeProcessJobWithVMStateAndActionNonSkipped(VirtualMachine.State.Running, VMSchedule.Action.FORCE_STOP); Mockito.when(vm.getState()).thenReturn(vmState);
executeProcessJobWithVMStateAndActionNonSkipped(VirtualMachine.State.Running, VMSchedule.Action.REBOOT); Mockito.when(vmScheduledJob.getAction()).thenReturn(action);
executeProcessJobWithVMStateAndActionNonSkipped(VirtualMachine.State.Running, VMSchedule.Action.FORCE_REBOOT);
executeProcessJobWithVMStateAndActionNonSkipped(VirtualMachine.State.Stopped, VMSchedule.Action.START); if (executeJobReturnValue != null) {
Mockito.doReturn(executeJobReturnValue).when(vmScheduler).executeStartVMJob(
Mockito.any(VirtualMachine.class), Mockito.anyLong());
Mockito.doReturn(executeJobReturnValue).when(vmScheduler).executeStopVMJob(
Mockito.any(VirtualMachine.class), Mockito.anyBoolean(), Mockito.anyLong());
Mockito.doReturn(executeJobReturnValue).when(vmScheduler).executeRebootVMJob(
Mockito.any(VirtualMachine.class), Mockito.anyBoolean(), Mockito.anyLong());
}
} }
@Test @Test
@ -172,7 +179,7 @@ public class VMSchedulerImplTest {
Mockito.when(vmSchedule.getStartDate()).thenReturn(startDate); Mockito.when(vmSchedule.getStartDate()).thenReturn(startDate);
Mockito.when(userVmManager.getUserVm(Mockito.anyLong())).thenReturn(vm); Mockito.when(userVmManager.getUserVm(Mockito.anyLong())).thenReturn(vm);
Mockito.when(vmScheduledJobDao.persist(Mockito.any())).thenThrow(EntityExistsException.class); Mockito.when(vmScheduledJobDao.persist(Mockito.any())).thenThrow(EntityExistsException.class);
Date actualScheduledTime = vmScheduler.scheduleNextJob(vmSchedule); Date actualScheduledTime = vmScheduler.scheduleNextJob(vmSchedule, new Date());
Assert.assertEquals(expectedScheduledTime, actualScheduledTime); Assert.assertEquals(expectedScheduledTime, actualScheduledTime);
} }
@ -190,7 +197,7 @@ public class VMSchedulerImplTest {
Mockito.when(vmSchedule.getTimeZoneId()).thenReturn(TimeZone.getTimeZone("UTC").toZoneId()); Mockito.when(vmSchedule.getTimeZoneId()).thenReturn(TimeZone.getTimeZone("UTC").toZoneId());
Mockito.when(vmSchedule.getStartDate()).thenReturn(startDate); Mockito.when(vmSchedule.getStartDate()).thenReturn(startDate);
Mockito.when(userVmManager.getUserVm(Mockito.anyLong())).thenReturn(vm); Mockito.when(userVmManager.getUserVm(Mockito.anyLong())).thenReturn(vm);
Date actualScheduledTime = vmScheduler.scheduleNextJob(vmSchedule); Date actualScheduledTime = vmScheduler.scheduleNextJob(vmSchedule, new Date());
Assert.assertEquals(expectedScheduledTime, actualScheduledTime); Assert.assertEquals(expectedScheduledTime, actualScheduledTime);
} }
@ -226,7 +233,7 @@ public class VMSchedulerImplTest {
expectedScheduledTime = DateUtils.addDays(expectedScheduledTime, 1); expectedScheduledTime = DateUtils.addDays(expectedScheduledTime, 1);
} }
Date actualScheduledTime = vmScheduler.scheduleNextJob(vmSchedule); Date actualScheduledTime = vmScheduler.scheduleNextJob(vmSchedule, new Date());
Assert.assertEquals(expectedScheduledTime, actualScheduledTime); Assert.assertEquals(expectedScheduledTime, actualScheduledTime);
} }
@ -242,7 +249,7 @@ public class VMSchedulerImplTest {
Mockito.when(vmSchedule.getTimeZoneId()).thenReturn(TimeZone.getTimeZone("UTC").toZoneId()); Mockito.when(vmSchedule.getTimeZoneId()).thenReturn(TimeZone.getTimeZone("UTC").toZoneId());
Mockito.when(vmSchedule.getStartDate()).thenReturn(DateUtils.addDays(now, -1)); Mockito.when(vmSchedule.getStartDate()).thenReturn(DateUtils.addDays(now, -1));
Mockito.when(userVmManager.getUserVm(Mockito.anyLong())).thenReturn(vm); Mockito.when(userVmManager.getUserVm(Mockito.anyLong())).thenReturn(vm);
Date actualScheduledTime = vmScheduler.scheduleNextJob(vmSchedule); Date actualScheduledTime = vmScheduler.scheduleNextJob(vmSchedule, new Date());
Assert.assertEquals(expectedScheduledTime, actualScheduledTime); Assert.assertEquals(expectedScheduledTime, actualScheduledTime);
} }
@ -277,7 +284,7 @@ public class VMSchedulerImplTest {
expectedScheduledTime = DateUtils.addDays(expectedScheduledTime, 1); expectedScheduledTime = DateUtils.addDays(expectedScheduledTime, 1);
} }
Date actualScheduledTime = vmScheduler.scheduleNextJob(vmSchedule); Date actualScheduledTime = vmScheduler.scheduleNextJob(vmSchedule, new Date());
Assert.assertEquals(expectedScheduledTime, actualScheduledTime); Assert.assertEquals(expectedScheduledTime, actualScheduledTime);
} }
@ -286,7 +293,7 @@ public class VMSchedulerImplTest {
VMScheduleVO vmSchedule = Mockito.mock(VMScheduleVO.class); VMScheduleVO vmSchedule = Mockito.mock(VMScheduleVO.class);
Mockito.when(vmSchedule.getEndDate()).thenReturn(DateUtils.addMinutes(new Date(), -5)); Mockito.when(vmSchedule.getEndDate()).thenReturn(DateUtils.addMinutes(new Date(), -5));
Mockito.when(vmSchedule.getEnabled()).thenReturn(true); Mockito.when(vmSchedule.getEnabled()).thenReturn(true);
Date actualDate = vmScheduler.scheduleNextJob(vmSchedule); Date actualDate = vmScheduler.scheduleNextJob(vmSchedule, new Date());
Assert.assertNull(actualDate); Assert.assertNull(actualDate);
} }
@ -294,28 +301,10 @@ public class VMSchedulerImplTest {
public void testScheduleNextJobScheduleDisabled() { public void testScheduleNextJobScheduleDisabled() {
VMScheduleVO vmSchedule = Mockito.mock(VMScheduleVO.class); VMScheduleVO vmSchedule = Mockito.mock(VMScheduleVO.class);
Mockito.when(vmSchedule.getEnabled()).thenReturn(false); Mockito.when(vmSchedule.getEnabled()).thenReturn(false);
Date actualDate = vmScheduler.scheduleNextJob(vmSchedule); Date actualDate = vmScheduler.scheduleNextJob(vmSchedule, new Date());
Assert.assertNull(actualDate); Assert.assertNull(actualDate);
} }
@Test
public void testScheduleNextJobScheduleIdNotExists() {
long vmScheduleId = 1;
Mockito.when(vmScheduleDao.findById(vmScheduleId)).thenReturn(null);
Date actualDate = vmScheduler.scheduleNextJob(vmScheduleId);
Assert.assertNull(actualDate);
}
@Test
public void testScheduleNextJobScheduleIdExists() {
long vmScheduleId = 1;
VMScheduleVO vmScheduleVO = Mockito.mock(VMScheduleVO.class);
Date date = Mockito.mock(Date.class);
Mockito.when(vmScheduleDao.findById(vmScheduleId)).thenReturn(vmScheduleVO);
Mockito.doReturn(date).when(vmScheduler).scheduleNextJob(vmScheduleVO);
Date actualDate = vmScheduler.scheduleNextJob(vmScheduleId);
Assert.assertEquals(date, actualDate);
}
@Test @Test
public void testExecuteJobs() { public void testExecuteJobs() {

View File

@ -571,7 +571,7 @@ class TestVMSchedule(cloudstackTestCase):
stop_vmschedule.delete(self.apiclient) stop_vmschedule.delete(self.apiclient)
# To ensure that all vm schedules have been deleted and all of their jobs have been completed # To ensure that all vm schedules have been deleted and all of their jobs have been completed
time.sleep(15) time.sleep(60)
# Verify VM Schedule is deleted # Verify VM Schedule is deleted
self.assertEqual( self.assertEqual(