From 8ec6d0471cbe77d9f8a0776dae9e7452f41d2324 Mon Sep 17 00:00:00 2001 From: Damodar Date: Thu, 9 Oct 2014 11:52:28 +0530 Subject: [PATCH] CLOUDSTACK-7648: There are new VM State Machine changes introduced which were missed to capture the usage events (cherry picked from commit 50185b7c3a1fd26e9a8635c28cee70fda32d3fc5) Signed-off-by: Rohit Yadav Conflicts: plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalManagerImpl.java server/src/com/cloud/capacity/CapacityManagerImpl.java server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java --- api/src/com/cloud/vm/VirtualMachine.java | 103 +++++++------ .../cloud/network/NetworkStateListener.java | 12 +- .../manager/BaremetalManagerImpl.java | 11 +- .../network/ovs/OvsTunnelManagerImpl.java | 32 ++-- .../cloud/capacity/CapacityManagerImpl.java | 6 +- .../deploy/DeploymentPlanningManagerImpl.java | 5 +- .../VirtualNetworkApplianceManagerImpl.java | 6 +- .../security/SecurityGroupManagerImpl.java | 46 +++--- .../listener/SnapshotStateListener.java | 9 +- .../storage/listener/VolumeStateListener.java | 9 +- .../src/com/cloud/vm/UserVmStateListener.java | 57 +++---- .../affinity/AffinityGroupServiceImpl.java | 4 +- .../com/cloud/utils/fsm/StateListener.java | 17 +-- .../com/cloud/utils/fsm/StateMachine2.java | 142 ++++++++++++++---- 14 files changed, 287 insertions(+), 172 deletions(-) diff --git a/api/src/com/cloud/vm/VirtualMachine.java b/api/src/com/cloud/vm/VirtualMachine.java index 34387ebea8f..99152d65fd1 100755 --- a/api/src/com/cloud/vm/VirtualMachine.java +++ b/api/src/com/cloud/vm/VirtualMachine.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.vm; +import java.util.Arrays; import java.util.Date; import java.util.Map; @@ -26,6 +27,8 @@ import org.apache.cloudstack.api.InternalIdentity; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.utils.fsm.StateMachine2; +import com.cloud.utils.fsm.StateMachine2.Transition; +import com.cloud.utils.fsm.StateMachine2.Transition.Impact; import com.cloud.utils.fsm.StateObject; /** @@ -75,63 +78,63 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I protected static final StateMachine2 s_fsm = new StateMachine2(); static { - s_fsm.addTransition(State.Stopped, VirtualMachine.Event.StartRequested, State.Starting); - s_fsm.addTransition(State.Stopped, VirtualMachine.Event.DestroyRequested, State.Destroyed); - s_fsm.addTransition(State.Stopped, VirtualMachine.Event.StopRequested, State.Stopped); - s_fsm.addTransition(State.Stopped, VirtualMachine.Event.AgentReportStopped, State.Stopped); + s_fsm.addTransition(new Transition(State.Stopped, VirtualMachine.Event.StartRequested, State.Starting, null)); + s_fsm.addTransition(new Transition(State.Stopped, VirtualMachine.Event.DestroyRequested, State.Destroyed, Arrays.asList(new Impact[]{Impact.USAGE}))); + s_fsm.addTransition(new Transition(State.Stopped, VirtualMachine.Event.StopRequested, State.Stopped, null)); + s_fsm.addTransition(new Transition(State.Stopped, VirtualMachine.Event.AgentReportStopped, State.Stopped, null)); // please pay attention about state transition to Error state, there should be only one case (failed in VM // creation process) // that can have such transition - s_fsm.addTransition(State.Stopped, VirtualMachine.Event.OperationFailedToError, State.Error); + s_fsm.addTransition(new Transition(State.Stopped, VirtualMachine.Event.OperationFailedToError, State.Error, Arrays.asList(new Impact[]{Impact.USAGE}))); - s_fsm.addTransition(State.Stopped, VirtualMachine.Event.OperationFailed, State.Stopped); - s_fsm.addTransition(State.Stopped, VirtualMachine.Event.ExpungeOperation, State.Expunging); - s_fsm.addTransition(State.Stopped, VirtualMachine.Event.AgentReportShutdowned, State.Stopped); - s_fsm.addTransition(State.Stopped, VirtualMachine.Event.StorageMigrationRequested, State.Migrating); - s_fsm.addTransition(State.Starting, VirtualMachine.Event.OperationRetry, State.Starting); - s_fsm.addTransition(State.Starting, VirtualMachine.Event.OperationSucceeded, State.Running); - s_fsm.addTransition(State.Starting, VirtualMachine.Event.OperationFailed, State.Stopped); - s_fsm.addTransition(State.Starting, VirtualMachine.Event.AgentReportRunning, State.Running); - s_fsm.addTransition(State.Starting, VirtualMachine.Event.AgentReportStopped, State.Stopped); - s_fsm.addTransition(State.Starting, VirtualMachine.Event.AgentReportShutdowned, State.Stopped); - s_fsm.addTransition(State.Destroyed, VirtualMachine.Event.RecoveryRequested, State.Stopped); - s_fsm.addTransition(State.Destroyed, VirtualMachine.Event.ExpungeOperation, State.Expunging); - s_fsm.addTransition(State.Running, VirtualMachine.Event.MigrationRequested, State.Migrating); - s_fsm.addTransition(State.Running, VirtualMachine.Event.AgentReportRunning, State.Running); - s_fsm.addTransition(State.Running, VirtualMachine.Event.AgentReportStopped, State.Stopped); - s_fsm.addTransition(State.Running, VirtualMachine.Event.StopRequested, State.Stopping); - s_fsm.addTransition(State.Running, VirtualMachine.Event.AgentReportShutdowned, State.Stopped); - s_fsm.addTransition(State.Running, VirtualMachine.Event.AgentReportMigrated, State.Running); - s_fsm.addTransition(State.Running, VirtualMachine.Event.OperationSucceeded, State.Running); - s_fsm.addTransition(State.Migrating, VirtualMachine.Event.MigrationRequested, State.Migrating); - s_fsm.addTransition(State.Migrating, VirtualMachine.Event.OperationSucceeded, State.Running); - s_fsm.addTransition(State.Migrating, VirtualMachine.Event.OperationFailed, State.Running); - s_fsm.addTransition(State.Migrating, VirtualMachine.Event.AgentReportRunning, State.Running); - s_fsm.addTransition(State.Migrating, VirtualMachine.Event.AgentReportStopped, State.Stopped); - s_fsm.addTransition(State.Migrating, VirtualMachine.Event.AgentReportShutdowned, State.Stopped); - s_fsm.addTransition(State.Stopping, VirtualMachine.Event.OperationSucceeded, State.Stopped); - s_fsm.addTransition(State.Stopping, VirtualMachine.Event.OperationFailed, State.Running); - s_fsm.addTransition(State.Stopping, VirtualMachine.Event.AgentReportRunning, State.Running); - s_fsm.addTransition(State.Stopping, VirtualMachine.Event.AgentReportStopped, State.Stopped); - s_fsm.addTransition(State.Stopping, VirtualMachine.Event.StopRequested, State.Stopping); - s_fsm.addTransition(State.Stopping, VirtualMachine.Event.AgentReportShutdowned, State.Stopped); - s_fsm.addTransition(State.Expunging, VirtualMachine.Event.OperationFailed, State.Expunging); - s_fsm.addTransition(State.Expunging, VirtualMachine.Event.ExpungeOperation, State.Expunging); - s_fsm.addTransition(State.Error, VirtualMachine.Event.DestroyRequested, State.Expunging); - s_fsm.addTransition(State.Error, VirtualMachine.Event.ExpungeOperation, State.Expunging); + s_fsm.addTransition(new Transition(State.Stopped, VirtualMachine.Event.OperationFailed, State.Stopped, null)); + s_fsm.addTransition(new Transition(State.Stopped, VirtualMachine.Event.ExpungeOperation, State.Expunging, Arrays.asList(new Impact[]{Impact.USAGE}))); + s_fsm.addTransition(new Transition(State.Stopped, VirtualMachine.Event.AgentReportShutdowned, State.Stopped, null)); + s_fsm.addTransition(new Transition(State.Stopped, VirtualMachine.Event.StorageMigrationRequested, State.Migrating, null)); + s_fsm.addTransition(new Transition(State.Starting, VirtualMachine.Event.OperationRetry, State.Starting, null)); + s_fsm.addTransition(new Transition(State.Starting, VirtualMachine.Event.OperationSucceeded, State.Running, Arrays.asList(new Impact[]{Impact.USAGE}))); + s_fsm.addTransition(new Transition(State.Starting, VirtualMachine.Event.OperationFailed, State.Stopped, null)); + s_fsm.addTransition(new Transition(State.Starting, VirtualMachine.Event.AgentReportRunning, State.Running, Arrays.asList(new Impact[]{Impact.USAGE}))); + s_fsm.addTransition(new Transition(State.Starting, VirtualMachine.Event.AgentReportStopped, State.Stopped, null)); + s_fsm.addTransition(new Transition(State.Starting, VirtualMachine.Event.AgentReportShutdowned, State.Stopped, null)); + s_fsm.addTransition(new Transition(State.Destroyed, VirtualMachine.Event.RecoveryRequested, State.Stopped, null)); + s_fsm.addTransition(new Transition(State.Destroyed, VirtualMachine.Event.ExpungeOperation, State.Expunging, null)); + s_fsm.addTransition(new Transition(State.Running, VirtualMachine.Event.MigrationRequested, State.Migrating, null)); + s_fsm.addTransition(new Transition(State.Running, VirtualMachine.Event.AgentReportRunning, State.Running, null)); + s_fsm.addTransition(new Transition(State.Running, VirtualMachine.Event.AgentReportStopped, State.Stopped, Arrays.asList(new Impact[]{Impact.USAGE}))); + s_fsm.addTransition(new Transition(State.Running, VirtualMachine.Event.StopRequested, State.Stopping, null)); + s_fsm.addTransition(new Transition(State.Running, VirtualMachine.Event.AgentReportShutdowned, State.Stopped, Arrays.asList(new Impact[]{Impact.USAGE}))); + s_fsm.addTransition(new Transition(State.Running, VirtualMachine.Event.AgentReportMigrated, State.Running, null)); + s_fsm.addTransition(new Transition(State.Running, VirtualMachine.Event.OperationSucceeded, State.Running, null)); + s_fsm.addTransition(new Transition(State.Migrating, VirtualMachine.Event.MigrationRequested, State.Migrating, null)); + s_fsm.addTransition(new Transition(State.Migrating, VirtualMachine.Event.OperationSucceeded, State.Running, null)); + s_fsm.addTransition(new Transition(State.Migrating, VirtualMachine.Event.OperationFailed, State.Running, null)); + s_fsm.addTransition(new Transition(State.Migrating, VirtualMachine.Event.AgentReportRunning, State.Running, null)); + s_fsm.addTransition(new Transition(State.Migrating, VirtualMachine.Event.AgentReportStopped, State.Stopped, null)); + s_fsm.addTransition(new Transition(State.Migrating, VirtualMachine.Event.AgentReportShutdowned, State.Stopped, null)); + s_fsm.addTransition(new Transition(State.Stopping, VirtualMachine.Event.OperationSucceeded, State.Stopped, Arrays.asList(new Impact[]{Impact.USAGE}))); + s_fsm.addTransition(new Transition(State.Stopping, VirtualMachine.Event.OperationFailed, State.Running, null)); + s_fsm.addTransition(new Transition(State.Stopping, VirtualMachine.Event.AgentReportRunning, State.Running, null)); + s_fsm.addTransition(new Transition(State.Stopping, VirtualMachine.Event.AgentReportStopped, State.Stopped, Arrays.asList(new Impact[]{Impact.USAGE}))); + s_fsm.addTransition(new Transition(State.Stopping, VirtualMachine.Event.StopRequested, State.Stopping, null)); + s_fsm.addTransition(new Transition(State.Stopping, VirtualMachine.Event.AgentReportShutdowned, State.Stopped, Arrays.asList(new Impact[]{Impact.USAGE}))); + s_fsm.addTransition(new Transition(State.Expunging, VirtualMachine.Event.OperationFailed, State.Expunging,null)); + s_fsm.addTransition(new Transition(State.Expunging, VirtualMachine.Event.ExpungeOperation, State.Expunging,null)); + s_fsm.addTransition(new Transition(State.Error, VirtualMachine.Event.DestroyRequested, State.Expunging, null)); + s_fsm.addTransition(new Transition(State.Error, VirtualMachine.Event.ExpungeOperation, State.Expunging, null)); - s_fsm.addTransition(State.Starting, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running); - s_fsm.addTransition(State.Stopping, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running); - s_fsm.addTransition(State.Stopped, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running); - s_fsm.addTransition(State.Running, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running); - s_fsm.addTransition(State.Migrating, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running); + s_fsm.addTransition(new Transition(State.Starting, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running, Arrays.asList(new Impact[]{Impact.USAGE}))); + s_fsm.addTransition(new Transition(State.Stopping, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running, null)); + s_fsm.addTransition(new Transition(State.Stopped, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running, Arrays.asList(new Impact[]{Impact.USAGE}))); + s_fsm.addTransition(new Transition(State.Running, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running, null)); + s_fsm.addTransition(new Transition(State.Migrating, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running, null)); - s_fsm.addTransition(State.Starting, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped); - s_fsm.addTransition(State.Stopping, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped); - s_fsm.addTransition(State.Running, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped); - s_fsm.addTransition(State.Migrating, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped); - s_fsm.addTransition(State.Stopped, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped); + s_fsm.addTransition(new Transition(State.Starting, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped, null)); + s_fsm.addTransition(new Transition(State.Stopping, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped, Arrays.asList(new Impact[]{Impact.USAGE}))); + s_fsm.addTransition(new Transition(State.Running, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped, Arrays.asList(new Impact[]{Impact.USAGE}))); + s_fsm.addTransition(new Transition(State.Migrating, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped, null)); + s_fsm.addTransition(new Transition(State.Stopped, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped, null)); } public static boolean isVmStarted(State oldState, Event e, State newState) { diff --git a/engine/components-api/src/com/cloud/network/NetworkStateListener.java b/engine/components-api/src/com/cloud/network/NetworkStateListener.java index c86f7820a5d..0ed1d9ea7fd 100644 --- a/engine/components-api/src/com/cloud/network/NetworkStateListener.java +++ b/engine/components-api/src/com/cloud/network/NetworkStateListener.java @@ -24,6 +24,7 @@ import java.util.Map; import javax.inject.Inject; +import com.cloud.utils.fsm.StateMachine2; import org.apache.log4j.Logger; import org.springframework.beans.factory.NoSuchBeanDefinitionException; @@ -65,12 +66,15 @@ public class NetworkStateListener implements StateListener transition, Network vo, boolean status, Object opaque) { + State oldState = transition.getCurrentState(); + State newState = transition.getToState(); + Event event = transition.getEvent(); + pubishOnEventBus(event.name(), "postStateTransitionEvent", vo, oldState, newState); + return true; } - private void pubishOnEventBus(String event, String status, Network vo, State oldState, State newState) { + private void pubishOnEventBus(String event, String status, Network vo, State oldState, State newState) { String configKey = "publish.resource.state.events"; String value = _configDao.getValue(configKey); diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalManagerImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalManagerImpl.java index f6a41133e3a..dc71e5b0467 100755 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalManagerImpl.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalManagerImpl.java @@ -26,6 +26,13 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.utils.db.QueryBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.fsm.StateMachine2; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.dao.VMInstanceDao; +import org.apache.cloudstack.api.BaremetalProvisionDoneNotificationCmd; import org.apache.log4j.Logger; import org.apache.cloudstack.api.AddBaremetalHostCmd; @@ -73,7 +80,9 @@ public class BaremetalManagerImpl extends ManagerBase implements BaremetalManage } @Override - public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Object opaque) { + public boolean postStateTransitionEvent(StateMachine2.Transition transition, VirtualMachine vo, boolean status, Object opaque) { + State newState = transition.getToState(); + State oldState = transition.getCurrentState(); if (newState != State.Starting && newState != State.Error && newState != State.Expunging) { return true; } diff --git a/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsTunnelManagerImpl.java b/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsTunnelManagerImpl.java index c998e3be38f..04d21fd354b 100644 --- a/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsTunnelManagerImpl.java +++ b/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsTunnelManagerImpl.java @@ -36,6 +36,7 @@ import com.cloud.network.vpc.dao.VpcDao; import com.cloud.network.vpc.VpcManager; import com.cloud.network.vpc.VpcVO; import com.cloud.network.vpc.dao.NetworkACLDao; +import com.cloud.utils.fsm.StateMachine2; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.dao.VMInstanceDao; import com.cloud.vm.Nic; @@ -680,25 +681,26 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage } @Override - public boolean postStateTransitionEvent(VirtualMachine.State oldState, VirtualMachine.Event event, - VirtualMachine.State newState, VirtualMachine vm, - boolean status, Object opaque) { - if (!status) { - return false; - } + public boolean postStateTransitionEvent(StateMachine2.Transition transition, VirtualMachine vm, boolean status, Object opaque) { + if (!status) { + return false; + } - if (VirtualMachine.State.isVmStarted(oldState, event, newState)) { - handleVmStateChange((VMInstanceVO)vm); - } else if (VirtualMachine.State.isVmStopped(oldState, event, newState)) { - handleVmStateChange((VMInstanceVO)vm); - } else if (VirtualMachine.State.isVmMigrated(oldState, event, newState)) { - handleVmStateChange((VMInstanceVO)vm); - } + VirtualMachine.State oldState = transition.getCurrentState(); + VirtualMachine.State newState = transition.getToState(); + VirtualMachine.Event event = transition.getEvent(); + if (VirtualMachine.State.isVmStarted(oldState, event, newState)) { + handleVmStateChange((VMInstanceVO)vm); + } else if (VirtualMachine.State.isVmStopped(oldState, event, newState)) { + handleVmStateChange((VMInstanceVO)vm); + } else if (VirtualMachine.State.isVmMigrated(oldState, event, newState)) { + handleVmStateChange((VMInstanceVO)vm); + } - return true; + return true; } - private void handleVmStateChange(VMInstanceVO vm) { + private void handleVmStateChange(VMInstanceVO vm) { // get the VPC's impacted with the VM start List vpcIds = _ovsNetworkToplogyGuru.getVpcIdsVmIsPartOf(vm.getId()); diff --git a/server/src/com/cloud/capacity/CapacityManagerImpl.java b/server/src/com/cloud/capacity/CapacityManagerImpl.java index 5ea7e3e4b71..af66b15fe29 100755 --- a/server/src/com/cloud/capacity/CapacityManagerImpl.java +++ b/server/src/com/cloud/capacity/CapacityManagerImpl.java @@ -28,6 +28,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import com.cloud.resource.ResourceState; +import com.cloud.utils.fsm.StateMachine2; import org.apache.log4j.Logger; @@ -775,7 +776,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, } @Override - public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vm, boolean status, Object opaque) { + public boolean postStateTransitionEvent(StateMachine2.Transition transition, VirtualMachine vm, boolean status, Object opaque) { if (!status) { return false; } @@ -783,6 +784,9 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, Pair hosts = (Pair)opaque; Long oldHostId = hosts.first(); + State oldState = transition.getCurrentState(); + State newState = transition.getToState(); + Event event = transition.getEvent(); s_logger.debug("VM state transitted from :" + oldState + " to " + newState + " with event: " + event + "vm's original host id: " + vm.getLastHostId() + " new host id: " + vm.getHostId() + " host id before state transition: " + oldHostId); diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java index c11aef7b731..54149c5880b 100755 --- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -31,6 +31,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.utils.fsm.StateMachine2; import org.apache.log4j.Logger; import org.apache.cloudstack.affinity.AffinityGroupProcessor; @@ -1451,10 +1452,12 @@ StateListener { } @Override - public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Object opaque) { + public boolean postStateTransitionEvent(StateMachine2.Transition transition, VirtualMachine vo, boolean status, Object opaque) { if (!status) { return false; } + State oldState = transition.getCurrentState(); + State newState = transition.getToState(); if ((oldState == State.Starting) && (newState != State.Starting)) { // cleanup all VM reservation entries SearchCriteria sc = _reservationDao.createSearchCriteria(); diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 92f1af9441b..b5d228496cc 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -217,6 +217,7 @@ import com.cloud.utils.db.TransactionCallbackNoReturn; import com.cloud.utils.db.TransactionStatus; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.StateListener; +import com.cloud.utils.fsm.StateMachine2; import com.cloud.utils.net.Ip; import com.cloud.utils.net.MacAddress; import com.cloud.utils.net.NetUtils; @@ -4470,7 +4471,10 @@ VirtualMachineGuru, Listener, Configurable, StateListener transition, VirtualMachine vo, boolean status, Object opaque) { + State oldState = transition.getCurrentState(); + State newState = transition.getToState(); + VirtualMachine.Event event = transition.getEvent(); if (event == VirtualMachine.Event.FollowAgentPowerOnReport && newState == State.Running) { if (vo.getType() == VirtualMachine.Type.DomainRouter) { // opaque -> diff --git a/server/src/com/cloud/network/security/SecurityGroupManagerImpl.java b/server/src/com/cloud/network/security/SecurityGroupManagerImpl.java index f60a746e68c..cffdf8f8be2 100755 --- a/server/src/com/cloud/network/security/SecurityGroupManagerImpl.java +++ b/server/src/com/cloud/network/security/SecurityGroupManagerImpl.java @@ -40,6 +40,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.utils.fsm.StateMachine2; import org.apache.commons.codec.digest.DigestUtils; import org.apache.log4j.Logger; @@ -1279,32 +1280,35 @@ public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGro } @Override - public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vm, boolean status, Object opaque) { - if (!status) { - return false; - } + public boolean postStateTransitionEvent(StateMachine2.Transition transition, VirtualMachine vm, boolean status, Object opaque) { + if (!status) { + return false; + } - if (VirtualMachine.State.isVmStarted(oldState, event, newState)) { - if (s_logger.isTraceEnabled()) { - s_logger.trace("Security Group Mgr: handling start of vm id" + vm.getId()); - } - handleVmStarted((VMInstanceVO)vm); - } else if (VirtualMachine.State.isVmStopped(oldState, event, newState)) { - if (s_logger.isTraceEnabled()) { - s_logger.trace("Security Group Mgr: handling stop of vm id" + vm.getId()); - } - handleVmStopped((VMInstanceVO)vm); - } else if (VirtualMachine.State.isVmMigrated(oldState, event, newState)) { - if (s_logger.isTraceEnabled()) { - s_logger.trace("Security Group Mgr: handling migration of vm id" + vm.getId()); - } - handleVmMigrated((VMInstanceVO)vm); + State oldState = transition.getCurrentState(); + State newState = transition.getToState(); + Event event = transition.getEvent(); + if (VirtualMachine.State.isVmStarted(oldState, event, newState)) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("Security Group Mgr: handling start of vm id" + vm.getId()); } + handleVmStarted((VMInstanceVO)vm); + } else if (VirtualMachine.State.isVmStopped(oldState, event, newState)) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("Security Group Mgr: handling stop of vm id" + vm.getId()); + } + handleVmStopped((VMInstanceVO)vm); + } else if (VirtualMachine.State.isVmMigrated(oldState, event, newState)) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("Security Group Mgr: handling migration of vm id" + vm.getId()); + } + handleVmMigrated((VMInstanceVO)vm); + } - return true; + return true; } - @Override + @Override public boolean isVmSecurityGroupEnabled(Long vmId) { VirtualMachine vm = _vmDao.findByIdIncludingRemoved(vmId); List nics = _networkMgr.getNicProfiles(vm); diff --git a/server/src/com/cloud/storage/listener/SnapshotStateListener.java b/server/src/com/cloud/storage/listener/SnapshotStateListener.java index 8da71a6793c..f4decf6f058 100644 --- a/server/src/com/cloud/storage/listener/SnapshotStateListener.java +++ b/server/src/com/cloud/storage/listener/SnapshotStateListener.java @@ -26,6 +26,7 @@ import javax.annotation.PostConstruct; import javax.ejb.Local; import javax.inject.Inject; +import com.cloud.utils.fsm.StateMachine2; import org.apache.log4j.Logger; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.stereotype.Component; @@ -72,12 +73,12 @@ public class SnapshotStateListener implements StateListener transition, SnapshotVO vo, boolean status, Object opaque) { + pubishOnEventBus(transition.getEvent().name(), "postStateTransitionEvent", vo, transition.getCurrentState(), transition.getToState()); + return true; } - private void pubishOnEventBus(String event, String status, Snapshot vo, State oldState, State newState) { + private void pubishOnEventBus(String event, String status, Snapshot vo, State oldState, State newState) { String configKey = Config.PublishResourceStateEvent.key(); String value = s_configDao.getValue(configKey); diff --git a/server/src/com/cloud/storage/listener/VolumeStateListener.java b/server/src/com/cloud/storage/listener/VolumeStateListener.java index 1911a482931..0ba2969a76a 100644 --- a/server/src/com/cloud/storage/listener/VolumeStateListener.java +++ b/server/src/com/cloud/storage/listener/VolumeStateListener.java @@ -22,6 +22,7 @@ import java.util.Date; import java.util.HashMap; import java.util.Map; +import com.cloud.utils.fsm.StateMachine2; import org.apache.log4j.Logger; import org.springframework.beans.factory.NoSuchBeanDefinitionException; @@ -56,12 +57,12 @@ public class VolumeStateListener implements StateListener } @Override - public boolean postStateTransitionEvent(State oldState, Event event, State newState, Volume vo, boolean status, Object opaque) { - pubishOnEventBus(event.name(), "postStateTransitionEvent", vo, oldState, newState); - return true; + public boolean postStateTransitionEvent(StateMachine2.Transition transition, Volume vo, boolean status, Object opaque) { + pubishOnEventBus(transition.getEvent().name(), "postStateTransitionEvent", vo, transition.getCurrentState(), transition.getToState()); + return true; } - private void pubishOnEventBus(String event, String status, Volume vo, State oldState, State newState) { + private void pubishOnEventBus(String event, String status, Volume vo, State oldState, State newState) { String configKey = Config.PublishResourceStateEvent.key(); String value = _configDao.getValue(configKey); diff --git a/server/src/com/cloud/vm/UserVmStateListener.java b/server/src/com/cloud/vm/UserVmStateListener.java index a0088b87163..e4df6bbbeb8 100644 --- a/server/src/com/cloud/vm/UserVmStateListener.java +++ b/server/src/com/cloud/vm/UserVmStateListener.java @@ -25,6 +25,7 @@ import java.util.Map; import javax.inject.Inject; import com.cloud.server.ManagementService; +import com.cloud.utils.fsm.StateMachine2; import com.cloud.vm.dao.UserVmDao; import org.apache.log4j.Logger; import org.springframework.beans.factory.NoSuchBeanDefinitionException; @@ -77,36 +78,40 @@ public class UserVmStateListener implements StateListener transition, VirtualMachine vo, boolean status, Object opaque) { + if (!status) { + return false; + } + Event event = transition.getEvent(); + State oldState = transition.getCurrentState(); + State newState = transition.getToState(); + pubishOnEventBus(event.name(), "postStateTransitionEvent", vo, oldState, newState); - pubishOnEventBus(event.name(), "postStateTransitionEvent", vo, oldState, newState); - - if (vo.getType() != VirtualMachine.Type.User) { - return true; - } - - if (VirtualMachine.State.isVmCreated(oldState, event, newState)) { - generateUsageEvent(vo.getServiceOfferingId(), vo, EventTypes.EVENT_VM_CREATE); - } else if (VirtualMachine.State.isVmStarted(oldState, event, newState)) { - generateUsageEvent(vo.getServiceOfferingId(), vo, EventTypes.EVENT_VM_START); - } else if (VirtualMachine.State.isVmStopped(oldState, event, newState)) { - generateUsageEvent(vo.getServiceOfferingId(), vo, EventTypes.EVENT_VM_STOP); - List nics = _nicDao.listByVmId(vo.getId()); - for (NicVO nic : nics) { - NetworkVO network = _networkDao.findById(nic.getNetworkId()); - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_REMOVE, vo.getAccountId(), vo.getDataCenterId(), vo.getId(), - Long.toString(nic.getId()), network.getNetworkOfferingId(), null, 0L, vo.getClass().getName(), vo.getUuid(), vo.isDisplay()); - } - } else if (VirtualMachine.State.isVmDestroyed(oldState, event, newState)) { - generateUsageEvent(vo.getServiceOfferingId(), vo, EventTypes.EVENT_VM_DESTROY); - } + if (vo.getType() != VirtualMachine.Type.User) { return true; + } + + if(transition.isImpacted(StateMachine2.Transition.Impact.USAGE)) { + if (oldState == State.Destroyed && newState == State.Stopped) { + generateUsageEvent(vo.getServiceOfferingId(), vo, EventTypes.EVENT_VM_CREATE); + } else if (newState == State.Running) { + generateUsageEvent(vo.getServiceOfferingId(), vo, EventTypes.EVENT_VM_START); + } else if (newState == State.Stopped) { + generateUsageEvent(vo.getServiceOfferingId(), vo, EventTypes.EVENT_VM_STOP); + List nics = _nicDao.listByVmId(vo.getId()); + for (NicVO nic : nics) { + NetworkVO network = _networkDao.findById(nic.getNetworkId()); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_REMOVE, vo.getAccountId(), vo.getDataCenterId(), vo.getId(), + Long.toString(nic.getId()), network.getNetworkOfferingId(), null, 0L, vo.getClass().getName(), vo.getUuid(), vo.isDisplay()); + } + } else if (newState == State.Destroyed || newState == State.Error || newState == State.Expunging) { + generateUsageEvent(vo.getServiceOfferingId(), vo, EventTypes.EVENT_VM_DESTROY); + } + } + return true; } - private void generateUsageEvent(Long serviceOfferingId, VirtualMachine vm, String eventType){ + private void generateUsageEvent(Long serviceOfferingId, VirtualMachine vm, String eventType){ boolean displayVm = true; if(vm.getType() == VirtualMachine.Type.User){ UserVmVO uservm = _userVmDao.findById(vm.getId()); diff --git a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java index 91835ea8b9d..cf396ec7cce 100644 --- a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java +++ b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java @@ -26,6 +26,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.utils.fsm.StateMachine2; import org.apache.log4j.Logger; import org.apache.cloudstack.acl.ControlledEntity; @@ -440,10 +441,11 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro } @Override - public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Object opaque) { + public boolean postStateTransitionEvent(StateMachine2.Transition transition, VirtualMachine vo, boolean status, Object opaque) { if (!status) { return false; } + State newState = transition.getToState(); if ((newState == State.Expunging) || (newState == State.Error)) { // cleanup all affinity groups associations of the Expunged VM SearchCriteria sc = _affinityGroupVMMapDao.createSearchCriteria(); diff --git a/utils/src/com/cloud/utils/fsm/StateListener.java b/utils/src/com/cloud/utils/fsm/StateListener.java index 3d0a645664a..96e8be92c3c 100644 --- a/utils/src/com/cloud/utils/fsm/StateListener.java +++ b/utils/src/com/cloud/utils/fsm/StateListener.java @@ -28,19 +28,16 @@ public interface StateListener { * @param newState VM's new state * @param vo the VM instance * @param opaque host id - * @param vmDao VM dao * @return */ public boolean preStateTransitionEvent(S oldState, E event, S newState, V vo, boolean status, Object opaque); /** - * Event is triggered after state machine transition finished - * @param oldState VM's old state - * @param event that triggered this VM state change - * @param newState VM's new state - * @param vo the VM instance - * @param status the state transition is allowed or not - * @return - */ - public boolean postStateTransitionEvent(S oldState, E event, S newState, V vo, boolean status, Object opaque); + * Event is triggered after state machine transition finished + * @param transition The Transition fo the Event + * @param vo the VM instance + * @param status the state transition is allowed or not + * @return + */ + public boolean postStateTransitionEvent(StateMachine2.Transition transition, V vo, boolean status, Object opaque); } diff --git a/utils/src/com/cloud/utils/fsm/StateMachine2.java b/utils/src/com/cloud/utils/fsm/StateMachine2.java index 4950a25cb91..431d961a416 100644 --- a/utils/src/com/cloud/utils/fsm/StateMachine2.java +++ b/utils/src/com/cloud/utils/fsm/StateMachine2.java @@ -46,25 +46,33 @@ public class StateMachine2> { } public void addTransition(S currentState, E event, S toState) { - StateEntry entry = null; - if (currentState == null) { - entry = _initialStateEntry; - } else { - entry = _states.get(currentState); - if (entry == null) { - entry = new StateEntry(currentState); - _states.put(currentState, entry); - } - } + addTransition(new Transition(currentState, event, toState, null)); + } - entry.addTransition(event, toState); - entry = _states.get(toState); + public void addTransition(Transition transition) { + S currentState = transition.getCurrentState(); + E event = transition.getEvent(); + S toState = transition.getToState(); + StateEntry entry = null; + if (currentState == null) { + entry = _initialStateEntry; + } else { + entry = _states.get(currentState); if (entry == null) { - entry = new StateEntry(toState); - _states.put(toState, entry); + entry = new StateEntry(currentState); + _states.put(currentState, entry); } - entry.addFromTransition(event, currentState); + } + + entry.addTransition(event, toState, transition); + + entry = _states.get(toState); + if (entry == null) { + entry = new StateEntry(toState); + _states.put(toState, entry); + } + entry.addFromTransition(event, currentState); } public Set getPossibleEvents(S s) { @@ -73,19 +81,23 @@ public class StateMachine2> { } public S getNextState(S s, E e) throws NoTransitionException { - StateEntry entry = null; - if (s == null) { - entry = _initialStateEntry; - } else { - entry = _states.get(s); - assert entry != null : "Cannot retrieve transitions for state " + s; - } + return getTransition(s, e).getToState(); + } - S ns = entry.nextStates.get(e); - if (ns == null) { - throw new NoTransitionException("Unable to transition to a new state from " + s + " via " + e); - } - return ns; + public Transition getTransition(S s, E e) throws NoTransitionException { + StateEntry entry = null; + if (s == null) { + entry = _initialStateEntry; + } else { + entry = _states.get(s); + assert entry != null : "Cannot retrieve transitions for state " + s; + } + + Transition transition = entry.nextStates.get(e); + if (transition == null) { + throw new NoTransitionException("Unable to transition to a new state from " + s + " via " + e); + } + return transition; } public List getFromStates(S s, E e) { @@ -100,6 +112,7 @@ public class StateMachine2> { public boolean transitTo(V vo, E e, Object opaque, StateDao dao) throws NoTransitionException { S currentState = vo.getState(); S nextState = getNextState(currentState, e); + Transition transition = getTransition(currentState, e); boolean transitionStatus = true; if (nextState == null) { @@ -116,7 +129,7 @@ public class StateMachine2> { } for (StateListener listener : _listeners) { - listener.postStateTransitionEvent(currentState, e, nextState, vo, transitionStatus, opaque); + listener.postStateTransitionEvent(transition, vo, transitionStatus, opaque); } return true; @@ -138,21 +151,84 @@ public class StateMachine2> { return str.toString(); } + public static class Transition { + + private S currentState; + + private E event; + + private S toState; + + private List impacts; + + public static enum Impact { + USAGE + } + + public Transition(S currentState, E event, S toState, List impacts) { + this.currentState = currentState; + this.event = event; + this.toState = toState; + this.impacts = impacts; + } + + public S getCurrentState() { + return currentState; + } + + public E getEvent() { + return event; + } + + public S getToState() { + return toState; + } + + public boolean isImpacted(Impact impact) { + if (impacts == null || impacts.isEmpty()) { + return false; + } + return impacts.contains(impact); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Transition that = (Transition) o; + + if (currentState != null ? !currentState.equals(that.currentState) : that.currentState != null) return false; + if (event != null ? !event.equals(that.event) : that.event != null) return false; + if (toState != null ? !toState.equals(that.toState) : that.toState != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = currentState != null ? currentState.hashCode() : 0; + result = 31 * result + (event != null ? event.hashCode() : 0); + result = 31 * result + (toState != null ? toState.hashCode() : 0); + return result; + } + } + private class StateEntry { public S state; - public HashMap nextStates; + public HashMap> nextStates; public HashMap> prevStates; public StateEntry(S state) { this.state = state; - nextStates = new HashMap(); prevStates = new HashMap>(); + nextStates = new HashMap>(); } - public void addTransition(E e, S s) { + public void addTransition(E e, S s, Transition transition) { assert !nextStates.containsKey(e) : "State " + getStateStr() + " already contains a transition to state " + nextStates.get(e).toString() + " via event " + e.toString() + ". Please revisit the rule you're adding to state " + s.toString(); - nextStates.put(e, s); + nextStates.put(e, transition); } public void addFromTransition(E e, S s) { @@ -172,7 +248,7 @@ public class StateMachine2> { public void buildString(StringBuilder str) { str.append("State: ").append(getStateStr()).append("\n"); - for (Map.Entry nextState : nextStates.entrySet()) { + for (Map.Entry> nextState : nextStates.entrySet()) { str.append(" --> Event: "); Formatter format = new Formatter(); str.append(format.format("%-30s", nextState.getKey().toString()));