mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Fix issues in VM Scheduler (#7782)
This commit is contained in:
parent
4eb110af73
commit
d25521e96f
@ -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);
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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() {
|
||||||
|
|||||||
@ -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(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user