Updated Branches: refs/heads/vmsync-rebase [created] d72af4bd0
Rebase PowerState from old vmsync branch Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/d72af4bd Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/d72af4bd Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/d72af4bd Branch: refs/heads/vmsync-rebase Commit: d72af4bd0fa9e44b38276379a6f8c22d95ad05dd Parents: 29d9228 Author: Kelven Yang <[email protected]> Authored: Mon Oct 14 17:24:55 2013 -0700 Committer: Kelven Yang <[email protected]> Committed: Mon Oct 14 17:24:55 2013 -0700 ---------------------------------------------------------------------- .../cloud/agent/api/HostVmStateReportEntry.java | 41 ++++++ api/src/com/cloud/vm/VirtualMachine.java | 6 + .../cloud/agent/api/StartupRoutingCommand.java | 46 +++---- .../src/com/cloud/vm/VirtualMachineManager.java | 4 + .../cloud/vm/VirtualMachinePowerStateSync.java | 32 +++++ .../vm/VirtualMachinePowerStateSyncImpl.java | 125 +++++++++++++++++++ .../schema/src/com/cloud/vm/VMInstanceVO.java | 50 +++++++- .../src/com/cloud/vm/dao/VMInstanceDao.java | 5 + .../src/com/cloud/vm/dao/VMInstanceDaoImpl.java | 58 +++++++++ 9 files changed, 335 insertions(+), 32 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d72af4bd/api/src/com/cloud/agent/api/HostVmStateReportEntry.java ---------------------------------------------------------------------- diff --git a/api/src/com/cloud/agent/api/HostVmStateReportEntry.java b/api/src/com/cloud/agent/api/HostVmStateReportEntry.java new file mode 100644 index 0000000..7bcb50f --- /dev/null +++ b/api/src/com/cloud/agent/api/HostVmStateReportEntry.java @@ -0,0 +1,41 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.agent.api; + +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.PowerState; + +public class HostVmStateReportEntry { + VirtualMachine.PowerState state; + String host; + + public HostVmStateReportEntry() { + } + + public HostVmStateReportEntry(PowerState state, String host) { + this.state = state; + this.host = host; + } + + public PowerState getState() { + return state; + } + + public String getHost() { + return host; + } +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d72af4bd/api/src/com/cloud/vm/VirtualMachine.java ---------------------------------------------------------------------- diff --git a/api/src/com/cloud/vm/VirtualMachine.java b/api/src/com/cloud/vm/VirtualMachine.java index 0a968bc..0d56826 100755 --- a/api/src/com/cloud/vm/VirtualMachine.java +++ b/api/src/com/cloud/vm/VirtualMachine.java @@ -206,6 +206,12 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I return _isUsedBySystem; } } + + public enum PowerState { + PowerUnknown, + PowerOn, + PowerOff, + } /** * @return The name of the vm instance used by the cloud stack to uniquely http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d72af4bd/core/src/com/cloud/agent/api/StartupRoutingCommand.java ---------------------------------------------------------------------- diff --git a/core/src/com/cloud/agent/api/StartupRoutingCommand.java b/core/src/com/cloud/agent/api/StartupRoutingCommand.java index 5961ab0..7cfc941 100755 --- a/core/src/com/cloud/agent/api/StartupRoutingCommand.java +++ b/core/src/com/cloud/agent/api/StartupRoutingCommand.java @@ -23,32 +23,16 @@ import com.cloud.host.Host; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.Networks.RouterPrivateIpStrategy; import com.cloud.utils.Pair; -import com.cloud.vm.VirtualMachine.State; +import com.cloud.vm.VirtualMachine.PowerState; public class StartupRoutingCommand extends StartupCommand { - public static class VmState { - State state; - String host; - public VmState() { - } - public VmState(State state, String host) { - this.state = state; - this.host = host; - } - public State getState() { - return state; - } - public String getHost() { - return host; - } - } int cpus; long speed; long memory; long dom0MinMemory; boolean poolSync; - Map<String, VmState> vms; - HashMap<String, Pair<String, State>> _clusterVMStates; + Map<String, HostVmStateReportEntry> vms; + HashMap<String, Pair<String, PowerState>> _clusterVMStates; String caps; String pool; HypervisorType hypervisorType; @@ -69,7 +53,7 @@ public class StartupRoutingCommand extends StartupCommand { String caps, HypervisorType hypervisorType, RouterPrivateIpStrategy privIpStrategy, - Map<String, VmState> vms) { + Map<String, HostVmStateReportEntry> vms) { this(cpus, speed, memory, dom0MinMemory, caps, hypervisorType, vms); getHostDetails().put(RouterPrivateIpStrategy.class.getCanonicalName(), privIpStrategy.toString()); } @@ -81,7 +65,7 @@ public class StartupRoutingCommand extends StartupCommand { String caps, HypervisorType hypervisorType, RouterPrivateIpStrategy privIpStrategy) { -this(cpus, speed, memory, dom0MinMemory, caps, hypervisorType, new HashMap<String,String>(), new HashMap<String, VmState>()); +this(cpus, speed, memory, dom0MinMemory, caps, hypervisorType, new HashMap<String,String>(), new HashMap<String, HostVmStateReportEntry>()); getHostDetails().put(RouterPrivateIpStrategy.class.getCanonicalName(), privIpStrategy.toString()); } @@ -92,7 +76,7 @@ getHostDetails().put(RouterPrivateIpStrategy.class.getCanonicalName(), privIpStr final String caps, final HypervisorType hypervisorType, final Map<String, String> hostDetails, - Map<String, VmState> vms) { + Map<String, HostVmStateReportEntry> vms) { super(Host.Type.Routing); this.cpus = cpus; this.speed = speed; @@ -107,29 +91,29 @@ getHostDetails().put(RouterPrivateIpStrategy.class.getCanonicalName(), privIpStr public StartupRoutingCommand(int cpus2, long speed2, long memory2, long dom0MinMemory2, String caps2, HypervisorType hypervisorType2, - Map<String, VmState> vms2) { + Map<String, HostVmStateReportEntry> vms2) { this(cpus2, speed2, memory2, dom0MinMemory2, caps2, hypervisorType2, new HashMap<String,String>(), vms2); } - public StartupRoutingCommand(int cpus, long speed, long memory, long dom0MinMemory, final String caps, final HypervisorType hypervisorType, final Map<String, String> hostDetails, Map<String, VmState> vms, String hypervisorVersion) { + public StartupRoutingCommand(int cpus, long speed, long memory, long dom0MinMemory, final String caps, final HypervisorType hypervisorType, final Map<String, String> hostDetails, Map<String, HostVmStateReportEntry> vms, String hypervisorVersion) { this(cpus, speed, memory, dom0MinMemory, caps, hypervisorType, hostDetails, vms); this.hypervisorVersion = hypervisorVersion; } - public void setChanges(Map<String, VmState> vms) { + public void setChanges(Map<String, HostVmStateReportEntry> vms) { this.vms = vms; } - public void setStateChanges(Map<String, State> vms) { + public void setStateChanges(Map<String, PowerState> vms) { for( String vm_name : vms.keySet() ) { if( this.vms == null ) { - this.vms = new HashMap<String, VmState>(); + this.vms = new HashMap<String, HostVmStateReportEntry>(); } - this.vms.put(vm_name, new VmState(vms.get(vm_name), null)); + this.vms.put(vm_name, new HostVmStateReportEntry(vms.get(vm_name), null)); } } - public void setClusterVMStateChanges(HashMap<String, Pair<String, State>> allStates){ + public void setClusterVMStateChanges(HashMap<String, Pair<String, PowerState>> allStates){ _clusterVMStates = allStates; } @@ -153,11 +137,11 @@ getHostDetails().put(RouterPrivateIpStrategy.class.getCanonicalName(), privIpStr return dom0MinMemory; } - public Map<String, VmState> getVmStates() { + public Map<String, HostVmStateReportEntry> getVmStates() { return vms; } - public HashMap<String, Pair<String, State>> getClusterVMStateChanges() { + public HashMap<String, Pair<String, PowerState>> getClusterVMStateChanges() { return _clusterVMStates; } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d72af4bd/engine/api/src/com/cloud/vm/VirtualMachineManager.java ---------------------------------------------------------------------- diff --git a/engine/api/src/com/cloud/vm/VirtualMachineManager.java b/engine/api/src/com/cloud/vm/VirtualMachineManager.java index afac6f3..9c76236 100644 --- a/engine/api/src/com/cloud/vm/VirtualMachineManager.java +++ b/engine/api/src/com/cloud/vm/VirtualMachineManager.java @@ -46,6 +46,10 @@ import com.cloud.utils.fsm.NoTransitionException; * Manages allocating resources to vms. */ public interface VirtualMachineManager extends Manager { + + public interface Topics { + public static final String VM_POWER_STATE = "vm.powerstate"; + } /** * Allocates a new virtual machine instance in the CloudStack DB. This http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d72af4bd/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSync.java ---------------------------------------------------------------------- diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSync.java b/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSync.java new file mode 100644 index 0000000..7a23ddd --- /dev/null +++ b/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSync.java @@ -0,0 +1,32 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.vm; + +import java.util.Map; + +import com.cloud.agent.api.HostVmStateReportEntry; +import com.cloud.vm.VirtualMachine.PowerState; + +public interface VirtualMachinePowerStateSync { + + void resetHostSyncState(long hostId); + + void processHostVmStateReport(long hostId, Map<String, HostVmStateReportEntry> report); + + // to adapt legacy ping report + void processHostVmStatePingReport(long hostId, Map<String, PowerState> report); +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d72af4bd/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java ---------------------------------------------------------------------- diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java b/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java new file mode 100644 index 0000000..9c47727 --- /dev/null +++ b/engine/orchestration/src/com/cloud/vm/VirtualMachinePowerStateSyncImpl.java @@ -0,0 +1,125 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.vm; + +import java.util.HashMap; +import java.util.Map; + +import javax.inject.Inject; + +import org.apache.log4j.Logger; + +import org.apache.cloudstack.framework.messagebus.MessageBus; +import org.apache.cloudstack.framework.messagebus.PublishScope; + +import com.cloud.agent.api.HostVmStateReportEntry; +import com.cloud.vm.VirtualMachine.PowerState; +import com.cloud.vm.dao.VMInstanceDao; + +public class VirtualMachinePowerStateSyncImpl implements VirtualMachinePowerStateSync { + private static final Logger s_logger = Logger.getLogger(VirtualMachinePowerStateSyncImpl.class); + + @Inject MessageBus _messageBus; + @Inject VMInstanceDao _instanceDao; + @Inject VirtualMachineManager _vmMgr; + + public VirtualMachinePowerStateSyncImpl() { + } + + @Override + public void resetHostSyncState(long hostId) { + s_logger.info("Reset VM power state sync for host: " + hostId); + _instanceDao.resetHostPowerStateTracking(hostId); + } + + @Override + public void processHostVmStateReport(long hostId, Map<String, HostVmStateReportEntry> report) { + if(s_logger.isDebugEnabled()) + s_logger.debug("Process host VM state report from ping process. host: " + hostId); + + Map<Long, VirtualMachine.PowerState> translatedInfo = convertToInfos(report); + processReport(hostId, translatedInfo); + } + + @Override + public void processHostVmStatePingReport(long hostId, Map<String, PowerState> report) { + if(s_logger.isDebugEnabled()) + s_logger.debug("Process host VM state report from ping process. host: " + hostId); + + Map<Long, VirtualMachine.PowerState> translatedInfo = convertHostPingInfos(report); + processReport(hostId, translatedInfo); + } + + private void processReport(long hostId, Map<Long, VirtualMachine.PowerState> translatedInfo) { + + for(Map.Entry<Long, VirtualMachine.PowerState> entry : translatedInfo.entrySet()) { + + if(s_logger.isDebugEnabled()) + s_logger.debug("VM state report. host: " + hostId + ", vm id: " + entry.getKey() + ", power state: " + entry.getValue()); + + if(_instanceDao.updatePowerState(entry.getKey(), hostId, entry.getValue())) { + + if(s_logger.isDebugEnabled()) + s_logger.debug("VM state report is updated. host: " + hostId + ", vm id: " + entry.getKey() + ", power state: " + entry.getValue()); + + _messageBus.publish(null, VirtualMachineManager.Topics.VM_POWER_STATE, PublishScope.GLOBAL, entry.getKey()); + } + } + } + + private Map<Long, VirtualMachine.PowerState> convertHostPingInfos(Map<String, PowerState> states) { + final HashMap<Long, VirtualMachine.PowerState> map = new HashMap<Long, VirtualMachine.PowerState>(); + if (states == null) { + return map; + } + + for (Map.Entry<String, PowerState> entry : states.entrySet()) { + VMInstanceVO vm = findVM(entry.getKey()); + if(vm != null) { + map.put(vm.getId(), entry.getValue()); + break; + } else { + s_logger.info("Unable to find matched VM in CloudStack DB. name: " + entry.getKey()); + } + } + + return map; + } + + private Map<Long, VirtualMachine.PowerState> convertToInfos(Map<String, HostVmStateReportEntry> states) { + final HashMap<Long, VirtualMachine.PowerState> map = new HashMap<Long, VirtualMachine.PowerState>(); + if (states == null) { + return map; + } + + for (Map.Entry<String, HostVmStateReportEntry> entry : states.entrySet()) { + VMInstanceVO vm = findVM(entry.getKey()); + if(vm != null) { + map.put(vm.getId(), entry.getValue().getState()); + break; + } else { + s_logger.info("Unable to find matched VM in CloudStack DB. name: " + entry.getKey()); + } + } + + return map; + } + + private VMInstanceVO findVM(String vmName) { + return _instanceDao.findVMByInstanceName(vmName); + } +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d72af4bd/engine/schema/src/com/cloud/vm/VMInstanceVO.java ---------------------------------------------------------------------- diff --git a/engine/schema/src/com/cloud/vm/VMInstanceVO.java b/engine/schema/src/com/cloud/vm/VMInstanceVO.java index 8cf7fd0..faa7879 100644 --- a/engine/schema/src/com/cloud/vm/VMInstanceVO.java +++ b/engine/schema/src/com/cloud/vm/VMInstanceVO.java @@ -162,6 +162,23 @@ public class VMInstanceVO implements VirtualMachine, FiniteStateObject<State, Vi @Column(name="disk_offering_id") protected Long diskOfferingId; + + // + // Power state for VM state sync + // + @Enumerated(value=EnumType.STRING) + @Column(name="power_state", updatable=true) + protected PowerState powerState; + + @Column(name="power_state_update_time", updatable=true, nullable=false) + @Temporal(value=TemporalType.TIMESTAMP) + protected Date powerStateUpdateTime; + + @Column(name="power_state_update_count", updatable=true) + protected int powerStateUpdateCount; + + @Column(name="power_host", updatable=true) + protected Long powerHostId; public VMInstanceVO(long id, long serviceOfferingId, @@ -500,5 +517,36 @@ public class VMInstanceVO implements VirtualMachine, FiniteStateObject<State, Vi public Boolean isDynamicallyScalable() { return this.dynamicallyScalable; } - + + public VirtualMachine.PowerState getPowerState() { + return powerState; + } + + public void setPowerState(PowerState powerState) { + this.powerState = powerState; + } + + public Date getPowerStateUpdateTime() { + return powerStateUpdateTime; + } + + public void setPowerStateUpdateTime(Date updateTime) { + powerStateUpdateTime = updateTime; + } + + public int getPowerStateUpdateCount() { + return powerStateUpdateCount; + } + + public void setPowerStateUpdateCount(int count) { + powerStateUpdateCount = count; + } + + public Long getPowerHostId() { + return powerHostId; + } + + public void setPowerHostId(Long hostId) { + powerHostId = hostId; + } } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d72af4bd/engine/schema/src/com/cloud/vm/dao/VMInstanceDao.java ---------------------------------------------------------------------- diff --git a/engine/schema/src/com/cloud/vm/dao/VMInstanceDao.java b/engine/schema/src/com/cloud/vm/dao/VMInstanceDao.java index 2fe8140..938f99b 100644 --- a/engine/schema/src/com/cloud/vm/dao/VMInstanceDao.java +++ b/engine/schema/src/com/cloud/vm/dao/VMInstanceDao.java @@ -122,4 +122,9 @@ public interface VMInstanceDao extends GenericDao<VMInstanceVO, Long>, StateDao< List<VMInstanceVO> listStartingWithNoHostId(); + boolean updatePowerState(long instanceId, long powerHostId, VirtualMachine.PowerState powerState); + + void resetVmPowerStateTracking(long instanceId); + + void resetHostPowerStateTracking(long hostId); } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d72af4bd/engine/schema/src/com/cloud/vm/dao/VMInstanceDaoImpl.java ---------------------------------------------------------------------- diff --git a/engine/schema/src/com/cloud/vm/dao/VMInstanceDaoImpl.java b/engine/schema/src/com/cloud/vm/dao/VMInstanceDaoImpl.java index cf8e0a8..5256c35 100644 --- a/engine/schema/src/com/cloud/vm/dao/VMInstanceDaoImpl.java +++ b/engine/schema/src/com/cloud/vm/dao/VMInstanceDaoImpl.java @@ -37,6 +37,7 @@ import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.server.ResourceTag.TaggedResourceType; import com.cloud.tags.dao.ResourceTagDao; +import com.cloud.utils.DateUtil; import com.cloud.utils.Pair; import com.cloud.utils.db.Attribute; import com.cloud.utils.db.DB; @@ -63,6 +64,7 @@ import com.cloud.vm.VirtualMachine.Type; public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implements VMInstanceDao { public static final Logger s_logger = Logger.getLogger(VMInstanceDaoImpl.class); + private static final int MAX_CONSECUTIVE_SAME_STATE_UPDATE_COUNT = 3; protected SearchBuilder<VMInstanceVO> VMClusterSearch; protected SearchBuilder<VMInstanceVO> LHVMClusterSearch; @@ -680,4 +682,60 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem return listBy(sc); } + @Override @DB + public boolean updatePowerState(long instanceId, long powerHostId, VirtualMachine.PowerState powerState) { + boolean needToUpdate = false; + Transaction txn = Transaction.currentTxn(); + txn.start(); + + VMInstanceVO instance = findById(instanceId); + if(instance != null) { + Long savedPowerHostId = instance.getPowerHostId(); + if(instance.getPowerState() != powerState || savedPowerHostId == null || savedPowerHostId.longValue() != powerHostId) { + instance.setPowerState(powerState); + instance.setPowerHostId(powerHostId); + instance.setPowerStateUpdateCount(1); + instance.setPowerStateUpdateTime(DateUtil.currentGMTTime()); + needToUpdate = true; + update(instanceId, instance); + } else { + // to reduce DB updates, consecutive same state update for more than 3 times + if(instance.getPowerStateUpdateCount() < MAX_CONSECUTIVE_SAME_STATE_UPDATE_COUNT) { + instance.setPowerStateUpdateCount(instance.getPowerStateUpdateCount() + 1); + instance.setPowerStateUpdateTime(DateUtil.currentGMTTime()); + needToUpdate = true; + update(instanceId, instance); + } + } + } + + txn.commit(); + return needToUpdate; + } + + @Override @DB + public void resetVmPowerStateTracking(long instanceId) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + VMInstanceVO instance = findById(instanceId); + if(instance != null) { + instance.setPowerStateUpdateCount(0); + instance.setPowerStateUpdateTime(DateUtil.currentGMTTime()); + update(instanceId, instance); + } + + txn.commit(); + } + + @Override @DB + public void resetHostPowerStateTracking(long hostId) { + SearchCriteria<VMInstanceVO> sc = createSearchCriteria(); + sc.addAnd("powerHostId", SearchCriteria.Op.EQ, hostId); + + VMInstanceVO instance = this.createForUpdate(); + instance.setPowerStateUpdateCount(0); + instance.setPowerStateUpdateTime(DateUtil.currentGMTTime()); + + this.update(instance, sc); + } }
