package org.zstack.network.service.virtualrouter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.zstack.core.cascade.AbstractAsyncCascadeExtension; import org.zstack.core.cascade.CascadeAction; import org.zstack.core.cascade.CascadeConstant; import org.zstack.core.cloudbus.CloudBus; import org.zstack.core.cloudbus.CloudBusListCallBack; import org.zstack.core.db.DatabaseFacade; import org.zstack.core.db.SimpleQuery; import org.zstack.core.db.SimpleQuery.Op; import org.zstack.header.configuration.ConfigurationConstant; import org.zstack.header.configuration.InstanceOfferingDeletionMsg; import org.zstack.header.core.Completion; import org.zstack.header.image.ImageDeletionStruct; import org.zstack.header.image.ImageVO; import org.zstack.header.message.MessageReply; import org.zstack.header.network.l3.L3NetworkInventory; import org.zstack.header.network.l3.L3NetworkVO; import org.zstack.utils.CollectionUtils; import org.zstack.utils.function.Function; import javax.persistence.Query; import java.util.Arrays; import java.util.List; /** */ public class VirtualRouterOfferingCascadeExtension extends AbstractAsyncCascadeExtension { @Autowired private DatabaseFacade dbf; @Autowired private CloudBus bus; private static String NAME = VirtualRouterOfferingVO.class.getSimpleName(); public void asyncCascade(CascadeAction action, Completion completion) { if (action.isActionCode(CascadeConstant.DELETION_CHECK_CODE)) { handleDeletionCheck(action, completion); } else if (action.isActionCode(CascadeConstant.DELETION_DELETE_CODE, CascadeConstant.DELETION_FORCE_DELETE_CODE)) { handleDeletion(action, completion); } else if (action.isActionCode(CascadeConstant.DELETION_CLEANUP_CODE)) { handleDeletionCleanup(action, completion); } else { completion.success(); } } @Transactional private void deleteInstanceOfferingEONotReferredByVm() { String sql = "delete from InstanceOfferingEO i" + " where i.deleted is not null" + " and i.uuid not in" + " (" + " select vm.instanceOfferingUuid" + " from VmInstanceVO vm" + " where vm.instanceOfferingUuid is not null" + " )"; Query q = dbf.getEntityManager().createQuery(sql); q.executeUpdate(); } private void handleDeletionCleanup(CascadeAction action, Completion completion) { deleteInstanceOfferingEONotReferredByVm(); completion.success(); } private List<VirtualRouterOfferingInventory> offeringFromAction(CascadeAction action) { List<VirtualRouterOfferingInventory> ret = null; if (L3NetworkVO.class.getSimpleName().equals(action.getParentIssuer())) { List<L3NetworkInventory> l3s = action.getParentIssuerContext(); List<String> l3uuids = CollectionUtils.transformToList(l3s, new Function<String, L3NetworkInventory>() { @Override public String call(L3NetworkInventory arg) { return arg.getUuid(); } }); SimpleQuery<VirtualRouterOfferingVO> q = dbf.createQuery(VirtualRouterOfferingVO.class); q.add(VirtualRouterOfferingVO_.publicNetworkUuid, Op.IN, l3uuids); List<VirtualRouterOfferingVO> offeringVOs = q.list(); q = dbf.createQuery(VirtualRouterOfferingVO.class); q.add(VirtualRouterOfferingVO_.managementNetworkUuid, Op.IN, l3uuids); List<VirtualRouterOfferingVO> lst = q.list(); offeringVOs.addAll(lst); ret = VirtualRouterOfferingInventory.valueOf1(offeringVOs); } else if (ImageVO.class.getSimpleName().equals(action.getParentIssuer())) { List<String> imgUuids = CollectionUtils.transformToList( (List<ImageDeletionStruct>) action.getParentIssuerContext(), new Function<String, ImageDeletionStruct>() { @Override public String call(ImageDeletionStruct arg) { return arg.getDeleteAll() ? arg.getImage().getUuid() : null; } }); SimpleQuery<VirtualRouterOfferingVO> q = dbf.createQuery(VirtualRouterOfferingVO.class); q.add(VirtualRouterOfferingVO_.imageUuid, Op.IN, imgUuids); List<VirtualRouterOfferingVO> offeringVOs = q.list(); ret = VirtualRouterOfferingInventory.valueOf1(offeringVOs); } if (ret != null && !ret.isEmpty()) { return ret; } else { return null; } } private void handleDeletion(final CascadeAction action, final Completion completion) { List<VirtualRouterOfferingInventory> offering = offeringFromAction(action); if (offering == null) { completion.success(); return; } List<String> offeringUuids = CollectionUtils.transformToList(offering, new Function<String, VirtualRouterOfferingInventory>() { @Override public String call(VirtualRouterOfferingInventory arg) { return arg.getUuid(); } }); List<InstanceOfferingDeletionMsg> msgs = CollectionUtils.transformToList( offeringUuids, new Function<InstanceOfferingDeletionMsg, String>() { @Override public InstanceOfferingDeletionMsg call(String arg) { InstanceOfferingDeletionMsg msg = new InstanceOfferingDeletionMsg(); msg.setInstanceOfferingUuid(arg); msg.setForceDelete(action.isActionCode(CascadeConstant.DELETION_FORCE_DELETE_CODE)); bus.makeTargetServiceIdByResourceUuid(msg, ConfigurationConstant.SERVICE_ID, arg); return msg; } }); bus.send(msgs, new CloudBusListCallBack(completion) { @Override public void run(List<MessageReply> replies) { if (!action.isActionCode(CascadeConstant.DELETION_FORCE_DELETE_CODE)) { for (MessageReply r : replies) { if (!r.isSuccess()) { completion.fail(r.getError()); return; } } } completion.success(); } }); } private void handleDeletionCheck(CascadeAction action, Completion completion) { completion.success(); } @Override public List<String> getEdgeNames() { return Arrays.asList(L3NetworkVO.class.getSimpleName(), ImageVO.class.getSimpleName()); } @Override public String getCascadeResourceName() { return NAME; } @Override public CascadeAction createActionForChildResource(CascadeAction action) { if (CascadeConstant.DELETION_CODES.contains(action.getActionCode())) { List<VirtualRouterOfferingInventory> ctx = offeringFromAction(action); if (ctx != null) { return action.copy().setParentIssuer(VirtualRouterOfferingVO.class.getSimpleName()).setParentIssuerContext(ctx); } } return null; } }