package org.ovirt.engine.core.bll.storage; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.ovirt.engine.core.bll.Backend; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.action.ExtendSANStorageDomainParameters; import org.ovirt.engine.core.common.businessentities.LUNs; import org.ovirt.engine.core.common.businessentities.VDS; import org.ovirt.engine.core.common.businessentities.VdsSpmStatus; import org.ovirt.engine.core.common.config.Config; import org.ovirt.engine.core.common.config.ConfigValues; import org.ovirt.engine.core.common.vdscommands.GetDeviceListVDSCommandParameters; import org.ovirt.engine.core.common.vdscommands.GetDevicesVisibilityVDSCommandParameters; import org.ovirt.engine.core.common.vdscommands.VDSCommandType; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.compat.LogCompat; import org.ovirt.engine.core.compat.LogFactoryCompat; import org.ovirt.engine.core.utils.Pair; import org.ovirt.engine.core.utils.linq.LinqUtils; import org.ovirt.engine.core.utils.linq.Predicate; public class ConnectAllHostsToLunCommand<T extends ExtendSANStorageDomainParameters> extends StorageDomainCommandBase<T> { public ConnectAllHostsToLunCommand(T parameters) { super(parameters); } @Override protected void executeCommand() { java.util.ArrayList<LUNs> processedLunsList = new java.util.ArrayList<LUNs>(); boolean operationSucceeded = true; // VDS spmVds = null; // LINQ AllRunningVdssInPool.Where(vds => // vds.spm_status == VdsSpmStatus.SPM).First(); VDS spmVds = (VDS) LinqUtils.filter(getAllRunningVdssInPool(), new Predicate<VDS>() { @Override public boolean eval(VDS vds) { return vds.getspm_status() == VdsSpmStatus.SPM; } }).get(0); List<LUNs> luns = (List<LUNs>) Backend .getInstance() .getResourceManager() .RunVdsCommand( VDSCommandType.GetDeviceList, new GetDeviceListVDSCommandParameters(spmVds.getvds_id(), getStorageDomain().getstorage_type())) .getReturnValue(); Map<String, LUNs> lunsMap = new HashMap<String, LUNs>(); for (LUNs lun : luns) { lunsMap.put(lun.getLUN_id(), lun); } for (String lunId : getParameters().getLunIds()) { LUNs lun = lunsMap.get(lunId); if (lun == null) { operationSucceeded = false; break; } lun.setvolume_group_id(getStorageDomain().getstorage()); processedLunsList.add(lun); } if (operationSucceeded) { // connect all vds in pool (except spm) to lun and getDeviceList Pair<Boolean, Map<String, List<Guid>>> result = ConnectVdsToLun(processedLunsList); if (result.getFirst()) { getReturnValue().setActionReturnValue(processedLunsList); setCommandShouldBeLogged(false); setSucceeded(true); } else { // disconnect all hosts if connection is not in use by other luns Map<String, List<Guid>> processed = result.getSecond(); for (String lunId : processed.keySet()) { for (Guid vdsId : processed.get(lunId)) { LUNs lun = lunsMap.get(lunId); StorageHelperDirector.getInstance().getItem(getStoragePool().getstorage_pool_type()) .DisconnectStorageFromLunByVdsId(getStorageDomain(), vdsId, lun); } } } } } /** * The following method will connect all provided lund to all running host in pool * * @param luns * - the luns which should be connected * @return the map where the key is true/false value which means if connection successes/not successes and value is * map of luns Ids -> connected hosts */ private Pair<Boolean, Map<String, List<Guid>>> ConnectVdsToLun(List<LUNs> luns) { // all vdss in pool except spm (already connected) Map<String, List<Guid>> resultMap = new HashMap<String, List<Guid>>(); for (VDS vds : getAllRunningVdssInPool()) { if (vds.getspm_status() == VdsSpmStatus.SPM) continue; // try to connect vds to luns and getDeviceList in order to refresh them for (LUNs lun : luns) { if (!StorageHelperDirector.getInstance().getItem(getStorageDomain().getstorage_type()) .ConnectStorageToLunByVdsId(getStorageDomain(), vds.getvds_id(), lun)) { log.errorFormat("Could not connect host {0} to lun {1}", vds.getvds_name(), lun.getLUN_id()); setVds(vds); return new Pair<Boolean, Map<String, List<Guid>>>(Boolean.FALSE, resultMap); } else { List<Guid> hosts = resultMap.get(lun.getLUN_id()); if (hosts == null) { hosts = new ArrayList<Guid>(); resultMap.put(lun.getLUN_id(), hosts); } hosts.add(vds.getvds_id()); } } // Refresh all connected luns to host if (!Config.<Boolean> GetValue(ConfigValues.SupportGetDevicesVisibility, vds.getvds_group_compatibility_version().getValue())) { Set<String> hostsLunsIds = new HashSet<String>(); List<LUNs> hostLuns = (List<LUNs>) Backend .getInstance() .getResourceManager() .RunVdsCommand( VDSCommandType.GetDeviceList, new GetDeviceListVDSCommandParameters(vds.getvds_id(), getStorageDomain().getstorage_type())).getReturnValue(); for (LUNs lun : hostLuns) { hostsLunsIds.add(lun.getLUN_id()); } for (LUNs lun : luns) { if (!hostsLunsIds.contains(lun.getLUN_id())) { return new Pair<Boolean, Map<String, List<Guid>>>(Boolean.FALSE, resultMap); } } } else if (!validateConnectedLuns(vds, getParameters().getLunIds())) { return new Pair<Boolean, Map<String, List<Guid>>>(Boolean.FALSE, resultMap); } } return new Pair<Boolean, Map<String, List<Guid>>>(Boolean.TRUE, resultMap); } /** * The following method will check which luns were successfully connected to vds * * @param vds * - the host * @param processedLunIds * - luns ids which we wants to check * @return - true if all connections successes, false otherwise */ private boolean validateConnectedLuns(VDS vds, List<String> processedLunIds) { Map<String, Boolean> returnValue = (Map<String, Boolean>) Backend.getInstance() .getResourceManager() .RunVdsCommand(VDSCommandType.GetDevicesVisibility, new GetDevicesVisibilityVDSCommandParameters(vds.getvds_id(), processedLunIds.toArray(new String[processedLunIds.size()]))).getReturnValue(); for (Map.Entry<String, Boolean> returnValueEntry : returnValue.entrySet()) { if (!Boolean.TRUE.equals(returnValueEntry.getValue())) { return false; } } return true; } @Override public AuditLogType getAuditLogTypeValue() { // this should return only error, if command succeeded no logging is // required return AuditLogType.USER_CONNECT_HOSTS_TO_LUN_FAILED; } private static LogCompat log = LogFactoryCompat.getLog(ConnectAllHostsToLunCommand.class); }