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.cloudbus.CloudBus;
import org.zstack.core.cloudbus.CloudBusCallBack;
import org.zstack.core.componentloader.PluginRegistry;
import org.zstack.header.core.workflow.Flow;
import org.zstack.header.core.workflow.FlowRollback;
import org.zstack.header.core.workflow.FlowTrigger;
import org.zstack.header.host.HostConstant;
import org.zstack.header.message.MessageReply;
import org.zstack.header.vm.*;
import org.zstack.utils.Utils;
import org.zstack.utils.logging.CLogger;
import java.util.List;
import java.util.Map;
import static org.zstack.core.progress.ProgressReportService.taskProgress;
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
public class VmCreateOnHypervisorFlow implements Flow {
private static final CLogger logger = Utils.getLogger(VmCreateOnHypervisorFlow.class);
@Autowired
private CloudBus bus;
@Autowired
private PluginRegistry pluginRgty;
private static String SUCCESS = "VmCreateOnHypervisorFlow.success";
private List<VmBeforeCreateOnHypervisorExtensionPoint> exts;
public VmCreateOnHypervisorFlow() {
exts = pluginRgty.getExtensionList(VmBeforeCreateOnHypervisorExtensionPoint.class);
}
private void fireExtensions(VmInstanceSpec spec) {
for (VmBeforeCreateOnHypervisorExtensionPoint ext : exts) {
ext.beforeCreateVmOnHypervisor(spec);
}
}
@Override
public void run(final FlowTrigger chain, final Map data) {
taskProgress("start on the hypervisor");
final VmInstanceSpec spec = (VmInstanceSpec) data.get(VmInstanceConstant.Params.VmInstanceSpec.toString());
fireExtensions(spec);
CreateVmOnHypervisorMsg msg = new CreateVmOnHypervisorMsg();
msg.setVmSpec(spec);
bus.makeTargetServiceIdByResourceUuid(msg, HostConstant.SERVICE_ID, spec.getDestHost().getUuid());
bus.send(msg, new CloudBusCallBack(chain) {
@Override
public void run(MessageReply reply) {
if (reply.isSuccess()) {
data.put(SUCCESS, true);
chain.next();
} else {
chain.fail(reply.getError());
}
}
});
}
@Override
public void rollback(final FlowRollback trigger, Map data) {
if (!data.containsKey(SUCCESS)) {
trigger.rollback();
return;
}
final VmInstanceSpec spec = (VmInstanceSpec) data.get(VmInstanceConstant.Params.VmInstanceSpec.toString());
DestroyVmOnHypervisorMsg msg = new DestroyVmOnHypervisorMsg();
msg.setVmInventory(spec.getVmInventory());
msg.getVmInventory().setHostUuid(spec.getDestHost().getUuid());
bus.makeTargetServiceIdByResourceUuid(msg, HostConstant.SERVICE_ID, spec.getDestHost().getUuid());
bus.send(msg, new CloudBusCallBack(trigger) {
@Override
public void run(MessageReply reply) {
if (!reply.isSuccess()) {
logger.warn(String.format("failed to roll back vm[uuid:%s, name:%s] on host[uuid:%s, ip:%s], %s",
spec.getVmInventory().getUuid(), spec.getVmInventory().getName(),
spec.getDestHost().getUuid(), spec.getDestHost().getName(), reply.getError()));
}
trigger.rollback();
}
});
}
}