package org.zstack.storage.volume; import org.springframework.beans.factory.annotation.Autowired; import org.zstack.core.cloudbus.CloudBus; import org.zstack.core.cloudbus.CloudBusCallBack; import org.zstack.core.db.DatabaseFacade; import org.zstack.core.db.SimpleQuery; import org.zstack.core.db.SimpleQuery.Od; import org.zstack.core.db.SimpleQuery.Op; import org.zstack.header.core.Completion; import org.zstack.header.image.ImageConstant.ImageMediaType; import org.zstack.header.message.MessageReply; import org.zstack.header.vm.PreVmInstantiateResourceExtensionPoint; import org.zstack.header.vm.VmInstanceSpec; import org.zstack.header.vm.VmInstanceSpec.ImageSpec; import org.zstack.header.vm.VmInstanceState; import org.zstack.header.vm.VmInstantiateResourceException; import org.zstack.header.volume.*; import org.zstack.utils.Utils; import org.zstack.utils.gson.JSONObjectUtil; import org.zstack.utils.logging.CLogger; import java.util.ArrayList; import java.util.BitSet; import java.util.Iterator; import java.util.List; public class InstantiateVolumeForNewCreatedVmExtension implements PreVmInstantiateResourceExtensionPoint { private static final CLogger logger = Utils.getLogger(InstantiateVolumeForNewCreatedVmExtension.class); @Autowired private CloudBus bus; @Autowired private DatabaseFacade dbf; @Override public void preBeforeInstantiateVmResource(VmInstanceSpec spec) throws VmInstantiateResourceException{ } private void doInstantiate(final Iterator<InstantiateVolumeMsg> it, final VmInstanceSpec spec, final Completion completion) { if (!it.hasNext()) { completion.success(); return; } InstantiateVolumeMsg msg = it.next(); bus.send(msg, new CloudBusCallBack(completion) { private int getNextDeviceId() { SimpleQuery<VolumeVO> q = dbf.createQuery(VolumeVO.class); q.select(VolumeVO_.deviceId); q.add(VolumeVO_.vmInstanceUuid, Op.EQ, spec.getVmInventory().getUuid()); q.add(VolumeVO_.deviceId, Op.NOT_NULL); q.orderBy(VolumeVO_.deviceId, Od.ASC); List<Integer> devIds = q.listValue(); BitSet full = new BitSet(devIds.size()+1); for (Integer id : devIds) { full.set(id); } return full.nextClearBit(0); } @Override public void run(MessageReply reply) { if (reply.isSuccess()) { InstantiateVolumeReply r = reply.castReply(); VolumeVO vo = dbf.findByUuid(r.getVolume().getUuid(), VolumeVO.class); if (vo.getType() == VolumeType.Data) { vo.setDeviceId(getNextDeviceId()); vo.setActualSize(0L); } else { vo.setActualSize(spec.getImageSpec().getInventory().getActualSize()); } vo = dbf.updateAndRefresh(vo); VolumeInventory vinv = VolumeInventory.valueOf(vo); if (spec.getDestRootVolume().getUuid().equals(vinv.getUuid())) { spec.setDestRootVolume(vinv); } else { spec.getDestDataVolumes().add(vinv); } logger.debug(String.format("spec.getDestRootVolume is: %s", spec.getDestRootVolume().getInstallPath())); logger.debug(String.format("successfully instantiated volume%s", JSONObjectUtil.toJsonString(vinv))); doInstantiate(it, spec, completion); } else { completion.fail(reply.getError()); } } }); } @Override public void preInstantiateVmResource(VmInstanceSpec spec, Completion completion) { if (!spec.getVmInventory().getState().equals(VmInstanceState.Created.toString())) { completion.success(); return; } List<InstantiateVolumeMsg> msgs = new ArrayList<>(); for (VolumeInventory volume : spec.getDestDataVolumes()) { InstantiateVolumeMsg msg = new InstantiateVolumeMsg(); msg.setVolumeUuid(volume.getUuid()); msg.setPrimaryStorageUuid(volume.getPrimaryStorageUuid()); msg.setHostUuid(spec.getDestHost().getUuid()); msg.setPrimaryStorageAllocated(true); bus.makeTargetServiceIdByResourceUuid(msg, VolumeConstant.SERVICE_ID, volume.getUuid()); msgs.add(msg); } ImageSpec image = spec.getImageSpec(); InstantiateVolumeMsg rmsg; if (ImageMediaType.RootVolumeTemplate.toString().equals(image.getInventory().getMediaType())) { rmsg = new InstantiateRootVolumeMsg(); ((InstantiateRootVolumeMsg)rmsg).setTemplateSpec(image); } else { rmsg = new InstantiateVolumeMsg(); } rmsg.setPrimaryStorageUuid(spec.getDestRootVolume().getPrimaryStorageUuid()); rmsg.setHostUuid(spec.getDestHost().getUuid()); rmsg.setVolumeUuid(spec.getDestRootVolume().getUuid()); rmsg.setPrimaryStorageAllocated(true); bus.makeTargetServiceIdByResourceUuid(rmsg, VolumeConstant.SERVICE_ID, spec.getDestRootVolume().getUuid()); msgs.add(rmsg); if (msgs.isEmpty()) { completion.success(); return; } // data volume will be refilled after being instantiated spec.getDestDataVolumes().clear(); doInstantiate(msgs.iterator(), spec, completion); } @Override public void preReleaseVmResource(VmInstanceSpec spec, Completion completion) { /* volumes will be deleted when VmAllocateVolumeFlow rolls back */ completion.success(); } }