package org.zstack.simulator;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.zstack.compute.host.HostBase;
import org.zstack.core.componentloader.PluginRegistry;
import org.zstack.core.errorcode.ErrorFacade;
import org.zstack.header.core.Completion;
import org.zstack.header.host.*;
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.Message;
import org.zstack.header.message.MessageReply;
import org.zstack.header.network.l2.CheckNetworkPhysicalInterfaceMsg;
import org.zstack.header.network.l2.CheckNetworkPhysicalInterfaceReply;
import org.zstack.header.simulator.*;
import org.zstack.header.vm.*;
import org.zstack.utils.Utils;
import org.zstack.utils.gson.JSONObjectUtil;
import org.zstack.utils.logging.CLogger;
import java.util.ArrayList;
import java.util.List;
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
class SimulatorHost extends HostBase {
private static final CLogger logger = Utils.getLogger(SimulatorHost.class);
private SimulatorConnection conn;
private volatile boolean isDisconnected;
@Autowired
private PluginRegistry pluginRegty;
@Autowired
private ErrorFacade errf;
@Autowired
private SimulatorConfig config;
protected SimulatorHost(SimulatorHostVO self) {
super(self);
conn = new SimulatorConnectionImpl(this);
}
@Override
public void changeStateHook(HostState current, HostStateEvent stateEvent, HostState next) {
logger.debug(String.format("Host: %s changed state from %s to %s by %s", self.getName(), current, next, stateEvent));
}
@Override
public void deleteHook() {
logger.debug(String.format("Host: %s is being deleted", self.getName()));
}
@Override
public void connectHook(ConnectHostInfo info, Completion complete) {
for (SimulatorConnectExtensionPoint sc : pluginRegty.getExtensionList(SimulatorConnectExtensionPoint.class)) {
String err = sc.connect(conn);
if (err != null) {
logger.warn(err);
complete.fail(errf.stringToOperationError(err));
return;
}
}
logger.debug(String.format("Host: %s is connected", self.getName()));
complete.success();
}
@Override
public void maintenanceHook(Completion completion) {
logger.debug(String.format("Host: %s entered maintenance mode", self.getName()));
completion.success();
}
SimulatorHostVO getSimulatorHostVO() {
return (SimulatorHostVO) self;
}
@Override
protected void pingHook(Completion completion) {
if (!isDisconnected) {
completion.success();
} else {
completion.fail(errf.stringToOperationError("set to disconnected"));
}
}
@Override
protected int getVmMigrateQuantity() {
return 1;
}
@Override
protected void handleApiMessage(APIMessage msg) {
super.handleApiMessage(msg);
}
@Override
protected void handleLocalMessage(Message msg) {
if (msg instanceof CheckNetworkPhysicalInterfaceMsg) {
handle((CheckNetworkPhysicalInterfaceMsg) msg);
} else if (msg instanceof SimulatorHostConnectionControlMsg) {
handle((SimulatorHostConnectionControlMsg) msg);
} else if (msg instanceof ChangeVmStateOnSimulatorHostMsg) {
handle((ChangeVmStateOnSimulatorHostMsg) msg);
} else if (msg instanceof RemoveVmOnSimulatorMsg) {
handle((RemoveVmOnSimulatorMsg) msg);
} else if (msg instanceof TakeSnapshotOnHypervisorMsg) {
handle((TakeSnapshotOnHypervisorMsg) msg);
} else if (msg instanceof DetachNicFromVmOnHypervisorMsg) {
handle((DetachNicFromVmOnHypervisorMsg) msg);
} else if (msg instanceof VmAttachNicOnHypervisorMsg) {
handle((VmAttachNicOnHypervisorMsg) msg);
} else if (msg instanceof CreateVmOnHypervisorMsg) {
handle((CreateVmOnHypervisorMsg) msg);
} else if (msg instanceof StopVmOnHypervisorMsg) {
handle((StopVmOnHypervisorMsg) msg);
} else if (msg instanceof RebootVmOnHypervisorMsg) {
handle((RebootVmOnHypervisorMsg) msg);
} else if (msg instanceof StartVmOnHypervisorMsg) {
handle((StartVmOnHypervisorMsg) msg);
} else if (msg instanceof MigrateVmOnHypervisorMsg) {
handle((MigrateVmOnHypervisorMsg) msg);
} else if (msg instanceof AttachVolumeToVmOnHypervisorMsg) {
handle((AttachVolumeToVmOnHypervisorMsg) msg);
} else if (msg instanceof DetachVolumeFromVmOnHypervisorMsg) {
handle((DetachVolumeFromVmOnHypervisorMsg) msg);
} else if (msg instanceof DestroyVmOnHypervisorMsg) {
handle((DestroyVmOnHypervisorMsg) msg);
} else {
super.handleLocalMessage(msg);
}
}
private void handle(MigrateVmOnHypervisorMsg msg) {
MigrateVmOnHypervisorReply reply = new MigrateVmOnHypervisorReply();
if (!config.migrateSuccess) {
reply.setError(errf.stringToOperationError("on purpose"));
} else {
logger.debug(String.format("Successfully migrate vm[uuid:%s] on simulator host[uuid:%s] to host[uuid:%s]", msg.getVmInventory().getUuid(), self.getUuid(), msg.getDestHostInventory().getUuid()));
config.removeVm(msg.getSrcHostUuid(), msg.getVmInventory().getUuid());
config.putVm(msg.getDestHostInventory().getUuid(), msg.getVmInventory().getUuid(), VmInstanceState.Running);
}
bus.reply(msg, reply);
}
private void handle(VmAttachNicOnHypervisorMsg msg) {
bus.reply(msg, new VmAttachNicOnHypervisorReply());
}
private void handle(DetachNicFromVmOnHypervisorMsg msg) {
DetachNicFromVmOnHypervisorReply reply = new DetachNicFromVmOnHypervisorReply();
bus.reply(msg, reply);
}
private void handle(TakeSnapshotOnHypervisorMsg msg) {
TakeSnapshotOnHypervisorReply reply = new TakeSnapshotOnHypervisorReply();
if (!config.snapshotSuccess) {
reply.setError(errf.stringToOperationError("on purpose"));
bus.reply(msg, reply);
return;
}
List<TakeSnapshotOnHypervisorMsg> lst = config.snapshots.get(msg.getHostUuid());
lst = new ArrayList<TakeSnapshotOnHypervisorMsg>();
lst.add(msg);
config.snapshots.put(msg.getHostUuid(), lst);
}
private void handle(RemoveVmOnSimulatorMsg msg) {
logger.debug(String.format("Successfully remove vm[uuid:%s] on simulator host[uuid:%s]", msg.getVmUuid(), msg.getHostUuid()));
removeVm(msg.getVmUuid());
MessageReply reply = new MessageReply();
bus.reply(msg, reply);
}
private void handle(ChangeVmStateOnSimulatorHostMsg msg) {
synchronized (config.vms) {
if (!config.containVm(msg.getVmUuid())) {
logger.warn(String.format("Cannot find vm[uuid:%s] on simulator host[uuid:%s], it's a stranger vm", msg.getVmUuid(), self.getUuid()));
} else {
logger.debug(String.format("Change state of vm[uuid:%s] on simulator host[uuid:%s] to %s", msg.getVmUuid(), self.getUuid(), msg.getVmState()));
}
String hostUuid = msg.getHostUuid() == null ? self.getUuid() : msg.getHostUuid();
config.putVm(hostUuid, msg.getVmUuid(), VmInstanceState.valueOf(msg.getVmState()));
}
MessageReply reply = new MessageReply();
bus.reply(msg, reply);
}
private void handle(SimulatorHostConnectionControlMsg msg) {
logger.debug(String.format("Change simulator[uuid:%s] isDisonnected to %s", self.getUuid(), msg.isDisconnected()));
isDisconnected = msg.isDisconnected();
MessageReply reply = new MessageReply();
bus.reply(msg, reply);
}
private void handle(CheckNetworkPhysicalInterfaceMsg msg) {
logger.debug(String.format("Successfully checked physical network interface %s on simulator host", msg.getPhysicalInterface()));
CheckNetworkPhysicalInterfaceReply reply = new CheckNetworkPhysicalInterfaceReply();
bus.reply(msg, reply);
}
private void handle(DestroyVmOnHypervisorMsg msg) {
logger.debug(String.format("Successfully destroyed vm on simulator host[uuid:%s], %s", self.getUuid(), JSONObjectUtil.toJsonString(msg.getVmInventory())));
DestroyVmOnHypervisorReply reply = new DestroyVmOnHypervisorReply();
bus.reply(msg, reply);
}
private void handle(DetachVolumeFromVmOnHypervisorMsg msg) {
logger.debug(String.format("Successfully detached volume[uuid:%s] to vm[uuid:%s] on simulator host[uuid:%s]", msg.getInventory().getUuid(), msg.getVmInventory().getUuid(), self.getUuid()));
DetachVolumeFromVmOnHypervisorReply reply = new DetachVolumeFromVmOnHypervisorReply();
bus.reply(msg, reply);
}
private void handle(AttachVolumeToVmOnHypervisorMsg msg) {
logger.debug(String.format("Successfully attached volume[uuid:%s] to vm[uuid:%s] on simulator host[uuid:%s]", msg.getInventory().getUuid(), msg.getVmInventory().getUuid(), self.getUuid()));
AttachVolumeToVmOnHypervisorReply reply = new AttachVolumeToVmOnHypervisorReply();
bus.reply(msg, reply);
}
private void handle(StartVmOnHypervisorMsg msg) {
logger.debug(String.format("Successfully started vm on simulator host[uuid:%s], %s", self.getUuid(), JSONObjectUtil.toJsonString(msg.getVmSpec())));
StartVmOnHypervisorReply reply = new StartVmOnHypervisorReply();
setVmState(msg.getVmSpec().getVmInventory().getUuid(), VmInstanceState.Running);
bus.reply(msg, reply);
}
private void handle(StopVmOnHypervisorMsg msg) {
logger.debug(String.format("Successfully stopped vm on simulator host[uuid:%s], %s", self.getUuid(), JSONObjectUtil.toJsonString(msg.getVmInventory())));
StopVmOnHypervisorReply reply = new StopVmOnHypervisorReply();
setVmState(msg.getVmInventory().getUuid(), VmInstanceState.Stopped);
bus.reply(msg, reply);
}
private void handle(CreateVmOnHypervisorMsg msg) {
logger.debug(String.format("Successfully created vm on simulator host[uuid:%s], %s", self.getUuid(), JSONObjectUtil.toJsonString(msg.getVmSpec())));
CreateVmOnHypervisorReply reply = new CreateVmOnHypervisorReply();
setVmState(msg.getVmSpec().getVmInventory().getUuid(), VmInstanceState.Running);
bus.reply(msg, reply);
}
private void handle(RebootVmOnHypervisorMsg msg) {
logger.debug(String.format("Successfully rebooted vm on simulator host[uuid:%s], %s", self.getUuid(), JSONObjectUtil.toJsonString(msg.getVmInventory())));
RebootVmOnHypervisorReply reply = new RebootVmOnHypervisorReply();
setVmState(msg.getVmInventory().getUuid(), VmInstanceState.Running);
bus.reply(msg, reply);
}
void setVmState(String vmUuid, VmInstanceState state) {
synchronized (config.vms) {
config.putVm(self.getUuid(), vmUuid, state);
}
}
void removeVm(String vmUuid) {
synchronized (config.vms) {
config.removeVm(self.getUuid(), vmUuid);
}
}
}