CLOUDSTACK-7648: There are new VM State Machine changes introduced which were missed to capture the usage events

This commit is contained in:
Damodar 2014-10-09 11:52:28 +05:30 committed by Kishan Kavala
parent b6cacb3d67
commit 50185b7c3a
14 changed files with 399 additions and 290 deletions

View File

@ -16,6 +16,7 @@
// under the License. // under the License.
package com.cloud.vm; package com.cloud.vm;
import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.Map; import java.util.Map;
@ -26,6 +27,8 @@ import org.apache.cloudstack.api.InternalIdentity;
import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.utils.fsm.StateMachine2; 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; import com.cloud.utils.fsm.StateObject;
/** /**
@ -75,63 +78,63 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Identity, I
protected static final StateMachine2<State, VirtualMachine.Event, VirtualMachine> s_fsm = new StateMachine2<State, VirtualMachine.Event, VirtualMachine>(); protected static final StateMachine2<State, VirtualMachine.Event, VirtualMachine> s_fsm = new StateMachine2<State, VirtualMachine.Event, VirtualMachine>();
static { static {
s_fsm.addTransition(State.Stopped, VirtualMachine.Event.StartRequested, State.Starting); s_fsm.addTransition(new Transition<State, Event>(State.Stopped, VirtualMachine.Event.StartRequested, State.Starting, null));
s_fsm.addTransition(State.Stopped, VirtualMachine.Event.DestroyRequested, State.Destroyed); s_fsm.addTransition(new Transition<State, Event>(State.Stopped, VirtualMachine.Event.DestroyRequested, State.Destroyed, Arrays.asList(new Impact[]{Impact.USAGE})));
s_fsm.addTransition(State.Stopped, VirtualMachine.Event.StopRequested, State.Stopped); s_fsm.addTransition(new Transition<State, Event>(State.Stopped, VirtualMachine.Event.StopRequested, State.Stopped, null));
s_fsm.addTransition(State.Stopped, VirtualMachine.Event.AgentReportStopped, State.Stopped); s_fsm.addTransition(new Transition<State, Event>(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 // please pay attention about state transition to Error state, there should be only one case (failed in VM
// creation process) // creation process)
// that can have such transition // that can have such transition
s_fsm.addTransition(State.Stopped, VirtualMachine.Event.OperationFailedToError, State.Error); s_fsm.addTransition(new Transition<State, Event>(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(new Transition<State, Event>(State.Stopped, VirtualMachine.Event.OperationFailed, State.Stopped, null));
s_fsm.addTransition(State.Stopped, VirtualMachine.Event.ExpungeOperation, State.Expunging); s_fsm.addTransition(new Transition<State, Event>(State.Stopped, VirtualMachine.Event.ExpungeOperation, State.Expunging, Arrays.asList(new Impact[]{Impact.USAGE})));
s_fsm.addTransition(State.Stopped, VirtualMachine.Event.AgentReportShutdowned, State.Stopped); s_fsm.addTransition(new Transition<State, Event>(State.Stopped, VirtualMachine.Event.AgentReportShutdowned, State.Stopped, null));
s_fsm.addTransition(State.Stopped, VirtualMachine.Event.StorageMigrationRequested, State.Migrating); s_fsm.addTransition(new Transition<State, Event>(State.Stopped, VirtualMachine.Event.StorageMigrationRequested, State.Migrating, null));
s_fsm.addTransition(State.Starting, VirtualMachine.Event.OperationRetry, State.Starting); s_fsm.addTransition(new Transition<State, Event>(State.Starting, VirtualMachine.Event.OperationRetry, State.Starting, null));
s_fsm.addTransition(State.Starting, VirtualMachine.Event.OperationSucceeded, State.Running); s_fsm.addTransition(new Transition<State, Event>(State.Starting, VirtualMachine.Event.OperationSucceeded, State.Running, Arrays.asList(new Impact[]{Impact.USAGE})));
s_fsm.addTransition(State.Starting, VirtualMachine.Event.OperationFailed, State.Stopped); s_fsm.addTransition(new Transition<State, Event>(State.Starting, VirtualMachine.Event.OperationFailed, State.Stopped, null));
s_fsm.addTransition(State.Starting, VirtualMachine.Event.AgentReportRunning, State.Running); s_fsm.addTransition(new Transition<State, Event>(State.Starting, VirtualMachine.Event.AgentReportRunning, State.Running, Arrays.asList(new Impact[]{Impact.USAGE})));
s_fsm.addTransition(State.Starting, VirtualMachine.Event.AgentReportStopped, State.Stopped); s_fsm.addTransition(new Transition<State, Event>(State.Starting, VirtualMachine.Event.AgentReportStopped, State.Stopped, null));
s_fsm.addTransition(State.Starting, VirtualMachine.Event.AgentReportShutdowned, State.Stopped); s_fsm.addTransition(new Transition<State, Event>(State.Starting, VirtualMachine.Event.AgentReportShutdowned, State.Stopped, null));
s_fsm.addTransition(State.Destroyed, VirtualMachine.Event.RecoveryRequested, State.Stopped); s_fsm.addTransition(new Transition<State, Event>(State.Destroyed, VirtualMachine.Event.RecoveryRequested, State.Stopped, null));
s_fsm.addTransition(State.Destroyed, VirtualMachine.Event.ExpungeOperation, State.Expunging); s_fsm.addTransition(new Transition<State, Event>(State.Destroyed, VirtualMachine.Event.ExpungeOperation, State.Expunging, null));
s_fsm.addTransition(State.Running, VirtualMachine.Event.MigrationRequested, State.Migrating); s_fsm.addTransition(new Transition<State, Event>(State.Running, VirtualMachine.Event.MigrationRequested, State.Migrating, null));
s_fsm.addTransition(State.Running, VirtualMachine.Event.AgentReportRunning, State.Running); s_fsm.addTransition(new Transition<State, Event>(State.Running, VirtualMachine.Event.AgentReportRunning, State.Running, null));
s_fsm.addTransition(State.Running, VirtualMachine.Event.AgentReportStopped, State.Stopped); s_fsm.addTransition(new Transition<State, Event>(State.Running, VirtualMachine.Event.AgentReportStopped, State.Stopped, Arrays.asList(new Impact[]{Impact.USAGE})));
s_fsm.addTransition(State.Running, VirtualMachine.Event.StopRequested, State.Stopping); s_fsm.addTransition(new Transition<State, Event>(State.Running, VirtualMachine.Event.StopRequested, State.Stopping, null));
s_fsm.addTransition(State.Running, VirtualMachine.Event.AgentReportShutdowned, State.Stopped); s_fsm.addTransition(new Transition<State, Event>(State.Running, VirtualMachine.Event.AgentReportShutdowned, State.Stopped, Arrays.asList(new Impact[]{Impact.USAGE})));
s_fsm.addTransition(State.Running, VirtualMachine.Event.AgentReportMigrated, State.Running); s_fsm.addTransition(new Transition<State, Event>(State.Running, VirtualMachine.Event.AgentReportMigrated, State.Running, null));
s_fsm.addTransition(State.Running, VirtualMachine.Event.OperationSucceeded, State.Running); s_fsm.addTransition(new Transition<State, Event>(State.Running, VirtualMachine.Event.OperationSucceeded, State.Running, null));
s_fsm.addTransition(State.Migrating, VirtualMachine.Event.MigrationRequested, State.Migrating); s_fsm.addTransition(new Transition<State, Event>(State.Migrating, VirtualMachine.Event.MigrationRequested, State.Migrating, null));
s_fsm.addTransition(State.Migrating, VirtualMachine.Event.OperationSucceeded, State.Running); s_fsm.addTransition(new Transition<State, Event>(State.Migrating, VirtualMachine.Event.OperationSucceeded, State.Running, null));
s_fsm.addTransition(State.Migrating, VirtualMachine.Event.OperationFailed, State.Running); s_fsm.addTransition(new Transition<State, Event>(State.Migrating, VirtualMachine.Event.OperationFailed, State.Running, null));
s_fsm.addTransition(State.Migrating, VirtualMachine.Event.AgentReportRunning, State.Running); s_fsm.addTransition(new Transition<State, Event>(State.Migrating, VirtualMachine.Event.AgentReportRunning, State.Running, null));
s_fsm.addTransition(State.Migrating, VirtualMachine.Event.AgentReportStopped, State.Stopped); s_fsm.addTransition(new Transition<State, Event>(State.Migrating, VirtualMachine.Event.AgentReportStopped, State.Stopped, null));
s_fsm.addTransition(State.Migrating, VirtualMachine.Event.AgentReportShutdowned, State.Stopped); s_fsm.addTransition(new Transition<State, Event>(State.Migrating, VirtualMachine.Event.AgentReportShutdowned, State.Stopped, null));
s_fsm.addTransition(State.Stopping, VirtualMachine.Event.OperationSucceeded, State.Stopped); s_fsm.addTransition(new Transition<State, Event>(State.Stopping, VirtualMachine.Event.OperationSucceeded, State.Stopped, Arrays.asList(new Impact[]{Impact.USAGE})));
s_fsm.addTransition(State.Stopping, VirtualMachine.Event.OperationFailed, State.Running); s_fsm.addTransition(new Transition<State, Event>(State.Stopping, VirtualMachine.Event.OperationFailed, State.Running, null));
s_fsm.addTransition(State.Stopping, VirtualMachine.Event.AgentReportRunning, State.Running); s_fsm.addTransition(new Transition<State, Event>(State.Stopping, VirtualMachine.Event.AgentReportRunning, State.Running, null));
s_fsm.addTransition(State.Stopping, VirtualMachine.Event.AgentReportStopped, State.Stopped); s_fsm.addTransition(new Transition<State, Event>(State.Stopping, VirtualMachine.Event.AgentReportStopped, State.Stopped, Arrays.asList(new Impact[]{Impact.USAGE})));
s_fsm.addTransition(State.Stopping, VirtualMachine.Event.StopRequested, State.Stopping); s_fsm.addTransition(new Transition<State, Event>(State.Stopping, VirtualMachine.Event.StopRequested, State.Stopping, null));
s_fsm.addTransition(State.Stopping, VirtualMachine.Event.AgentReportShutdowned, State.Stopped); s_fsm.addTransition(new Transition<State, Event>(State.Stopping, VirtualMachine.Event.AgentReportShutdowned, State.Stopped, Arrays.asList(new Impact[]{Impact.USAGE})));
s_fsm.addTransition(State.Expunging, VirtualMachine.Event.OperationFailed, State.Expunging); s_fsm.addTransition(new Transition<State, Event>(State.Expunging, VirtualMachine.Event.OperationFailed, State.Expunging,null));
s_fsm.addTransition(State.Expunging, VirtualMachine.Event.ExpungeOperation, State.Expunging); s_fsm.addTransition(new Transition<State, Event>(State.Expunging, VirtualMachine.Event.ExpungeOperation, State.Expunging,null));
s_fsm.addTransition(State.Error, VirtualMachine.Event.DestroyRequested, State.Expunging); s_fsm.addTransition(new Transition<State, Event>(State.Error, VirtualMachine.Event.DestroyRequested, State.Expunging, null));
s_fsm.addTransition(State.Error, VirtualMachine.Event.ExpungeOperation, State.Expunging); s_fsm.addTransition(new Transition<State, Event>(State.Error, VirtualMachine.Event.ExpungeOperation, State.Expunging, null));
s_fsm.addTransition(State.Starting, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running); s_fsm.addTransition(new Transition<State, Event>(State.Starting, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running, Arrays.asList(new Impact[]{Impact.USAGE})));
s_fsm.addTransition(State.Stopping, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running); s_fsm.addTransition(new Transition<State, Event>(State.Stopping, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running, null));
s_fsm.addTransition(State.Stopped, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running); s_fsm.addTransition(new Transition<State, Event>(State.Stopped, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running, Arrays.asList(new Impact[]{Impact.USAGE})));
s_fsm.addTransition(State.Running, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running); s_fsm.addTransition(new Transition<State, Event>(State.Running, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running, null));
s_fsm.addTransition(State.Migrating, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running); s_fsm.addTransition(new Transition<State, Event>(State.Migrating, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running, null));
s_fsm.addTransition(State.Starting, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped); s_fsm.addTransition(new Transition<State, Event>(State.Starting, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped, null));
s_fsm.addTransition(State.Stopping, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped); s_fsm.addTransition(new Transition<State, Event>(State.Stopping, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped, Arrays.asList(new Impact[]{Impact.USAGE})));
s_fsm.addTransition(State.Running, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped); s_fsm.addTransition(new Transition<State, Event>(State.Running, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped, Arrays.asList(new Impact[]{Impact.USAGE})));
s_fsm.addTransition(State.Migrating, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped); s_fsm.addTransition(new Transition<State, Event>(State.Migrating, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped, null));
s_fsm.addTransition(State.Stopped, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped); s_fsm.addTransition(new Transition<State, Event>(State.Stopped, VirtualMachine.Event.FollowAgentPowerOffReport, State.Stopped, null));
} }
public static boolean isVmStarted(State oldState, Event e, State newState) { public static boolean isVmStarted(State oldState, Event e, State newState) {

View File

@ -24,6 +24,7 @@ import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
import com.cloud.utils.fsm.StateMachine2;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.NoSuchBeanDefinitionException;
@ -65,7 +66,10 @@ public class NetworkStateListener implements StateListener<State, Event, Network
} }
@Override @Override
public boolean postStateTransitionEvent(State oldState, Event event, State newState, Network vo, boolean status, Object opaque) { public boolean postStateTransitionEvent(StateMachine2.Transition<State, Event> 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); pubishOnEventBus(event.name(), "postStateTransitionEvent", vo, oldState, newState);
return true; return true;
} }

View File

@ -29,6 +29,7 @@ import javax.naming.ConfigurationException;
import com.cloud.utils.db.QueryBuilder; import com.cloud.utils.db.QueryBuilder;
import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.fsm.StateMachine2;
import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.dao.VMInstanceDao; import com.cloud.vm.dao.VMInstanceDao;
import org.apache.cloudstack.api.BaremetalProvisionDoneNotificationCmd; import org.apache.cloudstack.api.BaremetalProvisionDoneNotificationCmd;
@ -81,7 +82,9 @@ public class BaremetalManagerImpl extends ManagerBase implements BaremetalManage
} }
@Override @Override
public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Object opaque) { public boolean postStateTransitionEvent(StateMachine2.Transition<State, Event> 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) { if (newState != State.Starting && newState != State.Error && newState != State.Expunging) {
return true; return true;
} }

View File

@ -36,6 +36,7 @@ import com.cloud.network.vpc.dao.VpcDao;
import com.cloud.network.vpc.VpcManager; import com.cloud.network.vpc.VpcManager;
import com.cloud.network.vpc.VpcVO; import com.cloud.network.vpc.VpcVO;
import com.cloud.network.vpc.dao.NetworkACLDao; import com.cloud.network.vpc.dao.NetworkACLDao;
import com.cloud.utils.fsm.StateMachine2;
import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.dao.VMInstanceDao; import com.cloud.vm.dao.VMInstanceDao;
import com.cloud.vm.Nic; import com.cloud.vm.Nic;
@ -680,13 +681,14 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage
} }
@Override @Override
public boolean postStateTransitionEvent(VirtualMachine.State oldState, VirtualMachine.Event event, public boolean postStateTransitionEvent(StateMachine2.Transition<VirtualMachine.State, VirtualMachine.Event> transition, VirtualMachine vm, boolean status, Object opaque) {
VirtualMachine.State newState, VirtualMachine vm,
boolean status, Object opaque) {
if (!status) { if (!status) {
return false; return false;
} }
VirtualMachine.State oldState = transition.getCurrentState();
VirtualMachine.State newState = transition.getToState();
VirtualMachine.Event event = transition.getEvent();
if (VirtualMachine.State.isVmStarted(oldState, event, newState)) { if (VirtualMachine.State.isVmStarted(oldState, event, newState)) {
handleVmStateChange((VMInstanceVO)vm); handleVmStateChange((VMInstanceVO)vm);
} else if (VirtualMachine.State.isVmStopped(oldState, event, newState)) { } else if (VirtualMachine.State.isVmStopped(oldState, event, newState)) {

View File

@ -27,6 +27,7 @@ import javax.ejb.Local;
import javax.inject.Inject; import javax.inject.Inject;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import com.cloud.utils.fsm.StateMachine2;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver;
@ -770,7 +771,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager,
} }
@Override @Override
public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vm, boolean status, Object opaque) { public boolean postStateTransitionEvent(StateMachine2.Transition<State, Event> transition, VirtualMachine vm, boolean status, Object opaque) {
if (!status) { if (!status) {
return false; return false;
} }
@ -778,6 +779,9 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager,
Pair<Long, Long> hosts = (Pair<Long, Long>)opaque; Pair<Long, Long> hosts = (Pair<Long, Long>)opaque;
Long oldHostId = hosts.first(); 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() + 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); " new host id: " + vm.getHostId() + " host id before state transition: " + oldHostId);

View File

@ -31,6 +31,7 @@ import javax.ejb.Local;
import javax.inject.Inject; import javax.inject.Inject;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import com.cloud.utils.fsm.StateMachine2;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.apache.cloudstack.affinity.AffinityGroupProcessor; import org.apache.cloudstack.affinity.AffinityGroupProcessor;
@ -1443,10 +1444,12 @@ StateListener<State, VirtualMachine.Event, VirtualMachine> {
} }
@Override @Override
public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Object opaque) { public boolean postStateTransitionEvent(StateMachine2.Transition<State, Event> transition, VirtualMachine vo, boolean status, Object opaque) {
if (!status) { if (!status) {
return false; return false;
} }
State oldState = transition.getCurrentState();
State newState = transition.getToState();
if ((oldState == State.Starting) && (newState != State.Starting)) { if ((oldState == State.Starting) && (newState != State.Starting)) {
// cleanup all VM reservation entries // cleanup all VM reservation entries
SearchCriteria<VMReservationVO> sc = _reservationDao.createSearchCriteria(); SearchCriteria<VMReservationVO> sc = _reservationDao.createSearchCriteria();

View File

@ -218,6 +218,7 @@ import com.cloud.utils.db.TransactionCallbackNoReturn;
import com.cloud.utils.db.TransactionStatus; import com.cloud.utils.db.TransactionStatus;
import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.fsm.StateListener; import com.cloud.utils.fsm.StateListener;
import com.cloud.utils.fsm.StateMachine2;
import com.cloud.utils.net.Ip; import com.cloud.utils.net.Ip;
import com.cloud.utils.net.MacAddress; import com.cloud.utils.net.MacAddress;
import com.cloud.utils.net.NetUtils; import com.cloud.utils.net.NetUtils;
@ -4432,7 +4433,10 @@ VirtualMachineGuru, Listener, Configurable, StateListener<State, VirtualMachine.
} }
@Override @Override
public boolean postStateTransitionEvent(State oldState, VirtualMachine.Event event, State newState, VirtualMachine vo, boolean status, Object opaque) { public boolean postStateTransitionEvent(StateMachine2.Transition<State, VirtualMachine.Event> transition, VirtualMachine vo, boolean status, Object opaque) {
State oldState = transition.getCurrentState();
State newState = transition.getToState();
VirtualMachine.Event event = transition.getEvent();
if (oldState == State.Stopped && event == VirtualMachine.Event.FollowAgentPowerOnReport && newState == State.Running) { if (oldState == State.Stopped && event == VirtualMachine.Event.FollowAgentPowerOnReport && newState == State.Running) {
if (vo.getType() == VirtualMachine.Type.DomainRouter) { if (vo.getType() == VirtualMachine.Type.DomainRouter) {
s_logger.info("Schedule a router reboot task as router " + vo.getId() + " is powered-on out-of-band. we need to reboot to refresh network rules"); s_logger.info("Schedule a router reboot task as router " + vo.getId() + " is powered-on out-of-band. we need to reboot to refresh network rules");

View File

@ -40,6 +40,7 @@ import javax.ejb.Local;
import javax.inject.Inject; import javax.inject.Inject;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import com.cloud.utils.fsm.StateMachine2;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
@ -1279,11 +1280,14 @@ public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGro
} }
@Override @Override
public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vm, boolean status, Object opaque) { public boolean postStateTransitionEvent(StateMachine2.Transition<State, Event> transition, VirtualMachine vm, boolean status, Object opaque) {
if (!status) { if (!status) {
return false; return false;
} }
State oldState = transition.getCurrentState();
State newState = transition.getToState();
Event event = transition.getEvent();
if (VirtualMachine.State.isVmStarted(oldState, event, newState)) { if (VirtualMachine.State.isVmStarted(oldState, event, newState)) {
if (s_logger.isTraceEnabled()) { if (s_logger.isTraceEnabled()) {
s_logger.trace("Security Group Mgr: handling start of vm id" + vm.getId()); s_logger.trace("Security Group Mgr: handling start of vm id" + vm.getId());

View File

@ -26,6 +26,7 @@ import javax.annotation.PostConstruct;
import javax.ejb.Local; import javax.ejb.Local;
import javax.inject.Inject; import javax.inject.Inject;
import com.cloud.utils.fsm.StateMachine2;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -72,8 +73,8 @@ public class SnapshotStateListener implements StateListener<State, Event, Snapsh
} }
@Override @Override
public boolean postStateTransitionEvent(State oldState, Event event, State newState, SnapshotVO vo, boolean status, Object opaque) { public boolean postStateTransitionEvent(StateMachine2.Transition<State, Event> transition, SnapshotVO vo, boolean status, Object opaque) {
pubishOnEventBus(event.name(), "postStateTransitionEvent", vo, oldState, newState); pubishOnEventBus(transition.getEvent().name(), "postStateTransitionEvent", vo, transition.getCurrentState(), transition.getToState());
return true; return true;
} }

View File

@ -22,6 +22,7 @@ import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.cloud.utils.fsm.StateMachine2;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.NoSuchBeanDefinitionException;
@ -56,8 +57,8 @@ public class VolumeStateListener implements StateListener<State, Event, Volume>
} }
@Override @Override
public boolean postStateTransitionEvent(State oldState, Event event, State newState, Volume vo, boolean status, Object opaque) { public boolean postStateTransitionEvent(StateMachine2.Transition<State, Event> transition, Volume vo, boolean status, Object opaque) {
pubishOnEventBus(event.name(), "postStateTransitionEvent", vo, oldState, newState); pubishOnEventBus(transition.getEvent().name(), "postStateTransitionEvent", vo, transition.getCurrentState(), transition.getToState());
return true; return true;
} }

View File

@ -25,6 +25,7 @@ import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
import com.cloud.server.ManagementService; import com.cloud.server.ManagementService;
import com.cloud.utils.fsm.StateMachine2;
import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.UserVmDao;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.NoSuchBeanDefinitionException;
@ -77,22 +78,25 @@ public class UserVmStateListener implements StateListener<State, VirtualMachine.
} }
@Override @Override
public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Object opaque) { public boolean postStateTransitionEvent(StateMachine2.Transition<State, Event> transition, VirtualMachine vo, boolean status, Object opaque) {
if (!status) { if (!status) {
return false; 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) { if (vo.getType() != VirtualMachine.Type.User) {
return true; return true;
} }
if (VirtualMachine.State.isVmCreated(oldState, event, newState)) { if(transition.isImpacted(StateMachine2.Transition.Impact.USAGE)) {
if (oldState == State.Destroyed && newState == State.Stopped) {
generateUsageEvent(vo.getServiceOfferingId(), vo, EventTypes.EVENT_VM_CREATE); generateUsageEvent(vo.getServiceOfferingId(), vo, EventTypes.EVENT_VM_CREATE);
} else if (VirtualMachine.State.isVmStarted(oldState, event, newState)) { } else if (newState == State.Running) {
generateUsageEvent(vo.getServiceOfferingId(), vo, EventTypes.EVENT_VM_START); generateUsageEvent(vo.getServiceOfferingId(), vo, EventTypes.EVENT_VM_START);
} else if (VirtualMachine.State.isVmStopped(oldState, event, newState)) { } else if (newState == State.Stopped) {
generateUsageEvent(vo.getServiceOfferingId(), vo, EventTypes.EVENT_VM_STOP); generateUsageEvent(vo.getServiceOfferingId(), vo, EventTypes.EVENT_VM_STOP);
List<NicVO> nics = _nicDao.listByVmId(vo.getId()); List<NicVO> nics = _nicDao.listByVmId(vo.getId());
for (NicVO nic : nics) { for (NicVO nic : nics) {
@ -100,9 +104,10 @@ public class UserVmStateListener implements StateListener<State, VirtualMachine.
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_REMOVE, vo.getAccountId(), vo.getDataCenterId(), vo.getId(), 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()); Long.toString(nic.getId()), network.getNetworkOfferingId(), null, 0L, vo.getClass().getName(), vo.getUuid(), vo.isDisplay());
} }
} else if (VirtualMachine.State.isVmDestroyed(oldState, event, newState)) { } else if (newState == State.Destroyed || newState == State.Error || newState == State.Expunging) {
generateUsageEvent(vo.getServiceOfferingId(), vo, EventTypes.EVENT_VM_DESTROY); generateUsageEvent(vo.getServiceOfferingId(), vo, EventTypes.EVENT_VM_DESTROY);
} }
}
return true; return true;
} }

View File

@ -26,6 +26,7 @@ import javax.ejb.Local;
import javax.inject.Inject; import javax.inject.Inject;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import com.cloud.utils.fsm.StateMachine2;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity;
@ -439,10 +440,11 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
} }
@Override @Override
public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Object opaque) { public boolean postStateTransitionEvent(StateMachine2.Transition<State, Event> transition, VirtualMachine vo, boolean status, Object opaque) {
if (!status) { if (!status) {
return false; return false;
} }
State newState = transition.getToState();
if ((newState == State.Expunging) || (newState == State.Error)) { if ((newState == State.Expunging) || (newState == State.Error)) {
// cleanup all affinity groups associations of the Expunged VM // cleanup all affinity groups associations of the Expunged VM
SearchCriteria<AffinityGroupVMMapVO> sc = _affinityGroupVMMapDao.createSearchCriteria(); SearchCriteria<AffinityGroupVMMapVO> sc = _affinityGroupVMMapDao.createSearchCriteria();

View File

@ -28,19 +28,16 @@ public interface StateListener<S, E, V> {
* @param newState VM's new state * @param newState VM's new state
* @param vo the VM instance * @param vo the VM instance
* @param opaque host id * @param opaque host id
* @param vmDao VM dao
* @return * @return
*/ */
public boolean preStateTransitionEvent(S oldState, E event, S newState, V vo, boolean status, Object opaque); public boolean preStateTransitionEvent(S oldState, E event, S newState, V vo, boolean status, Object opaque);
/** /**
* Event is triggered after state machine transition finished * Event is triggered after state machine transition finished
* @param oldState VM's old state * @param transition The Transition fo the Event
* @param event that triggered this VM state change
* @param newState VM's new state
* @param vo the VM instance * @param vo the VM instance
* @param status the state transition is allowed or not * @param status the state transition is allowed or not
* @return * @return
*/ */
public boolean postStateTransitionEvent(S oldState, E event, S newState, V vo, boolean status, Object opaque); public boolean postStateTransitionEvent(StateMachine2.Transition<S, E> transition, V vo, boolean status, Object opaque);
} }

View File

@ -46,6 +46,14 @@ public class StateMachine2<S, E, V extends StateObject<S>> {
} }
public void addTransition(S currentState, E event, S toState) { public void addTransition(S currentState, E event, S toState) {
addTransition(new Transition<S, E>(currentState, event, toState, null));
}
public void addTransition(Transition<S, E> transition) {
S currentState = transition.getCurrentState();
E event = transition.getEvent();
S toState = transition.getToState();
StateEntry entry = null; StateEntry entry = null;
if (currentState == null) { if (currentState == null) {
entry = _initialStateEntry; entry = _initialStateEntry;
@ -57,7 +65,7 @@ public class StateMachine2<S, E, V extends StateObject<S>> {
} }
} }
entry.addTransition(event, toState); entry.addTransition(event, toState, transition);
entry = _states.get(toState); entry = _states.get(toState);
if (entry == null) { if (entry == null) {
@ -73,6 +81,10 @@ public class StateMachine2<S, E, V extends StateObject<S>> {
} }
public S getNextState(S s, E e) throws NoTransitionException { public S getNextState(S s, E e) throws NoTransitionException {
return getTransition(s, e).getToState();
}
public Transition<S, E> getTransition(S s, E e) throws NoTransitionException {
StateEntry entry = null; StateEntry entry = null;
if (s == null) { if (s == null) {
entry = _initialStateEntry; entry = _initialStateEntry;
@ -81,11 +93,11 @@ public class StateMachine2<S, E, V extends StateObject<S>> {
assert entry != null : "Cannot retrieve transitions for state " + s; assert entry != null : "Cannot retrieve transitions for state " + s;
} }
S ns = entry.nextStates.get(e); Transition<S, E> transition = entry.nextStates.get(e);
if (ns == null) { if (transition == null) {
throw new NoTransitionException("Unable to transition to a new state from " + s + " via " + e); throw new NoTransitionException("Unable to transition to a new state from " + s + " via " + e);
} }
return ns; return transition;
} }
public List<S> getFromStates(S s, E e) { public List<S> getFromStates(S s, E e) {
@ -100,6 +112,7 @@ public class StateMachine2<S, E, V extends StateObject<S>> {
public boolean transitTo(V vo, E e, Object opaque, StateDao<S, E, V> dao) throws NoTransitionException { public boolean transitTo(V vo, E e, Object opaque, StateDao<S, E, V> dao) throws NoTransitionException {
S currentState = vo.getState(); S currentState = vo.getState();
S nextState = getNextState(currentState, e); S nextState = getNextState(currentState, e);
Transition<S, E> transition = getTransition(currentState, e);
boolean transitionStatus = true; boolean transitionStatus = true;
if (nextState == null) { if (nextState == null) {
@ -116,7 +129,7 @@ public class StateMachine2<S, E, V extends StateObject<S>> {
} }
for (StateListener<S, E, V> listener : _listeners) { for (StateListener<S, E, V> listener : _listeners) {
listener.postStateTransitionEvent(currentState, e, nextState, vo, transitionStatus, opaque); listener.postStateTransitionEvent(transition, vo, transitionStatus, opaque);
} }
return true; return true;
@ -138,21 +151,84 @@ public class StateMachine2<S, E, V extends StateObject<S>> {
return str.toString(); return str.toString();
} }
public static class Transition<S, E> {
private S currentState;
private E event;
private S toState;
private List<Impact> impacts;
public static enum Impact {
USAGE
}
public Transition(S currentState, E event, S toState, List<Impact> 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 { private class StateEntry {
public S state; public S state;
public HashMap<E, S> nextStates; public HashMap<E, Transition<S, E>> nextStates;
public HashMap<E, List<S>> prevStates; public HashMap<E, List<S>> prevStates;
public StateEntry(S state) { public StateEntry(S state) {
this.state = state; this.state = state;
nextStates = new HashMap<E, S>();
prevStates = new HashMap<E, List<S>>(); prevStates = new HashMap<E, List<S>>();
nextStates = new HashMap<E, Transition<S, E>>();
} }
public void addTransition(E e, S s) { public void addTransition(E e, S s, Transition<S, E> transition) {
assert !nextStates.containsKey(e) : "State " + getStateStr() + " already contains a transition to state " + nextStates.get(e).toString() + " via event " + 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(); 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) { public void addFromTransition(E e, S s) {
@ -172,7 +248,7 @@ public class StateMachine2<S, E, V extends StateObject<S>> {
public void buildString(StringBuilder str) { public void buildString(StringBuilder str) {
str.append("State: ").append(getStateStr()).append("\n"); str.append("State: ").append(getStateStr()).append("\n");
for (Map.Entry<E, S> nextState : nextStates.entrySet()) { for (Map.Entry<E, Transition<S, E>> nextState : nextStates.entrySet()) {
str.append(" --> Event: "); str.append(" --> Event: ");
Formatter format = new Formatter(); Formatter format = new Formatter();
str.append(format.format("%-30s", nextState.getKey().toString())); str.append(format.format("%-30s", nextState.getKey().toString()));