package org.zstack.kvm; 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.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.*; 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.*; import org.zstack.utils.Utils; import org.zstack.utils.logging.CLogger; import javax.persistence.TypedQuery; import java.util.*; import java.util.concurrent.TimeUnit; import static org.zstack.core.Platform.operr; /** */ public class KVMConnectExtensionForL2Network implements KVMHostConnectExtensionPoint, HostConnectionReestablishExtensionPoint { @Autowired private DatabaseFacade dbf; @Autowired private KVMRealizeL2NoVlanNetworkBackend noVlanNetworkBackend; @Autowired private KVMRealizeL2VlanNetworkBackend vlanNetworkBackend; @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 (L2NetworkConstant.L2_VLAN_NETWORK_TYPE.equals(vo.getType())) { L2VlanNetworkVO vlanvo = dbf.getEntityManager().find(L2VlanNetworkVO.class, vo.getUuid()); ret.add(L2VlanNetworkInventory.valueOf(vlanvo)); } else { ret.add(L2NetworkInventory.valueOf(vo)); } } return ret; } private List<String> getSupportTypes() { List<String> types = Arrays.asList(L2NetworkConstant.L2_NO_VLAN_NETWORK_TYPE, L2NetworkConstant.L2_VLAN_NETWORK_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(); FlowChain chain = FlowChainBuilder.newSimpleFlowChain(); chain.setName(String.format("prepare-l2-%s-for-kvm-%s-connect", l2.getUuid(), hostUuid)); chain.then(new NoRollbackFlow() { @Override public void run(final FlowTrigger trigger, Map data) { CheckNetworkPhysicalInterfaceMsg cmsg = new CheckNetworkPhysicalInterfaceMsg(); cmsg.setHostUuid(hostUuid); cmsg.setPhysicalInterface(l2.getPhysicalInterface()); bus.makeTargetServiceIdByResourceUuid(cmsg, HostConstant.SERVICE_ID, hostUuid); bus.send(cmsg, new CloudBusCallBack(completion) { @Override public void run(MessageReply reply) { if (!reply.isSuccess()) { trigger.fail(reply.getError()); } else { trigger.next(); } } }); } }); if (l2.getType().equals(L2NetworkConstant.L2_NO_VLAN_NETWORK_TYPE)) { chain.then(new NoRollbackFlow() { @Override public void run(final FlowTrigger trigger, Map data) { noVlanNetworkBackend.realize(l2, hostUuid, true, new Completion(trigger) { @Override public void success() { trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } }); } else if (L2NetworkConstant.L2_VLAN_NETWORK_TYPE.equals(l2.getType())) { chain.then(new NoRollbackFlow() { @Override public void run(final FlowTrigger trigger, Map data) { vlanNetworkBackend.realize(l2, hostUuid, true, new Completion(trigger) { @Override public void success() { trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } }); } else { completion.fail(operr("KVMConnectExtensionForL2Network wont's support L2Network[type:%s]", l2.getType())); return; } chain.done(new FlowDoneHandler(completion) { @Override public void handle(Map data) { prepareNetwork(it, hostUuid, completion); } }).error(new FlowErrorHandler(completion) { @Override public void handle(ErrorCode errCode, Map data) { completion.fail(errCode); } }).start(); } @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-l2-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); } }); } }; } }