package org.zstack.network.service.flat; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.zstack.core.cloudbus.AutoOffEventCallback; import org.zstack.core.cloudbus.EventFacade; import org.zstack.core.db.DatabaseFacade; import org.zstack.core.errorcode.ErrorFacade; import org.zstack.header.Component; import org.zstack.header.errorcode.ErrorCode; import org.zstack.header.host.HostCanonicalEvents; import org.zstack.header.host.HostCanonicalEvents.HostStatusChangedData; import org.zstack.header.host.HostErrors; import org.zstack.header.host.HostStatus; import org.zstack.header.network.l3.L3NetworkInventory; import org.zstack.header.network.l3.L3NetworkVO; import org.zstack.header.network.service.NetworkServiceType; import org.zstack.kvm.KVMConstant; import org.zstack.kvm.KvmCommandSender; import org.zstack.kvm.KvmCommandSender.SteppingSendCallback; import org.zstack.kvm.KvmResponseWrapper; import org.zstack.network.service.flat.FlatDhcpBackend.DeleteNamespaceCmd; import org.zstack.network.service.flat.FlatDhcpBackend.DeleteNamespaceRsp; import org.zstack.utils.Utils; import org.zstack.utils.logging.CLogger; import javax.persistence.Tuple; import javax.persistence.TypedQuery; import java.util.ArrayList; import java.util.List; import java.util.Map; import static org.zstack.core.Platform.operr; /** * Created by xing5 on 2016/6/25. */ public class FlatDhcpUpgradeExtension implements Component { private static final CLogger logger = Utils.getLogger(FlatDhcpUpgradeExtension.class); @Autowired private DatabaseFacade dbf; @Autowired private EventFacade evtf; @Autowired private ErrorFacade errf; class L3Host { String hostUuid; L3NetworkInventory l3; } @Transactional(readOnly = true) private List<L3Host> findL3NeedToDeleteDeprecatedNameSpace() { String sql = "select l3.uuid from L3NetworkVO l3, NetworkServiceL3NetworkRefVO ref, NetworkServiceProviderVO provider" + " where l3.uuid = ref.l3NetworkUuid and ref.networkServiceProviderUuid = provider.uuid" + " and ref.networkServiceType = :nsType and provider.type = :ptype"; TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("nsType", NetworkServiceType.DHCP.toString()); q.setParameter("ptype", FlatNetworkServiceConstant.FLAT_NETWORK_SERVICE_TYPE_STRING); List<String> l3Uuids = q.getResultList(); if (l3Uuids.isEmpty()) { return null; } sql = "select l3, host.uuid from L3NetworkVO l3, HostVO host, L2NetworkClusterRefVO ref where host.hypervisorType = :htype and l3.uuid in (:uuids)" + " and ref.l2NetworkUuid = l3.l2NetworkUuid and host.clusterUuid = ref.clusterUuid"; TypedQuery<Tuple> tq = dbf.getEntityManager().createQuery(sql, Tuple.class); tq.setParameter("htype", KVMConstant.KVM_HYPERVISOR_TYPE); tq.setParameter("uuids", l3Uuids); List<Tuple> ts = tq.getResultList(); if (ts.isEmpty()) { return null; } List<L3Host> ret = new ArrayList<>(); for (Tuple t : ts) { L3NetworkVO l3 = t.get(0, L3NetworkVO.class); String huuid = t.get(1, String.class); L3Host lh = new L3Host(); lh.hostUuid= huuid; lh.l3 = L3NetworkInventory.valueOf(l3); ret.add(lh); } return ret; } @Override public boolean start() { if (FlatNetworkGlobalProperty.DELETE_DEPRECATED_DHCP_NAME_SPACE) { deleteDeprecatedDHCPNameSpace(); } return true; } private void deleteDeprecatedDHCPNameSpace() { List<L3Host> l3Hosts = findL3NeedToDeleteDeprecatedNameSpace(); if (l3Hosts == null) { return; } logger.debug(String.format("will delete deprecated DHCP namespace on %s hosts", l3Hosts.size())); for (L3Host l3Host : l3Hosts) { evtf.onLocal(HostCanonicalEvents.HOST_STATUS_CHANGED_PATH, new AutoOffEventCallback() { @Override protected boolean run(Map tokens, Object data) { HostStatusChangedData d = (HostStatusChangedData) data; if (!HostStatus.Connected.toString().equals(d.getNewStatus())) { return false; } L3NetworkInventory l3 = l3Host.l3; String brName = new BridgeNameFinder().findByL3Uuid(l3.getUuid()); DeleteNamespaceCmd cmd = new DeleteNamespaceCmd(); cmd.bridgeName = brName; cmd.namespaceName = brName; new KvmCommandSender(l3Host.hostUuid).send(cmd, FlatDhcpBackend.DHCP_DELETE_NAMESPACE_PATH, wrapper -> { DeleteNamespaceRsp rsp = wrapper.getResponse(DeleteNamespaceRsp.class); return rsp.isSuccess() ? null : operr(rsp.getError()); }, new SteppingSendCallback<KvmResponseWrapper>() { @Override public void success(KvmResponseWrapper w) { logger.debug(String.format("successfully deleted namespace for L3 network[uuid:%s, name:%s] on the " + "KVM host[uuid:%s]", l3.getUuid(), l3.getName(), getHostUuid())); } @Override public void fail(ErrorCode errorCode) { if (!errorCode.isError(HostErrors.OPERATION_FAILURE_GC_ELIGIBLE)) { return; } FlatDHCPDeleteNamespaceGC gc = new FlatDHCPDeleteNamespaceGC(); gc.hostUuid = getHostUuid(); gc.command = cmd; gc.NAME = String.format("gc-namespace-on-host-%s", getHostUuid()); gc.submit(); } }); return true; } }); } } @Override public boolean stop() { return true; } }