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.springframework.transaction.annotation.Transactional;
import org.zstack.core.cloudbus.CloudBus;
import org.zstack.core.cloudbus.CloudBusCallBack;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.db.SimpleQuery;
import org.zstack.core.db.UpdateQuery;
import org.zstack.core.errorcode.ErrorFacade;
import org.zstack.header.allocator.*;
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.HostInventory;
import org.zstack.header.message.MessageReply;
import org.zstack.header.network.l3.L3NetworkInventory;
import org.zstack.header.vm.*;
import org.zstack.utils.CollectionUtils;
import org.zstack.utils.function.Function;
import java.util.Map;
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
public class VmAllocateHostForStoppedVmFlow implements Flow {
@Autowired
protected DatabaseFacade dbf;
@Autowired
protected CloudBus bus;
@Autowired
protected ErrorFacade errf;
private static final String SUCCESS = VmAllocateHostForStoppedVmFlow.class.getName();
@Override
public void run(final FlowTrigger chain, final Map data) {
final VmInstanceSpec spec = (VmInstanceSpec) data.get(VmInstanceConstant.Params.VmInstanceSpec.toString());
AllocateHostMsg amsg;
DesignatedAllocateHostMsg msg = new DesignatedAllocateHostMsg();
msg.setVmInstance(spec.getVmInventory());
msg.setCpuCapacity(spec.getVmInventory().getCpuNum());
msg.setMemoryCapacity(spec.getVmInventory().getMemorySize());
msg.setVmOperation(spec.getCurrentVmOperation().toString());
if ((spec.getRequiredClusterUuid() != null &&
!spec.getRequiredClusterUuid().equals(msg.getVmInstance().getClusterUuid()))
|| spec.getRequiredHostUuid() != null) {
msg.setAllocatorStrategy(HostAllocatorConstant.DESIGNATED_HOST_ALLOCATOR_STRATEGY_TYPE);
msg.setHostUuid(spec.getRequiredHostUuid());
} else {
msg.setAllocatorStrategy(HostAllocatorConstant.LEAST_VM_PREFERRED_HOST_ALLOCATOR_STRATEGY_TYPE);
}
msg.setL3NetworkUuids(CollectionUtils.transformToList(spec.getL3Networks(), new Function<String, L3NetworkInventory>() {
@Override
public String call(L3NetworkInventory arg) {
return arg.getUuid();
}
}));
msg.setClusterUuid(spec.getRequiredClusterUuid());
msg.setServiceId(bus.makeLocalServiceId(HostAllocatorConstant.SERVICE_ID));
amsg = msg;
bus.send(amsg, new CloudBusCallBack(chain) {
@Override
public void run(MessageReply reply) {
if (reply.isSuccess()) {
AllocateHostReply areply = (AllocateHostReply) reply;
spec.setDestHost(areply.getHost());
UpdateQuery q = UpdateQuery.New(VmInstanceVO.class);
q.condAnd(VmInstanceVO_.uuid, SimpleQuery.Op.EQ, spec.getVmInventory().getUuid());
q.set(VmInstanceVO_.lastHostUuid, spec.getVmInventory().getHostUuid());
q.set(VmInstanceVO_.hostUuid, areply.getHost().getUuid());
q.set(VmInstanceVO_.clusterUuid, areply.getHost().getClusterUuid());
q.update();
data.put(SUCCESS, true);
chain.next();
} else {
chain.fail(reply.getError());
}
}
});
}
@Override
public void rollback(FlowRollback chain, Map data) {
final VmInstanceSpec spec = (VmInstanceSpec) data.get(VmInstanceConstant.Params.VmInstanceSpec.toString());
if (data.containsKey(SUCCESS)) {
VmInstanceVO vm = dbf.findByUuid(spec.getVmInventory().getUuid(), VmInstanceVO.class);
vm.setHostUuid(null);
dbf.update(vm);
HostInventory host = spec.getDestHost();
ReturnHostCapacityMsg msg = new ReturnHostCapacityMsg();
msg.setCpuCapacity(spec.getVmInventory().getCpuNum());
msg.setMemoryCapacity(spec.getVmInventory().getMemorySize());
msg.setHostUuid(host.getUuid());
msg.setServiceId(bus.makeLocalServiceId(HostAllocatorConstant.SERVICE_ID));
bus.send(msg);
}
chain.rollback();
}
}