package org.zstack.compute.allocator;
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.CoreGlobalProperty;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.header.allocator.AbstractHostAllocatorFlow;
import org.zstack.header.exception.CloudRuntimeException;
import org.zstack.header.host.HostVO;
import org.zstack.header.network.l2.L2NetworkClusterRefVO;
import org.zstack.utils.Utils;
import org.zstack.utils.logging.CLogger;
import javax.persistence.TypedQuery;
import java.util.*;
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
public class AttachedL2NetworkAllocatorFlow extends AbstractHostAllocatorFlow {
private static final CLogger logger = Utils.getLogger(AttachedL2NetworkAllocatorFlow.class);
@Autowired
private DatabaseFacade dbf;
@Transactional(readOnly = true)
private List<HostVO> allocate(Collection<String> l3NetworkUuids, Collection<String> hostUuids) {
String sql = "select l3.l2NetworkUuid from L3NetworkVO l3 where l3.uuid in (:l3uuids)";
TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class);
q.setParameter("l3uuids", l3NetworkUuids);
List<String> l2uuids = q.getResultList();
if (l2uuids.isEmpty()) {
return new ArrayList<>();
}
sql = "select ref from L2NetworkClusterRefVO ref where ref.l2NetworkUuid in (:l2uuids)";
TypedQuery<L2NetworkClusterRefVO> rq = dbf.getEntityManager().createQuery(sql, L2NetworkClusterRefVO.class);
rq.setParameter("l2uuids", l2uuids);
List<L2NetworkClusterRefVO> refs = rq.getResultList();
if (refs.isEmpty()) {
return new ArrayList<>();
}
Map<String, Set<String>> l2ClusterMap = new HashMap<>();
for (L2NetworkClusterRefVO ref : refs) {
Set<String> l2s = l2ClusterMap.get(ref.getClusterUuid());
if (l2s == null) {
l2s = new HashSet<>();
l2ClusterMap.put(ref.getClusterUuid(), l2s);
}
l2s.add(ref.getL2NetworkUuid());
}
Set<String> clusterUuids = new HashSet<>();
for (Map.Entry<String, Set<String>> e : l2ClusterMap.entrySet()) {
if (e.getValue().containsAll(l2uuids)) {
clusterUuids.add(e.getKey());
}
}
if (clusterUuids.isEmpty()) {
return new ArrayList<>();
}
if (hostUuids.isEmpty()) {
sql = "select h from HostVO h where h.clusterUuid in (:cuuids)";
TypedQuery<HostVO> hq = dbf.getEntityManager().createQuery(sql, HostVO.class);
hq.setParameter("cuuids", clusterUuids);
if (usePagination()) {
hq.setFirstResult(paginationInfo.getOffset());
hq.setMaxResults(paginationInfo.getLimit());
}
return hq.getResultList();
} else {
sql = "select h from HostVO h where h.clusterUuid in (:cuuids) and h.uuid in (:huuids)";
TypedQuery<HostVO> hq = dbf.getEntityManager().createQuery(sql, HostVO.class);
hq.setParameter("cuuids", clusterUuids);
hq.setParameter("huuids", hostUuids);
if (usePagination()) {
hq.setFirstResult(paginationInfo.getOffset());
hq.setMaxResults(paginationInfo.getLimit());
}
return hq.getResultList();
}
}
@Override
public void allocate() {
if (spec.getL3NetworkUuids().isEmpty()) {
if (CoreGlobalProperty.UNIT_TEST_ON || spec.isAllowNoL3Networks()) {
skip();
return;
} else {
throw new CloudRuntimeException("l3Network uuids can not be empty AttachedL2NetworkAllocatorFlow");
}
}
if (amITheFirstFlow()) {
candidates = allocate(spec.getL3NetworkUuids(), new ArrayList<>());
} else {
candidates = allocate(spec.getL3NetworkUuids(), getHostUuidsFromCandidates());
}
if (candidates.isEmpty()) {
fail(String.format("no host found in clusters that has attached to L2Networks which have L3Networks%s", spec.getL3NetworkUuids()));
} else {
next(candidates);
}
}
}