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.zstack.core.db.DatabaseFacade;
import org.zstack.core.db.SimpleQuery;
import org.zstack.core.db.SimpleQuery.Op;
import org.zstack.header.allocator.AbstractHostAllocatorFlow;
import org.zstack.header.host.HostVO;
import org.zstack.header.storage.primary.PrimaryStorageClusterRefVO;
import org.zstack.header.storage.primary.PrimaryStorageClusterRefVO_;
import org.zstack.header.vm.VmInstanceConstant.VmOperation;
import org.zstack.header.vm.VmInstanceInventory;
import org.zstack.header.volume.VolumeInventory;
import org.zstack.utils.CollectionUtils;
import org.zstack.utils.function.Function;
import java.util.*;
/**
*/
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
public class AttachedVolumePrimaryStorageAllocatorFlow extends AbstractHostAllocatorFlow {
@Autowired
private DatabaseFacade dbf;
@Override
public void allocate() {
throwExceptionIfIAmTheFirstFlow();
if (VmOperation.NewCreate.toString().equals(spec.getVmOperation())) {
next(candidates);
return;
}
VmInstanceInventory vm = spec.getVmInstance();
List<String> requiredPsUuids = CollectionUtils.transformToList(vm.getAllVolumes(), new Function<String, VolumeInventory>() {
@Override
public String call(VolumeInventory arg) {
return arg.getPrimaryStorageUuid();
}
});
// find out cluster that have all required primary storage attached
SimpleQuery<PrimaryStorageClusterRefVO> q = dbf.createQuery(PrimaryStorageClusterRefVO.class);
q.add(PrimaryStorageClusterRefVO_.primaryStorageUuid, Op.IN, requiredPsUuids);
List<PrimaryStorageClusterRefVO> refs = q.list();
Map<String, Set<String>> clusterPs = new HashMap<>();
for (PrimaryStorageClusterRefVO ref : refs) {
Set<String> pss = clusterPs.get(ref.getClusterUuid());
if (pss == null) {
pss = new HashSet<>();
clusterPs.put(ref.getClusterUuid(), pss);
}
pss.add(ref.getPrimaryStorageUuid());
}
List<String> clusterHavingAllPs = new ArrayList<>();
for (Map.Entry<String, Set<String>> e : clusterPs.entrySet()) {
if (e.getValue().containsAll(requiredPsUuids)) {
clusterHavingAllPs.add(e.getKey());
}
}
// find out host in above result clusters
List<HostVO> tmp = candidates;
candidates = new ArrayList<>();
if (!clusterHavingAllPs.isEmpty()) {
for (HostVO h : tmp) {
if (clusterHavingAllPs.contains(h.getClusterUuid())) {
candidates.add(h);
}
}
}
if (candidates.isEmpty()) {
fail(String.format("no host found in clusters which have attached to all primary storage%s where vm[uuid:%s]'s volumes locate",
requiredPsUuids, vm.getUuid()));
} else {
next(candidates);
}
}
}