package org.zstack.network.l2.vxlan.vxlanNetworkPool;
import org.springframework.beans.factory.annotation.Autowired;
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.Q;
import org.zstack.core.errorcode.ErrorFacade;
import org.zstack.core.workflow.FlowChainBuilder;
import org.zstack.header.core.Completion;
import org.zstack.header.core.FutureCompletion;
import org.zstack.header.core.workflow.Flow;
import org.zstack.header.core.workflow.FlowChain;
import org.zstack.header.core.workflow.FlowTrigger;
import org.zstack.header.core.workflow.NoRollbackFlow;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.errorcode.OperationFailureException;
import org.zstack.header.host.*;
import org.zstack.header.message.MessageReply;
import org.zstack.header.network.l2.CheckL2NetworkOnHostMsg;
import org.zstack.header.network.l2.L2NetworkConstant;
import org.zstack.header.network.l2.L2NetworkInventory;
import org.zstack.header.network.l2.L2NetworkVO;
import org.zstack.kvm.KVMConstant;
import org.zstack.kvm.KVMHostConnectExtensionPoint;
import org.zstack.kvm.KVMHostConnectedContext;
import org.zstack.network.l2.vxlan.vxlanNetwork.*;
import org.zstack.utils.Utils;
import org.zstack.utils.logging.CLogger;
import javax.persistence.TypedQuery;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* Created by weiwang on 10/05/2017.
*/
public class KVMConnectExtensionForVxlanNetwork implements KVMHostConnectExtensionPoint, HostConnectionReestablishExtensionPoint {
private static final CLogger logger = Utils.getLogger(KVMConnectExtensionForVxlanNetwork.class);
@Autowired
private DatabaseFacade dbf;
@Autowired
private KVMRealizeL2VxlanNetworkBackend kvmRealizeL2VxlanNetworkBackend;
@Autowired
private ErrorFacade errf;
@Autowired
private CloudBus bus;
@Transactional
private List<L2NetworkInventory> getL2Networks(String clusterUuid) {
String sql = "select l2 from L2NetworkVO l2, L2NetworkClusterRefVO ref where l2.uuid = ref.l2NetworkUuid and ref.clusterUuid = :clusterUuid and l2.type in (:supportTypes)";
TypedQuery<L2NetworkVO> q = dbf.getEntityManager().createQuery(sql, L2NetworkVO.class);
q.setParameter("clusterUuid", clusterUuid);
q.setParameter("supportTypes", getSupportTypes());
List<L2NetworkVO> vos = q.getResultList();
List<L2NetworkInventory> ret = new ArrayList<L2NetworkInventory>(vos.size());
for (L2NetworkVO vo : vos) {
if (VxlanNetworkPoolConstant.VXLAN_NETWORK_POOL_TYPE.equals(vo.getType())) {
VxlanNetworkPoolVO poolvo = Q.New(VxlanNetworkPoolVO.class).eq(VxlanNetworkPoolVO_.uuid, vo.getUuid()).find();
ret.add(L2VxlanNetworkPoolInventory.valueOf(poolvo));
} else if (VxlanNetworkConstant.VXLAN_NETWORK_TYPE.equals(vo.getType())) {
VxlanNetworkVO vxlanvo = Q.New(VxlanNetworkVO.class).eq(VxlanNetworkVO_.uuid, vo.getUuid()).find();
ret.add(L2VxlanNetworkInventory.valueOf(vxlanvo));
} else {
logger.info(String.format("unsupport network type %s", vo.getType()));
}
}
return ret;
}
private List<String> getSupportTypes() {
List<String> types = Arrays.asList(VxlanNetworkPoolConstant.VXLAN_NETWORK_POOL_TYPE);
return types;
}
private void prepareNetwork(final Iterator<L2NetworkInventory> it, final String hostUuid, final Completion completion) {
if (!it.hasNext()) {
completion.success();
return;
}
final L2NetworkInventory l2 = it.next();
CheckL2NetworkOnHostMsg cmsg = new CheckL2NetworkOnHostMsg();
cmsg.setHostUuid(hostUuid);
cmsg.setL2NetworkUuid(l2.getUuid());
bus.makeTargetServiceIdByResourceUuid(cmsg, L2NetworkConstant.SERVICE_ID, l2.getUuid());
bus.send(cmsg, new CloudBusCallBack(completion) {
@Override
public void run(MessageReply reply) {
if (!reply.isSuccess()) {
completion.fail(reply.getError());
} else {
completion.success();
}
}
});
}
@Override
public void connectionReestablished(HostInventory inv) throws HostException {
//TODO: make connect async
List<L2NetworkInventory> l2s = getL2Networks(inv.getClusterUuid());
if (l2s.isEmpty()) {
return;
}
FutureCompletion completion = new FutureCompletion(null);
prepareNetwork(l2s.iterator(), inv.getUuid(), completion);
completion.await(TimeUnit.SECONDS.toMillis(600));
if (!completion.isSuccess()) {
throw new OperationFailureException(completion.getErrorCode());
}
}
@Override
public HypervisorType getHypervisorTypeForReestablishExtensionPoint() {
return new HypervisorType(KVMConstant.KVM_HYPERVISOR_TYPE);
}
@Override
public Flow createKvmHostConnectingFlow(final KVMHostConnectedContext context) {
return new NoRollbackFlow() {
String __name__ = "prepare-vxlan-network";
@Override
public void run(final FlowTrigger trigger, Map data) {
List<L2NetworkInventory> l2s = getL2Networks(context.getInventory().getClusterUuid());
if (l2s.isEmpty()) {
trigger.next();
return;
}
prepareNetwork(l2s.iterator(), context.getInventory().getUuid(), new Completion(trigger) {
@Override
public void success() {
trigger.next();
}
@Override
public void fail(ErrorCode errorCode) {
trigger.fail(errorCode);
}
});
}
};
}
}