package org.zstack.network.service.virtualrouter.vip;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.transaction.annotation.Transactional;
import org.zstack.core.db.DatabaseFacade;
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.core.Completion;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.vm.VmInstanceState;
import org.zstack.header.vm.VmNicInventory;
import org.zstack.network.service.eip.EipConstant;
import org.zstack.network.service.portforwarding.PortForwardingConstant;
import org.zstack.network.service.vip.VipInventory;
import org.zstack.network.service.vip.VipVO;
import org.zstack.network.service.virtualrouter.VirtualRouterConstant;
import org.zstack.network.service.virtualrouter.VirtualRouterSystemTags;
import org.zstack.network.service.virtualrouter.VirtualRouterVmInventory;
import org.zstack.network.service.virtualrouter.VirtualRouterManager;
import javax.persistence.TypedQuery;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
public class VirtualRouterSyncVipForNewCreateFlow implements Flow {
@Autowired
protected DatabaseFacade dbf;
@Autowired
@Qualifier("VirtualRouterVipBackend")
protected VirtualRouterVipBackend vipExt;
@Autowired
protected VirtualRouterManager vrMgr;
@Override
public void run(final FlowTrigger chain, Map data) {
final VirtualRouterVmInventory vr = (VirtualRouterVmInventory) data.get(VirtualRouterConstant.Param.VR.toString());
final VmNicInventory guestNic = vr.getGuestNic();
final VmNicInventory publicNic = vr.getPublicNic();
List<String> vipUuids = new ArrayList<String>();
if (vrMgr.isL3NetworkNeedingNetworkServiceByVirtualRouter(guestNic.getL3NetworkUuid(), EipConstant.EIP_NETWORK_SERVICE_TYPE) &&
!(VirtualRouterSystemTags.DEDICATED_ROLE_VR.hasTag(vr.getUuid()) && !VirtualRouterSystemTags.VR_EIP_ROLE.hasTag(vr.getUuid()))) {
vipUuids.addAll(new Callable<List<String>>() {
@Override
@Transactional(readOnly = true)
public List<String> call() {
String sql = "select vip.uuid from EipVO eip, VmNicVO nic, VipVO vip, VmInstanceVO vm where vm.uuid = nic.vmInstanceUuid and vm.state = :vmState and eip.vipUuid = vip.uuid and eip.vmNicUuid = nic.uuid and vip.l3NetworkUuid = :vipL3Uuid and nic.l3NetworkUuid = :guestL3Uuid";
TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class);
q.setParameter("vipL3Uuid", publicNic.getL3NetworkUuid());
q.setParameter("guestL3Uuid", guestNic.getL3NetworkUuid());
q.setParameter("vmState", VmInstanceState.Running);
return q.getResultList();
}
}.call());
}
if (vrMgr.isL3NetworkNeedingNetworkServiceByVirtualRouter(guestNic.getL3NetworkUuid(), PortForwardingConstant.PORTFORWARDING_NETWORK_SERVICE_TYPE) &&
!(VirtualRouterSystemTags.DEDICATED_ROLE_VR.hasTag(vr.getUuid()) && !VirtualRouterSystemTags.VR_PORT_FORWARDING_ROLE.hasTag(vr.getUuid()))) {
vipUuids.addAll(new Callable<List<String>>() {
@Override
@Transactional(readOnly = true)
public List<String> call() {
String sql = "select vip.uuid from PortForwardingRuleVO rule, VmNicVO nic, VipVO vip, VmInstanceVO vm where vm.uuid = nic.vmInstanceUuid and vm.state = :vmState and rule.vipUuid = vip.uuid and rule.vmNicUuid = nic.uuid and vip.l3NetworkUuid = :vipL3Uuid and nic.l3NetworkUuid = :guestL3Uuid";
TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class);
q.setParameter("vipL3Uuid", publicNic.getL3NetworkUuid());
q.setParameter("guestL3Uuid", guestNic.getL3NetworkUuid());
q.setParameter("vmState", VmInstanceState.Running);
return q.getResultList();
}
}.call());
}
if (vipUuids.isEmpty()) {
chain.next();
return;
}
List<VirtualRouterVipVO> refs = new ArrayList<VirtualRouterVipVO>();
for (String vipUuid : vipUuids) {
VirtualRouterVipVO ref = new VirtualRouterVipVO();
ref.setUuid(vipUuid);
ref.setVirtualRouterVmUuid(vr.getUuid());
refs.add(ref);
}
dbf.persistCollection(refs);
data.put(VirtualRouterSyncVipForNewCreateFlow.class.getName(), refs);
List<VipVO> vips = dbf.listByPrimaryKeys(vipUuids, VipVO.class);
List<VipInventory> invs = VipInventory.valueOf(vips);
vipExt.createVipOnVirtualRouterVm(vr, invs, new Completion(chain) {
@Override
public void success() {
chain.next();
}
@Override
public void fail(ErrorCode errorCode) {
chain.fail(errorCode);
}
});
}
@Override
public void rollback(FlowRollback trigger, Map data) {
List<VirtualRouterVipVO> refs = (List<VirtualRouterVipVO>) data.get(VirtualRouterSyncVipForNewCreateFlow.class.getName());
if (refs != null) {
dbf.removeCollection(refs, VirtualRouterVipVO.class);
}
trigger.rollback();
}
}