You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by da...@apache.org on 2026/10/07 13:57:01 UTC
(cloudstack) branch bulk-power-state-update-time-gmt created (now 5da21becf1e)
This is an automated email from the ASF dual-hosted git repository.
DaanHoogland pushed a change to branch bulk-power-state-update-time-gmt
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
at 5da21becf1e update powerstate timestamps to the right timezone
This branch includes the following new commits:
new 5da21becf1e update powerstate timestamps to the right timezone
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(cloudstack) 01/01: update powerstate timestamps to the right timezone
Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
DaanHoogland pushed a commit to branch bulk-power-state-update-time-gmt
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
commit 5da21becf1ea74d38de9e1857bc67e9325c7c965
Author: Daan Hoogland <da...@apache.org>
AuthorDate: Wed Oct 7 15:56:32 2026 +0200
update powerstate timestamps to the right timezone
---
.../java/com/cloud/vm/dao/VMInstanceDaoImpl.java | 4 +-
.../com/cloud/vm/dao/VMInstanceDaoImplTest.java | 55 ++++++++++++++++++++++
2 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java
index 518bc3cf497..232a99211a1 100755
--- a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java
@@ -19,6 +19,7 @@ package com.cloud.vm.dao;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
+import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
@@ -1037,7 +1038,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem
return notUpdated;
}
StringBuilder sql = new StringBuilder("UPDATE `cloud`.`vm_instance` SET " +
- "`power_host` = ?, `power_state_update_time` = now(), `power_state` = CASE ");
+ "`power_host` = ?, `power_state_update_time` = ?, `power_state` = CASE ");
updateCounts.keySet().forEach(key -> {
sql.append("WHEN id = ").append(key).append(" THEN '").append(instancePowerStates.get(key)).append("' ");
});
@@ -1052,6 +1053,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem
TransactionLegacy txn = TransactionLegacy.currentTxn();
try (PreparedStatement pstmt = txn.prepareAutoCloseStatement(sql.toString())) {
pstmt.setLong(1, powerHostId);
+ pstmt.setTimestamp(2, new Timestamp(DateUtil.currentGMTTime().getTime()), gmtCalendar());
pstmt.executeUpdate();
} catch (SQLException e) {
logger.error("Unable to execute update power states SQL from VMs {} due to: {}",
diff --git a/engine/schema/src/test/java/com/cloud/vm/dao/VMInstanceDaoImplTest.java b/engine/schema/src/test/java/com/cloud/vm/dao/VMInstanceDaoImplTest.java
index 5f8b2dd90ec..5317f3a6689 100644
--- a/engine/schema/src/test/java/com/cloud/vm/dao/VMInstanceDaoImplTest.java
+++ b/engine/schema/src/test/java/com/cloud/vm/dao/VMInstanceDaoImplTest.java
@@ -20,19 +20,26 @@ package com.cloud.vm.dao;
import static com.cloud.vm.VirtualMachine.State.Running;
import static com.cloud.vm.VirtualMachine.State.Stopped;
import static com.cloud.vm.dao.VMInstanceDaoImpl.MAX_CONSECUTIVE_SAME_STATE_UPDATE_COUNT;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import java.sql.PreparedStatement;
+import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
import com.cloud.host.dao.HostDao;
import org.joda.time.DateTime;
@@ -40,8 +47,10 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
+import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
@@ -50,6 +59,7 @@ import com.cloud.utils.Pair;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.TransactionLegacy;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import org.mockito.junit.MockitoJUnitRunner;
@@ -210,6 +220,51 @@ public class VMInstanceDaoImplTest {
assertTrue(result);
}
+ @Test
+ public void testUpdatePowerStatesBindsGmtUpdateTimeInsteadOfDbNow() throws Exception {
+ TimeZone defaultTimeZone = TimeZone.getDefault();
+ try {
+ for (String timeZone : List.of("UTC", "Europe/Amsterdam", "America/New_York", "Asia/Kolkata", "Pacific/Auckland")) {
+ TimeZone.setDefault(TimeZone.getTimeZone(timeZone));
+ verifyBulkUpdatePowerStatesBindsGmtUpdateTime(timeZone);
+ }
+ } finally {
+ TimeZone.setDefault(defaultTimeZone);
+ }
+ }
+
+ private void verifyBulkUpdatePowerStatesBindsGmtUpdateTime(String timeZone) throws Exception {
+ VMInstanceVO instance = Mockito.mock(VMInstanceVO.class);
+ when(instance.getId()).thenReturn(1L);
+ when(instance.getPowerState()).thenReturn(VirtualMachine.PowerState.PowerOn);
+ doReturn(List.of(instance)).when(vmInstanceDao).listSelectPowerStateByIds(any());
+ TransactionLegacy txn = Mockito.mock(TransactionLegacy.class);
+ PreparedStatement pstmt = Mockito.mock(PreparedStatement.class);
+ ArgumentCaptor<String> sqlCaptor = ArgumentCaptor.forClass(String.class);
+ when(txn.prepareAutoCloseStatement(sqlCaptor.capture())).thenReturn(pstmt);
+ ArgumentCaptor<Timestamp> timeCaptor = ArgumentCaptor.forClass(Timestamp.class);
+ ArgumentCaptor<Calendar> calendarCaptor = ArgumentCaptor.forClass(Calendar.class);
+
+ long before = System.currentTimeMillis();
+ Map<Long, VirtualMachine.PowerState> notUpdated;
+ try (MockedStatic<TransactionLegacy> ignored = Mockito.mockStatic(TransactionLegacy.class)) {
+ ignored.when(TransactionLegacy::currentTxn).thenReturn(txn);
+ notUpdated = vmInstanceDao.updatePowerState(Map.of(1L, VirtualMachine.PowerState.PowerOff), 2L, new Date());
+ }
+ long after = System.currentTimeMillis();
+
+ assertTrue(timeZone, notUpdated.isEmpty());
+ String sql = sqlCaptor.getValue();
+ assertFalse(timeZone, sql.toLowerCase().contains("now()"));
+ assertTrue(timeZone, sql.contains("`power_state_update_time` = ?"));
+ verify(pstmt).setLong(1, 2L);
+ verify(pstmt).setTimestamp(eq(2), timeCaptor.capture(), calendarCaptor.capture());
+ verify(pstmt).executeUpdate();
+ long written = timeCaptor.getValue().getTime();
+ assertTrue(timeZone, written >= before && written <= after);
+ assertEquals(timeZone, "GMT", calendarCaptor.getValue().getTimeZone().getID());
+ }
+
@Test
public void testSearchRemovedByRemoveDate() {
SearchBuilder<VMInstanceVO> sb = Mockito.mock(SearchBuilder.class);