package org.zstack.storage.primary; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.zstack.core.db.DatabaseFacade; import org.zstack.core.errorcode.ErrorFacade; import org.zstack.header.allocator.DiskOfferingTagAllocatorExtensionPoint; import org.zstack.header.allocator.HostAllocatorError; import org.zstack.header.allocator.HostAllocatorSpec; import org.zstack.header.allocator.InstanceOfferingTagAllocatorExtensionPoint; import org.zstack.header.errorcode.OperationFailureException; import org.zstack.header.host.HostVO; import org.zstack.header.storage.primary.PrimaryStorageTagAllocatorExtensionPoint; import org.zstack.header.storage.primary.PrimaryStorageVO; import org.zstack.header.tag.SystemTagInventory; import org.zstack.header.tag.TagInventory; import org.zstack.header.vm.VmInstanceConstant.VmOperation; import org.zstack.utils.CollectionUtils; import org.zstack.utils.function.Function; import static org.zstack.core.Platform.operr; import javax.persistence.TypedQuery; import java.util.ArrayList; import java.util.List; /** */ public class PrimaryStorageTagAllocatorExtension implements InstanceOfferingTagAllocatorExtensionPoint, PrimaryStorageTagAllocatorExtensionPoint, DiskOfferingTagAllocatorExtensionPoint { @Autowired private DatabaseFacade dbf; @Autowired private ErrorFacade errf; @Transactional(readOnly = true) private List<HostVO> uuidTagAllocateHost(List<HostVO> candidates, String psUuid) { List<String> hostUuids = CollectionUtils.transformToList(candidates, new Function<String, HostVO>() { @Override public String call(HostVO arg) { return arg.getUuid(); } }); String sql = "select h from HostVO h where h.clusterUuid in (select ref.clusterUuid from PrimaryStorageClusterRefVO ref where ref.primaryStorageUuid = :psUuid) and h.uuid in (:huuids)"; TypedQuery<HostVO> q = dbf.getEntityManager().createQuery(sql, HostVO.class); q.setParameter("psUuid", psUuid); q.setParameter("huuids", hostUuids); candidates = q.getResultList(); if (candidates.isEmpty()) { throw new OperationFailureException(errf.instantiateErrorCode(HostAllocatorError.NO_AVAILABLE_HOST, String.format("cannot find host whose cluster has attached to primary storage[uuid:%s]. The primary storage uuid is specified in instance offering tag", psUuid) )); } return candidates; } @Override public List<HostVO> allocateHost(List<TagInventory> tags, List<HostVO> candidates, HostAllocatorSpec spec) { if (!VmOperation.NewCreate.toString().equals(spec.getVmOperation())) { return candidates; } for (TagInventory tag : tags) { String uuid = PrimaryStorageSystemTags.PRIMARY_STORAGE_ALLOCATOR_UUID_TAG.getTokenByTag(tag.getTag(), "uuid"); if (uuid != null) { return uuidTagAllocateHost(candidates, uuid); } String requiredUserTag = PrimaryStorageSystemTags.PRIMARY_STORAGE_ALLOCATOR_USERTAG_TAG_MANDATORY.getTokenByTag(tag.getTag(), "tag"); if (requiredUserTag != null) { return userTagAllocateHost(candidates, requiredUserTag, true); } String userTag = PrimaryStorageSystemTags.PRIMARY_STORAGE_ALLOCATOR_USERTAG_TAG.getTokenByTag(tag.getTag(), "tag"); if (userTag != null) { return userTagAllocateHost(candidates, userTag, false); } } return candidates; } @Transactional(readOnly = true) private List<HostVO> userTagAllocateHost(List<HostVO> candidates, String tag, boolean required) { List<String> hostUuids = CollectionUtils.transformToList(candidates, new Function<String, HostVO>() { @Override public String call(HostVO arg) { return arg.getUuid(); } }); String sql = "select h from HostVO h where h.clusterUuid in (select ref.clusterUuid from PrimaryStorageClusterRefVO ref where ref.primaryStorageUuid in (select t.resourceUuid from UserTagVO t where t.tag = :tag and t.resourceType = :resourceType)) and h.uuid in (:huuids)"; TypedQuery<HostVO> q = dbf.getEntityManager().createQuery(sql, HostVO.class); q.setParameter("tag", tag); q.setParameter("resourceType", PrimaryStorageVO.class.getSimpleName()); q.setParameter("huuids", hostUuids); List<HostVO> vos = q.getResultList(); if (vos.isEmpty() && required) { throw new OperationFailureException(errf.instantiateErrorCode(HostAllocatorError.NO_AVAILABLE_HOST, String.format("cannot find host whose cluster has attached to primary storage having user tag[%s]. The user tag is specified in instance offering tag", tag) )); } else if (vos.isEmpty()) { return candidates; } else { return vos; } } @Override public List<PrimaryStorageVO> allocatePrimaryStorage(List<SystemTagInventory> tags, List<PrimaryStorageVO> candidates) { for (SystemTagInventory tag : tags) { final String uuid = PrimaryStorageSystemTags.PRIMARY_STORAGE_ALLOCATOR_UUID_TAG.getTokenByTag(tag.getTag(), "uuid"); if (uuid != null) { PrimaryStorageVO pvo = CollectionUtils.find(candidates, new Function<PrimaryStorageVO, PrimaryStorageVO>() { @Override public PrimaryStorageVO call(PrimaryStorageVO arg) { return uuid.equals(arg.getUuid()) ? arg : null; } }); if (pvo == null) { throw new OperationFailureException(operr("cannot find primary storage[uuid:%s], the uuid is specified in instance offering or disk offering", uuid)); } List<PrimaryStorageVO> psvos = new ArrayList<PrimaryStorageVO>(); psvos.add(pvo); return psvos; } String requiredUserTag = PrimaryStorageSystemTags.PRIMARY_STORAGE_ALLOCATOR_USERTAG_TAG_MANDATORY.getTokenByTag(tag.getTag(), "tag"); if (requiredUserTag != null) { return allocatePrimaryStorageByUserTag(requiredUserTag, candidates, true); } String userTag = PrimaryStorageSystemTags.PRIMARY_STORAGE_ALLOCATOR_USERTAG_TAG.getTokenByTag(tag.getTag(), "tag"); if (userTag != null) { return allocatePrimaryStorageByUserTag(userTag, candidates, false); } } return candidates; } @Transactional(readOnly = true) private List<PrimaryStorageVO> allocatePrimaryStorageByUserTag(String tag, List<PrimaryStorageVO> candidates, boolean required) { List<String> uuids = CollectionUtils.transformToList(candidates, new Function<String, PrimaryStorageVO>() { @Override public String call(PrimaryStorageVO arg) { return arg.getUuid(); } }); String sql = "select ps from PrimaryStorageVO ps where ps.uuid in (:uuids) and ps.uuid in (select t.resourceUuid from UserTagVO t where t.tag = :tag and t.resourceType = :resourceType)"; TypedQuery<PrimaryStorageVO> q = dbf.getEntityManager().createQuery(sql, PrimaryStorageVO.class); q.setParameter("uuids", uuids); q.setParameter("tag", tag); q.setParameter("resourceType", PrimaryStorageVO.class.getSimpleName()); List<PrimaryStorageVO> vos = q.getResultList(); if (vos.isEmpty() && required) { throw new OperationFailureException(operr("cannot find primary storage having user tag[%s]. The user tag is specified in instance offering or disk offering", tag)); } else if (vos.isEmpty()) { return candidates; } else { return vos; } } }