@Override @Transactional(readOnly = true) public void preRecoverVm(VmInstanceInventory vm) { String rootVolUuid = vm.getRootVolumeUuid(); String sql = "select ps.uuid from PrimaryStorageVO ps, VolumeVO vol where ps.uuid = vol.primaryStorageUuid" + " and vol.uuid = :uuid and ps.type = :pstype"; TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("uuid", rootVolUuid); q.setParameter("pstype", LocalStorageConstants.LOCAL_STORAGE_TYPE); String psuuid = dbf.find(q); if (psuuid == null) { return; } sql = "select count(ref) from LocalStorageResourceRefVO ref where ref.resourceUuid = :uuid and ref.resourceType = :rtype"; TypedQuery<Long> rq = dbf.getEntityManager().createQuery(sql, Long.class); rq.setParameter("uuid", rootVolUuid); rq.setParameter("rtype", VolumeVO.class.getSimpleName()); long count = rq.getSingleResult(); if (count == 0) { throw new OperationFailureException( errf.stringToOperationError( String.format( "unable to recover the vm[uuid:%s, name:%s]. The vm's root volume is on the local" + " storage[uuid:%s]; however, the host on which the root volume is has been deleted", vm.getUuid(), vm.getName(), psuuid))); } }
@Transactional private void updateCapacity(long total, long avail) { PrimaryStorageCapacityVO cvo = dbf.getEntityManager() .find(PrimaryStorageCapacityVO.class, self.getUuid(), LockModeType.PESSIMISTIC_WRITE); DebugUtils.Assert( cvo != null, String.format("how can there is no PrimaryStorageCapacityVO[uuid:%s]", self.getUuid())); cvo.setTotalPhysicalCapacity(total); cvo.setAvailablePhysicalCapacity(avail); dbf.getEntityManager().merge(cvo); }
@Override @Transactional public void delete(String uuid) { String sql = "delete from KeyValueVO vo where vo.uuid = :uuid"; Query q = dbf.getEntityManager().createQuery(sql); q.setParameter("uuid", uuid); q.executeUpdate(); sql = "delete from KeyValueBinaryVO vo where vo.uuid = :uuid"; q = dbf.getEntityManager().createQuery(sql); q.setParameter("uuid", uuid); q.executeUpdate(); }
@Transactional private void handle(TakePrimaryStorageCapacityMsg msg) { PrimaryStorageCapacityVO vo = dbf.getEntityManager() .find(PrimaryStorageCapacityVO.class, self.getUuid(), LockModeType.PESSIMISTIC_WRITE); vo.setAvailableCapacity(vo.getAvailableCapacity() - msg.getSize()); if (vo.getAvailableCapacity() < 0) { vo.setAvailableCapacity(0); } dbf.getEntityManager().merge(vo); TakePrimaryStorageCapacityReply reply = new TakePrimaryStorageCapacityReply(); bus.reply(msg, reply); }
@Transactional public void updatePhysicalCapacityByKvmAgentResponse( String psUuid, String hostUuid, AgentResponse rsp) { LocalStorageHostRefVO ref = dbf.getEntityManager() .find(LocalStorageHostRefVO.class, hostUuid, LockModeType.PESSIMISTIC_WRITE); if (ref == null) { return; } if (ref.getAvailablePhysicalCapacity() == rsp.getAvailableCapacity() && ref.getTotalPhysicalCapacity() == rsp.getTotalCapacity()) { return; } long originalPhysicalTotal = ref.getTotalPhysicalCapacity(); long originalPhysicalAvailable = ref.getAvailablePhysicalCapacity(); ref.setTotalPhysicalCapacity(rsp.getTotalCapacity()); ref.setAvailablePhysicalCapacity(rsp.getAvailableCapacity()); dbf.getEntityManager().merge(ref); if (logger.isTraceEnabled()) { logger.trace( String.format( "[Local Storage Capacity] changed the physical capacity of the host[uuid:%s] of " + "the local primary storage[uuid:%s] as:\n" + "physical total: %s --> %s\n" + "physical available: %s --> %s\n", hostUuid, psUuid, originalPhysicalTotal, ref.getTotalPhysicalCapacity(), originalPhysicalAvailable, ref.getAvailablePhysicalCapacity())); } final long totalChange = rsp.getTotalCapacity() - ref.getTotalPhysicalCapacity(); final long availChange = rsp.getAvailableCapacity() - ref.getAvailablePhysicalCapacity(); new PrimaryStorageCapacityUpdater(psUuid) .run( new PrimaryStorageCapacityUpdaterRunnable() { @Override public PrimaryStorageCapacityVO call(PrimaryStorageCapacityVO cap) { cap.setTotalPhysicalCapacity(cap.getTotalPhysicalCapacity() + totalChange); cap.setAvailablePhysicalCapacity(cap.getAvailablePhysicalCapacity() + availChange); return cap; } }); }
@Transactional private void handle(PrimaryStorageReportCapacityMsg msg) { PrimaryStorageCapacityVO vo = dbf.getEntityManager() .find(PrimaryStorageCapacityVO.class, self.getUuid(), LockModeType.PESSIMISTIC_WRITE); if (vo.getTotalCapacity() == 0) { vo.setTotalCapacity(msg.getTotalCapacity()); vo.setAvailableCapacity(msg.getAvailableCapacity()); dbf.getEntityManager().merge(vo); } PrimaryStorageReportCapacityReply reply = new PrimaryStorageReportCapacityReply(); bus.reply(msg, reply); }
@Transactional private void handle(ReturnBackupStorageMsg msg) { self = dbf.getEntityManager() .find(BackupStorageVO.class, self.getUuid(), LockModeType.PESSIMISTIC_WRITE); long availSize = self.getAvailableCapacity() + msg.getSize(); if (availSize > self.getTotalCapacity()) { availSize = self.getTotalCapacity(); } self.setAvailableCapacity(availSize); dbf.getEntityManager().merge(self); bus.reply(msg, new ReturnBackupStorageReply()); }
@Override @Transactional(readOnly = true) public List<VmInstanceVO> returnAttachableVms( VolumeInventory vol, List<VmInstanceVO> candidates) { String sql = "select ref.hostUuid from LocalStorageResourceRefVO ref where ref.resourceUuid = :uuid" + " and ref.resourceType = :rtype"; TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("uuid", vol.getUuid()); q.setParameter("rtype", VolumeVO.class.getSimpleName()); List<String> ret = q.getResultList(); if (ret.isEmpty()) { return candidates; } String hostUuid = ret.get(0); List<String> vmRootVolumeUuids = CollectionUtils.transformToList( candidates, new Function<String, VmInstanceVO>() { @Override public String call(VmInstanceVO arg) { return arg.getRootVolumeUuid(); } }); sql = "select ref.resourceUuid from LocalStorageResourceRefVO ref where ref.hostUuid = :huuid" + " and ref.resourceUuid in (:rootVolumeUuids) and ref.resourceType = :rtype"; q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("huuid", hostUuid); q.setParameter("rootVolumeUuids", vmRootVolumeUuids); q.setParameter("rtype", VolumeVO.class.getSimpleName()); final List<String> toInclude = q.getResultList(); candidates = CollectionUtils.transformToList( candidates, new Function<VmInstanceVO, VmInstanceVO>() { @Override public VmInstanceVO call(VmInstanceVO arg) { return toInclude.contains(arg.getRootVolumeUuid()) ? arg : null; } }); return candidates; }
@Transactional private void batchWrite(List lst) { for (Object obj : lst) { LogVO vo = (LogVO) obj; dbf.getEntityManager().persist(vo); } }
@Override @Transactional( readOnly = true, noRollbackForClassName = {"org.zstack.header.errorcode.OperationFailureException"}) public void preVmMigration(VmInstanceInventory vm) { List<String> volUuids = CollectionUtils.transformToList( vm.getAllVolumes(), new Function<String, VolumeInventory>() { @Override public String call(VolumeInventory arg) { return arg.getUuid(); } }); String sql = "select count(ps) from PrimaryStorageVO ps, VolumeVO vol where ps.uuid = vol.primaryStorageUuid and" + " vol.uuid in (:volUuids) and ps.type = :ptype"; TypedQuery<Long> q = dbf.getEntityManager().createQuery(sql, Long.class); q.setParameter("volUuids", volUuids); q.setParameter("ptype", LocalStorageConstants.LOCAL_STORAGE_TYPE); q.setMaxResults(1); Long count = q.getSingleResult(); if (count > 0) { throw new OperationFailureException( errf.stringToOperationError( String.format( "unable to live migrate with local storage. The vm[uuid:%s] has volumes on local storage," + "to protect your data, please stop the vm and do the volume migration", vm.getUuid()))); } }
@Transactional(readOnly = true) private boolean isThereOtherStorageForTheHost(String hostUuid, String localStorageUuid) { String sql = "select count(pri) from PrimaryStorageVO pri, PrimaryStorageClusterRefVO ref, HostVO host where pri.uuid = ref.primaryStorageUuid and ref.clusterUuid = host.clusterUuid and host.uuid = :huuid and pri.uuid != :puuid"; TypedQuery<Long> q = dbf.getEntityManager().createQuery(sql, Long.class); q.setParameter("huuid", hostUuid); q.setParameter("puuid", localStorageUuid); return q.getSingleResult() > 0; }
@Transactional(readOnly = true) private Collection<PortForwardingRuleTO> calculateAllRules( Map<String, PortForwardingRuleVO> ruleMap, String vrUuid) { String sql = "select rule.uuid, nic.ip, vip.ip from PortForwardingRuleVO rule, VmNicVO nic, VipVO vip where rule.vmNicUuid = nic.uuid and rule.uuid in (:ruleUuids) and vip.uuid = rule.vipUuid"; TypedQuery<Tuple> q = dbf.getEntityManager().createQuery(sql, Tuple.class); q.setParameter("ruleUuids", ruleMap.keySet()); List<Tuple> privateIps = q.getResultList(); Map<String, PortForwardingRuleTO> tos = new HashMap<String, PortForwardingRuleTO>(); for (Tuple t : privateIps) { String ruleUuid = t.get(0, String.class); PortForwardingRuleTO to = new PortForwardingRuleTO(); to.setPrivateIp(t.get(1, String.class)); PortForwardingRuleVO ruleVO = ruleMap.get(ruleUuid); to.setAllowedCidr(ruleVO.getAllowedCidr()); to.setPrivatePortEnd(ruleVO.getPrivatePortEnd()); to.setPrivatePortStart(ruleVO.getPrivatePortStart()); to.setVipPortEnd(ruleVO.getVipPortEnd()); to.setSnatInboundTraffic( PortForwardingGlobalConfig.SNAT_INBOUND_TRAFFIC.value(Boolean.class)); to.setVipPortStart(ruleVO.getVipPortStart()); to.setVipIp(t.get(2, String.class)); to.setProtocolType(ruleVO.getProtocolType().toString()); tos.put(ruleUuid, to); } assert tos.size() == ruleMap.size(); sql = "select rule.uuid, vrnic.mac from PortForwardingRuleVO rule, VmNicVO vrnic, VmNicVO nic2, ApplianceVmVO vr where vr.uuid = vrnic.vmInstanceUuid and vrnic.l3NetworkUuid = nic2.l3NetworkUuid and nic2.uuid = rule.vmNicUuid and rule.uuid in (:ruleUuids) and vr.uuid = :vrUuid"; TypedQuery<Tuple> privateMacQuery = dbf.getEntityManager().createQuery(sql, Tuple.class); privateMacQuery.setParameter("ruleUuids", ruleMap.keySet()); privateMacQuery.setParameter("vrUuid", vrUuid); List<Tuple> privateMacs = privateMacQuery.getResultList(); for (Tuple t : privateMacs) { String ruleUuid = t.get(0, String.class); PortForwardingRuleTO to = tos.get(ruleUuid); to.setPrivateMac(t.get(1, String.class)); } return tos.values(); }
@Override @Transactional public <T> T find(String uuid) { KeyValueBinaryVO bvo = dbf.getEntityManager().find(KeyValueBinaryVO.class, uuid); try { return SerializableHelper.readObject(bvo.getContents()); } catch (Exception e) { throw new CloudRuntimeException(e); } }
@Transactional private List<PortForwardingRuleVO> findRulesForThisRouter( VirtualRouterVmInventory vr, Map<String, Object> data, boolean isNewCreated) { if (!isNewCreated) { String sql = "select rule from PortForwardingRuleVO rule, VirtualRouterPortForwardingRuleRefVO ref, VmNicVO nic, VmInstanceVO vm where vm.state = :vmState and nic.vmInstanceUuid = vm.uuid and rule.vmNicUuid = nic.uuid and rule.uuid = ref.uuid and ref.virtualRouterVmUuid = :vrUuid"; TypedQuery<PortForwardingRuleVO> q = dbf.getEntityManager().createQuery(sql, PortForwardingRuleVO.class); q.setParameter("vrUuid", vr.getUuid()); q.setParameter("vmState", VmInstanceState.Running); return q.getResultList(); } else { VmNicInventory publicNic = vr.getPublicNic(); VmNicInventory guestNic = vr.getGuestNic(); String sql = "select rule from PortForwardingRuleVO rule, VipVO vip, VmNicVO nic, VmInstanceVO vm where vm.uuid = nic.vmInstanceUuid and vm.state = :vmState and rule.vipUuid = vip.uuid and rule.vmNicUuid = nic.uuid and vip.l3NetworkUuid = :vipL3Uuid and nic.l3NetworkUuid = :guestL3Uuid"; TypedQuery<PortForwardingRuleVO> q = dbf.getEntityManager().createQuery(sql, PortForwardingRuleVO.class); q.setParameter("vipL3Uuid", publicNic.getL3NetworkUuid()); q.setParameter("guestL3Uuid", guestNic.getL3NetworkUuid()); q.setParameter("vmState", VmInstanceState.Running); List<PortForwardingRuleVO> rules = q.getResultList(); if (!rules.isEmpty()) { List<VirtualRouterPortForwardingRuleRefVO> refs = new ArrayList<VirtualRouterPortForwardingRuleRefVO>(); for (PortForwardingRuleVO rule : rules) { VirtualRouterPortForwardingRuleRefVO ref = new VirtualRouterPortForwardingRuleRefVO(); ref.setVirtualRouterVmUuid(vr.getUuid()); ref.setVipUuid(rule.getVipUuid()); ref.setUuid(rule.getUuid()); dbf.getEntityManager().persist(ref); refs.add(ref); } data.put(VirtualRouterSyncPortForwardingRulesOnStartFlow.class.getName(), refs); } return rules; } }
@Override @Transactional(readOnly = true) public HostMaintenancePolicy getHostMaintenancePolicy(HostInventory host) { String sql = "select count(ps) from PrimaryStorageVO ps, PrimaryStorageClusterRefVO ref where ps.uuid = ref.primaryStorageUuid" + " and ps.type = :type and ref.clusterUuid = :cuuid"; TypedQuery<Long> q = dbf.getEntityManager().createQuery(sql, Long.class); q.setParameter("type", LocalStorageConstants.LOCAL_STORAGE_TYPE); q.setParameter("cuuid", host.getClusterUuid()); q.setMaxResults(1); Long count = q.getSingleResult(); return count > 0 ? HostMaintenancePolicy.StopVm : null; }
@Override @Transactional public void persist(KeyValueEntity entity) { KeyValueBinaryVO bvo = new KeyValueBinaryVO(); bvo.setUuid(entity.getUuid()); try { bvo.setContents(SerializableHelper.writeObject(entity)); } catch (IOException e) { throw new CloudRuntimeException(e); } dbf.getEntityManager().persist(bvo); List<KeyValueStruct> structs = new KeyValueSerializer().build(entity); for (KeyValueStruct struct : structs) { KeyValueVO vo = new KeyValueVO(); vo.setClassName(entity.getClass().getName()); vo.setUuid(entity.getUuid()); vo.setEntityKey(struct.getKey()); vo.setEntityValue(struct.getValue()); vo.setValueType(struct.getType().getName()); dbf.getEntityManager().persist(vo); } }
@Transactional(readOnly = true) private String getLocalStorageInCluster(String clusterUuid) { String sql = "select pri.uuid from PrimaryStorageVO pri, PrimaryStorageClusterRefVO ref where pri.uuid = ref.primaryStorageUuid and ref.clusterUuid = :cuuid and pri.type = :ptype"; TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("cuuid", clusterUuid); q.setParameter("ptype", LocalStorageConstants.LOCAL_STORAGE_TYPE); List<String> ret = q.getResultList(); if (ret.isEmpty()) { return null; } return ret.get(0); }
@Transactional(readOnly = true) private void checkIfBackupStorageAttachedToMyZone(String bsUuid) { String sql = "select bs.uuid from BackupStorageVO bs, BackupStorageZoneRefVO ref where bs.uuid = ref.backupStorageUuid and ref.zoneUuid = :zoneUuid and bs.uuid = :bsUuid"; TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("zoneUuid", self.getZoneUuid()); q.setParameter("bsUuid", bsUuid); if (q.getResultList().isEmpty()) { throw new OperationFailureException( errf.stringToOperationError( String.format( "backup storage[uuid:%s] is not attached to zone[uuid:%s] the primary storage[uuid:%s] belongs to", bsUuid, self.getZoneUuid(), self.getUuid()))); } }
@Transactional(readOnly = true) private List<String> getVmUuidFromL2NetworkDetached(List<L2NetworkDetachStruct> structs) { List<String> vmUuids = new ArrayList<String>(); for (L2NetworkDetachStruct s : structs) { String sql = "select vm.uuid from VmInstanceVO vm, L2NetworkVO l2, L3NetworkVO l3, VmNicVO nic where vm.type = :vmType and vm.clusterUuid = :clusterUuid and vm.state not in (:vmStates) and vm.uuid = nic.vmInstanceUuid and nic.l3NetworkUuid = l3.uuid and l3.l2NetworkUuid = l2.uuid and l2.uuid = :l2Uuid"; TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("vmType", VmInstanceConstant.USER_VM_TYPE); q.setParameter( "vmStates", Arrays.asList( VmInstanceState.Stopped, VmInstanceState.Migrating, VmInstanceState.Stopping)); q.setParameter("clusterUuid", s.getClusterUuid()); q.setParameter("l2Uuid", s.getL2NetworkUuid()); vmUuids.addAll(q.getResultList()); } return vmUuids; }
@Transactional(readOnly = true) private List<String> getVmUuidForPrimaryStorageDetached( List<PrimaryStorageDetachStruct> structs) { List<String> vmUuids = new ArrayList<String>(); for (PrimaryStorageDetachStruct s : structs) { String sql = "select vm.uuid from VmInstanceVO vm, PrimaryStorageVO ps, VolumeVO vol where vm.type = :vmType and vm.state not in (:vmStates) and vm.clusterUuid = :clusterUuid and vm.uuid = vol.vmInstanceUuid and vol.primaryStorageUuid = :psUuid"; TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("vmType", VmInstanceConstant.USER_VM_TYPE); q.setParameter( "vmStates", Arrays.asList( VmInstanceState.Stopped, VmInstanceState.Migrating, VmInstanceState.Stopping)); q.setParameter("clusterUuid", s.getClusterUuid()); q.setParameter("psUuid", s.getPrimaryStorageUuid()); vmUuids.addAll(q.getResultList()); } return vmUuids; }
@Transactional(readOnly = true) private List<VmInstanceVO> getCandidateVmForAttaching(String accountUuid) { List<String> vmUuids = acntMgr.getResourceUuidsCanAccessByAccount(accountUuid, VmInstanceVO.class); if (vmUuids != null && vmUuids.isEmpty()) { return new ArrayList<VmInstanceVO>(); } TypedQuery<VmInstanceVO> q = null; String sql; if (vmUuids == null) { // all vms if (self.getStatus() == VolumeStatus.Ready) { sql = "select vm from VmInstanceVO vm, PrimaryStorageClusterRefVO ref, VolumeVO vol where vm.state in (:vmStates) and vol.uuid = :volUuid and vm.hypervisorType in (:hvTypes) and vm.clusterUuid = ref.clusterUuid and ref.primaryStorageUuid = vol.primaryStorageUuid group by vm.uuid"; q = dbf.getEntityManager().createQuery(sql, VmInstanceVO.class); q.setParameter("volUuid", self.getUuid()); List<String> hvTypes = VolumeFormat.valueOf(self.getFormat()) .getHypervisorTypesSupportingThisVolumeFormatInString(); q.setParameter("hvTypes", hvTypes); } else if (self.getStatus() == VolumeStatus.NotInstantiated) { sql = "select vm from VmInstanceVO vm where vm.state in (:vmStates) group by vm.uuid"; q = dbf.getEntityManager().createQuery(sql, VmInstanceVO.class); } else { DebugUtils.Assert( false, String.format("should not reach here, volume[uuid:%s]", self.getUuid())); } } else { if (self.getStatus() == VolumeStatus.Ready) { sql = "select vm from VmInstanceVO vm, PrimaryStorageClusterRefVO ref, VolumeVO vol where vm.uuid in (:vmUuids) and vm.state in (:vmStates) and vol.uuid = :volUuid and vm.hypervisorType in (:hvTypes) and vm.clusterUuid = ref.clusterUuid and ref.primaryStorageUuid = vol.primaryStorageUuid group by vm.uuid"; q = dbf.getEntityManager().createQuery(sql, VmInstanceVO.class); q.setParameter("volUuid", self.getUuid()); List<String> hvTypes = VolumeFormat.valueOf(self.getFormat()) .getHypervisorTypesSupportingThisVolumeFormatInString(); q.setParameter("hvTypes", hvTypes); } else if (self.getStatus() == VolumeStatus.NotInstantiated) { sql = "select vm from VmInstanceVO vm where vm.uuid in (:vmUuids) and vm.state in (:vmStates) group by vm.uuid"; q = dbf.getEntityManager().createQuery(sql, VmInstanceVO.class); } else { DebugUtils.Assert( false, String.format("should not reach here, volume[uuid:%s]", self.getUuid())); } q.setParameter("vmUuids", vmUuids); } q.setParameter("vmStates", Arrays.asList(VmInstanceState.Running, VmInstanceState.Stopped)); List<VmInstanceVO> vms = q.getResultList(); if (vms.isEmpty()) { return vms; } VolumeInventory vol = getSelfInventory(); for (VolumeGetAttachableVmExtensionPoint ext : pluginRgty.getExtensionList(VolumeGetAttachableVmExtensionPoint.class)) { vms = ext.returnAttachableVms(vol, vms); } return vms; }
@Override @Transactional(readOnly = true) public List<VolumeVO> returnAttachableVolumes(VmInstanceInventory vm, List<VolumeVO> candidates) { // find instantiated volumes List<String> volUuids = CollectionUtils.transformToList( candidates, new Function<String, VolumeVO>() { @Override public String call(VolumeVO arg) { return VolumeStatus.Ready == arg.getStatus() ? arg.getUuid() : null; } }); if (volUuids.isEmpty()) { return candidates; } List<VolumeVO> uninstantiatedVolumes = CollectionUtils.transformToList( candidates, new Function<VolumeVO, VolumeVO>() { @Override public VolumeVO call(VolumeVO arg) { return arg.getStatus() == VolumeStatus.NotInstantiated ? arg : null; } }); String sql = "select ref.hostUuid from LocalStorageResourceRefVO ref where ref.resourceUuid = :volUuid and ref.resourceType = :rtype"; TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("volUuid", vm.getRootVolumeUuid()); q.setParameter("rtype", VolumeVO.class.getSimpleName()); List<String> ret = q.getResultList(); if (ret.isEmpty()) { return candidates; } String hostUuid = ret.get(0); sql = "select ref.resourceUuid from LocalStorageResourceRefVO ref where ref.resourceUuid in (:uuids) and ref.resourceType = :rtype" + " and ref.hostUuid != :huuid"; q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("uuids", volUuids); q.setParameter("huuid", hostUuid); q.setParameter("rtype", VolumeVO.class.getSimpleName()); final List<String> toExclude = q.getResultList(); candidates = CollectionUtils.transformToList( candidates, new Function<VolumeVO, VolumeVO>() { @Override public VolumeVO call(VolumeVO arg) { return toExclude.contains(arg.getUuid()) ? null : arg; } }); candidates.addAll(uninstantiatedVolumes); return candidates; }