package org.zstack.compute.vm;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.zstack.core.errorcode.ErrorFacade;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.message.Message;
import org.zstack.header.vm.*;
import org.zstack.utils.message.OperationChecker;
import static org.zstack.core.Platform.i18n;
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
public abstract class AbstractVmInstance implements VmInstance {
protected static OperationChecker allowedOperations = new OperationChecker(true);
protected static OperationChecker stateChangeChecker = new OperationChecker(false);
@Autowired
protected ErrorFacade errf;
static {
allowedOperations.addState(VmInstanceState.Created,
StartNewCreatedVmInstanceMsg.class.getName(),
APIStartVmInstanceMsg.class.getName(),
StartVmInstanceMsg.class.getName()
);
allowedOperations.addState(VmInstanceState.Running,
APIStopVmInstanceMsg.class.getName(),
StopVmInstanceMsg.class.getName(),
APIRebootVmInstanceMsg.class.getName(),
RebootVmInstanceMsg.class.getName(),
APIDestroyVmInstanceMsg.class.getName(),
DestroyVmInstanceMsg.class.getName(),
APIMigrateVmMsg.class.getName(),
MigrateVmMsg.class.getName(),
AttachDataVolumeToVmMsg.class.getName(),
DetachDataVolumeFromVmMsg.class.getName(),
AttachNicToVmMsg.class.getName(),
VmAttachNicMsg.class.getName(),
APIAttachL3NetworkToVmMsg.class.getName(),
GetVmMigrationTargetHostMsg.class.getName(),
APIChangeInstanceOfferingMsg.class.getName(),
APIGetVmMigrationCandidateHostsMsg.class.getName(),
APIDetachL3NetworkFromVmMsg.class.getName(),
DetachNicFromVmMsg.class.getName(),
APIAttachIsoToVmInstanceMsg.class.getName(),
APIDetachIsoFromVmInstanceMsg.class.getName(),
APIGetVmConsoleAddressMsg.class.getName(),
APIDeleteVmStaticIpMsg.class.getName(),
APIPauseVmInstanceMsg.class.getName()
);
allowedOperations.addState(VmInstanceState.Stopped,
APIStopVmInstanceMsg.class.getName(),
APIDestroyVmInstanceMsg.class.getName(),
DestroyVmInstanceMsg.class.getName(),
APIStartVmInstanceMsg.class.getName(),
StartVmInstanceMsg.class.getName(),
AttachDataVolumeToVmMsg.class.getName(),
DetachDataVolumeFromVmMsg.class.getName(),
CreateTemplateFromVmRootVolumeMsg.class.getName(),
VmAttachNicMsg.class.getName(),
APIAttachL3NetworkToVmMsg.class.getName(),
APIChangeInstanceOfferingMsg.class.getName(),
StopVmInstanceMsg.class.getName(),
APIDetachL3NetworkFromVmMsg.class.getName(),
DetachNicFromVmMsg.class.getName(),
APIAttachIsoToVmInstanceMsg.class.getName(),
APIDetachIsoFromVmInstanceMsg.class.getName(),
APISetVmStaticIpMsg.class.getName(),
APIDeleteVmStaticIpMsg.class.getName(),
StartVmInstanceMsg.class.getName(),
HaStartVmInstanceMsg.class.getName(),
APIGetVmStartingCandidateClustersHostsMsg.class.getName()
);
allowedOperations.addState(VmInstanceState.Unknown,
APIDestroyVmInstanceMsg.class.getName(),
DestroyVmInstanceMsg.class.getName(),
APIStopVmInstanceMsg.class.getName(),
StopVmInstanceMsg.class.getName());
allowedOperations.addState(VmInstanceState.Starting,
APIDestroyVmInstanceMsg.class.getName(),
DestroyVmInstanceMsg.class.getName());
allowedOperations.addState(VmInstanceState.Migrating,
APIDestroyVmInstanceMsg.class.getName(),
DestroyVmInstanceMsg.class.getName());
allowedOperations.addState(VmInstanceState.Stopping,
APIDestroyVmInstanceMsg.class.getName(),
DestroyVmInstanceMsg.class.getName());
allowedOperations.addState(VmInstanceState.Rebooting,
APIDestroyVmInstanceMsg.class.getName(),
DestroyVmInstanceMsg.class.getName());
allowedOperations.addState(VmInstanceState.Destroyed,
ExpungeVmMsg.class.getName(),
APIExpungeVmInstanceMsg.class.getName(),
APIRecoverVmInstanceMsg.class.getName());
allowedOperations.addState(VmInstanceState.Paused,
APIResumeVmInstanceMsg.class.getName(),
APIStopVmInstanceMsg.class.getName(),
StopVmInstanceMsg.class.getName(),
APIDestroyVmInstanceMsg.class.getName(),
DestroyVmInstanceMsg.class.getName(),
APIMigrateVmMsg.class.getName(),
MigrateVmMsg.class.getName(),
AttachDataVolumeToVmMsg.class.getName(),
DetachDataVolumeFromVmMsg.class.getName(),
AttachNicToVmMsg.class.getName(),
VmAttachNicMsg.class.getName(),
APIAttachL3NetworkToVmMsg.class.getName(),
GetVmMigrationTargetHostMsg.class.getName(),
APIChangeInstanceOfferingMsg.class.getName(),
APIGetVmMigrationCandidateHostsMsg.class.getName(),
APIDetachL3NetworkFromVmMsg.class.getName(),
DetachNicFromVmMsg.class.getName(),
APIAttachIsoToVmInstanceMsg.class.getName(),
APIDetachIsoFromVmInstanceMsg.class.getName(),
APIGetVmConsoleAddressMsg.class.getName(),
APIDeleteVmStaticIpMsg.class.getName());
allowedOperations.addState(VmInstanceState.Pausing,
APIDestroyVmInstanceMsg.class.getName(),
DestroyVmInstanceMsg.class.getName());
allowedOperations.addState(VmInstanceState.Resuming,
APIDestroyVmInstanceMsg.class.getName(),
DestroyVmInstanceMsg.class.getName());
stateChangeChecker.addState(VmInstanceStateEvent.unknown.toString(),
VmInstanceState.Created.toString(),
VmInstanceState.Stopped.toString(),
VmInstanceState.Destroyed.toString(),
VmInstanceState.Expunging.toString());
}
private ErrorCode validateOperationByState(OperationChecker checker, Message msg, VmInstanceState currentState, Enum errorCode) {
if (checker.isOperationAllowed(msg.getMessageName(), currentState.toString())) {
return null;
} else {
String details = i18n("current vm instance state[%s] doesn't allow to proceed message[%s], allowed states are %s", currentState,
msg.getMessageName(), checker.getStatesForOperation(msg.getMessageName()));
ErrorCode cause = errf.instantiateErrorCode(VmErrors.NOT_IN_CORRECT_STATE, details);
if (errorCode != null) {
return errf.instantiateErrorCode(errorCode, cause);
} else {
return cause;
}
}
}
public ErrorCode validateOperationByState(Message msg, VmInstanceState currentState, Enum errorCode) {
return validateOperationByState(allowedOperations, msg, currentState, errorCode);
}
public static boolean needChangeState(OperationChecker checker, VmInstanceStateEvent stateEvent, VmInstanceState currentState) {
return checker.isOperationAllowed(stateEvent.toString(), currentState.toString(), false);
}
public static boolean needChangeState(VmInstanceStateEvent stateEvent, VmInstanceState currentState) {
return needChangeState(stateChangeChecker, stateEvent, currentState);
}
}