package org.zstack.network.securitygroup; import org.springframework.beans.factory.annotation.Autowired; import org.zstack.core.cascade.*; 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.errorcode.ErrorFacade; import org.zstack.header.core.Completion; import org.zstack.header.message.MessageReply; import org.zstack.header.vm.VmDeletionStruct; import org.zstack.header.vm.VmInstanceInventory; import org.zstack.header.vm.VmInstanceVO; import org.zstack.header.vm.VmNicInventory; import org.zstack.utils.CollectionUtils; import org.zstack.utils.Utils; import org.zstack.utils.function.Function; import org.zstack.utils.logging.CLogger; import java.util.*; /** */ public class SecurityGroupCascadeExtension extends AbstractAsyncCascadeExtension { private static final CLogger logger = Utils.getLogger(SecurityGroupCascadeExtension.class); @Autowired private DatabaseFacade dbf; @Autowired private CloudBus bus; private static String NAME = VmNicSecurityGroupRefVO.class.getSimpleName(); @Override 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(); } } private void handleDeletionCleanup(CascadeAction action, Completion completion) { dbf.eoCleanup(SecurityGroupVO.class); completion.success(); } private void handleDeletionCheck(CascadeAction action, Completion completion) { completion.success(); } private void handleDeletion(CascadeAction action, final Completion completion) { List<VmNicSecurityGroupRefInventory> refs = refFromAction(action); if (refs.isEmpty()) { completion.success(); return; } Map<String, List<String>> map = new HashMap<String, List<String>>(); for (VmNicSecurityGroupRefInventory ref : refs) { List<String> nicUuids = map.get(ref.getSecurityGroupUuid()); if (nicUuids == null) { nicUuids = new ArrayList<String>(); map.put(ref.getSecurityGroupUuid(), nicUuids); } nicUuids.add(ref.getVmNicUuid()); } List<RemoveVmNicFromSecurityGroupMsg> msgs = new ArrayList<RemoveVmNicFromSecurityGroupMsg>(); for (Map.Entry<String, List<String>> e : map.entrySet()) { RemoveVmNicFromSecurityGroupMsg msg = new RemoveVmNicFromSecurityGroupMsg(); msg.setSecurityGroupUuid(e.getKey()); msg.setVmNicUuids(e.getValue()); bus.makeTargetServiceIdByResourceUuid(msg, SecurityGroupConstant.SERVICE_ID, e.getKey()); msgs.add(msg); } bus.send(msgs, new CloudBusListCallBack(completion) { @Override public void run(List<MessageReply> replies) { for (MessageReply reply : replies) { if (!reply.isSuccess()) { logger.warn(String.format("failed to remove vm nic from some security group for some destroyed vm," + "no worry, security group will catch it up later. %s", reply.getError())); } } completion.success(); } }); } @Override public List<String> getEdgeNames() { return Arrays.asList(VmInstanceVO.class.getSimpleName()); } @Override public String getCascadeResourceName() { return NAME; } private List<VmNicSecurityGroupRefInventory> refFromAction(CascadeAction action) { List<VmDeletionStruct> vms = action.getParentIssuerContext(); List<String> nicUuids = new ArrayList<String>(); for (VmDeletionStruct vm : vms) { nicUuids.addAll(CollectionUtils.transformToList(vm.getInventory().getVmNics(), new Function<String, VmNicInventory>() { @Override public String call(VmNicInventory arg) { return arg.getUuid(); } })); } if (nicUuids.isEmpty()) { return new ArrayList<VmNicSecurityGroupRefInventory>(); } SimpleQuery<VmNicSecurityGroupRefVO> q = dbf.createQuery(VmNicSecurityGroupRefVO.class); q.add(VmNicSecurityGroupRefVO_.vmNicUuid, SimpleQuery.Op.IN, nicUuids); List<VmNicSecurityGroupRefVO> vos = q.list(); return VmNicSecurityGroupRefInventory.valueOf(vos); } @Override public CascadeAction createActionForChildResource(CascadeAction action) { if (CascadeConstant.DELETION_CLEANUP_CODE.equals(action.getActionCode())) { return null; } if (!action.getParentIssuer().equals(VmInstanceVO.class.getSimpleName())) { return null; } List<VmNicSecurityGroupRefInventory> refs = refFromAction(action); if (refs.isEmpty()) { return null; } return action.copy().setParentIssuer(NAME).setParentIssuerContext(refs); } }