package org.zstack.storage.primary; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.zstack.core.cloudbus.CloudBus; import org.zstack.core.db.DatabaseFacade; import org.zstack.core.db.SimpleQuery; import org.zstack.core.db.SimpleQuery.Op; import org.zstack.core.errorcode.ErrorFacade; import org.zstack.header.errorcode.SysErrors; import org.zstack.header.apimediator.ApiMessageInterceptionException; import org.zstack.header.apimediator.ApiMessageInterceptor; import org.zstack.header.apimediator.StopRoutingException; import org.zstack.header.message.APIMessage; import org.zstack.header.storage.primary.*; import org.zstack.header.zone.ZoneVO; import org.zstack.header.zone.ZoneVO_; import org.zstack.utils.CollectionUtils; import static org.zstack.core.Platform.argerr; import static org.zstack.core.Platform.operr; import javax.persistence.TypedQuery; import java.util.List; import java.util.stream.Collectors; /** * Created with IntelliJ IDEA. * User: frank * Time: 4:41 PM * To change this template use File | Settings | File Templates. */ public class PrimaryStorageApiInterceptor implements ApiMessageInterceptor { @Autowired private CloudBus bus; @Autowired private DatabaseFacade dbf; @Autowired private ErrorFacade errf; private void setServiceId(APIMessage msg) { if (msg instanceof PrimaryStorageMessage) { PrimaryStorageMessage pmsg = (PrimaryStorageMessage) msg; bus.makeTargetServiceIdByResourceUuid(msg, PrimaryStorageConstant.SERVICE_ID, pmsg.getPrimaryStorageUuid()); } } @Override public APIMessage intercept(APIMessage msg) throws ApiMessageInterceptionException { if (msg instanceof APIDeletePrimaryStorageMsg) { validate((APIDeletePrimaryStorageMsg) msg); } else if (msg instanceof APIAttachPrimaryStorageToClusterMsg) { validate((APIAttachPrimaryStorageToClusterMsg) msg); } else if (msg instanceof APIDetachPrimaryStorageFromClusterMsg) { validate((APIDetachPrimaryStorageFromClusterMsg) msg); } else if (msg instanceof APIGetPrimaryStorageCapacityMsg) { validate((APIGetPrimaryStorageCapacityMsg) msg); } setServiceId(msg); return msg; } private void validate(APIGetPrimaryStorageCapacityMsg msg) { boolean pass = false; if (msg.getZoneUuids() != null && !msg.getZoneUuids().isEmpty()) { pass = true; } if (msg.getClusterUuids() != null && !msg.getClusterUuids().isEmpty()) { pass = true; } if (msg.getPrimaryStorageUuids() != null && !msg.getPrimaryStorageUuids().isEmpty()) { pass = true; } if (!pass && !msg.isAll()) { throw new ApiMessageInterceptionException(argerr("zoneUuids, clusterUuids, primaryStorageUuids must have at least one be none-empty list, or all is set to true")); } if (msg.isAll() && (msg.getZoneUuids() == null || msg.getZoneUuids().isEmpty())) { SimpleQuery<ZoneVO> q = dbf.createQuery(ZoneVO.class); q.select(ZoneVO_.uuid); List<String> zuuids = q.listValue(); msg.setZoneUuids(zuuids); if (msg.getZoneUuids().isEmpty()) { APIGetPrimaryStorageCapacityReply reply = new APIGetPrimaryStorageCapacityReply(); bus.reply(msg, reply); throw new StopRoutingException(); } } } private void validate(APIDetachPrimaryStorageFromClusterMsg msg) { SimpleQuery<PrimaryStorageClusterRefVO> q = dbf.createQuery(PrimaryStorageClusterRefVO.class); q.add(PrimaryStorageClusterRefVO_.clusterUuid, Op.EQ, msg.getClusterUuid()); q.add(PrimaryStorageClusterRefVO_.primaryStorageUuid, Op.EQ, msg.getPrimaryStorageUuid()); if (!q.isExists()) { throw new ApiMessageInterceptionException(argerr("primary storage[uuid:%s] has not been attached to cluster[uuid:%s] yet", msg.getPrimaryStorageUuid(), msg.getClusterUuid())); } } @Transactional private void validate(APIAttachPrimaryStorageToClusterMsg msg) { { String sql = "select count(ref)" + " from PrimaryStorageClusterRefVO ref" + " where ref.clusterUuid = :clusterUuid" + " and ref.primaryStorageUuid = :psUuid"; TypedQuery<Long> q = dbf.getEntityManager().createQuery(sql, Long.class); q.setParameter("psUuid", msg.getPrimaryStorageUuid()); q.setParameter("clusterUuid", msg.getClusterUuid()); long count = q.getSingleResult(); if (count != 0) { throw new ApiMessageInterceptionException(operr("primary storage[uuid:%s] has been attached to cluster[uuid:%s]", msg.getPrimaryStorageUuid(), msg.getClusterUuid())); } } { String sql = "select count(ps)" + " from PrimaryStorageVO ps, ClusterVO cluster" + " where cluster.zoneUuid = ps.zoneUuid" + " and cluster.uuid = :clusterUuid" + " and ps.uuid = :psUuid"; TypedQuery<Long> jq = dbf.getEntityManager().createQuery(sql, Long.class); jq.setParameter("psUuid", msg.getPrimaryStorageUuid()); jq.setParameter("clusterUuid", msg.getClusterUuid()); long count = jq.getSingleResult(); if (count == 0) { throw new ApiMessageInterceptionException(argerr("primary storage[uuid:%s] and cluster[uuid:%s] are not in the same zone", msg.getPrimaryStorageUuid(), msg.getClusterUuid())); } } } private void validate(APIDeletePrimaryStorageMsg msg) { if (!dbf.isExist(msg.getUuid(), PrimaryStorageVO.class)) { APIDeletePrimaryStorageEvent evt = new APIDeletePrimaryStorageEvent(msg.getId()); bus.publish(evt); throw new StopRoutingException(); } SimpleQuery<PrimaryStorageClusterRefVO> sq = dbf.createQuery(PrimaryStorageClusterRefVO.class); sq.add(PrimaryStorageClusterRefVO_.primaryStorageUuid, Op.EQ, msg.getPrimaryStorageUuid()); List<PrimaryStorageClusterRefVO> pscRefs = sq.list(); if (!pscRefs.isEmpty()) { String clusterUuidsString = pscRefs.stream() .map(PrimaryStorageClusterRefVO::getClusterUuid) .collect(Collectors.joining(", ")); throw new ApiMessageInterceptionException(operr("primary storage[uuid:%s] cannot be deleted for still " + "being attached to cluster[uuid:%s].", msg.getPrimaryStorageUuid(), clusterUuidsString)); } } }