/*
* Copyright (c) 2012-2015 iWave Software LLC
* All Rights Reserved
*/
package com.iwave.ext.vmware;
import java.rmi.RemoteException;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.iwave.ext.command.HostRescanAdapter;
import com.vmware.vim25.AlreadyExists;
import com.vmware.vim25.DuplicateName;
import com.vmware.vim25.HostConfigFault;
import com.vmware.vim25.HostFibreChannelHba;
import com.vmware.vim25.HostFibreChannelTargetTransport;
import com.vmware.vim25.HostFileSystemMountInfo;
import com.vmware.vim25.HostHostBusAdapter;
import com.vmware.vim25.HostInternetScsiHba;
import com.vmware.vim25.HostInternetScsiHbaSendTarget;
import com.vmware.vim25.HostInternetScsiTargetTransport;
import com.vmware.vim25.HostMultipathInfoFixedLogicalUnitPolicy;
import com.vmware.vim25.HostMultipathInfoLogicalUnitPolicy;
import com.vmware.vim25.HostNasVolumeSpec;
import com.vmware.vim25.HostPathSelectionPolicyOption;
import com.vmware.vim25.HostScsiDisk;
import com.vmware.vim25.HostScsiDiskPartition;
import com.vmware.vim25.HostScsiTopology;
import com.vmware.vim25.HostScsiTopologyInterface;
import com.vmware.vim25.HostScsiTopologyLun;
import com.vmware.vim25.HostScsiTopologyTarget;
import com.vmware.vim25.HostStorageDeviceInfo;
import com.vmware.vim25.HostTargetTransport;
import com.vmware.vim25.HostVmfsVolume;
import com.vmware.vim25.InvalidProperty;
import com.vmware.vim25.NotFound;
import com.vmware.vim25.ResourceInUse;
import com.vmware.vim25.RuntimeFault;
import com.vmware.vim25.ScsiLun;
import com.vmware.vim25.VmfsDatastoreCreateSpec;
import com.vmware.vim25.VmfsDatastoreExpandSpec;
import com.vmware.vim25.VmfsDatastoreExtendSpec;
import com.vmware.vim25.VmfsDatastoreInfo;
import com.vmware.vim25.VmfsDatastoreOption;
import com.vmware.vim25.mo.Datastore;
import com.vmware.vim25.mo.HostDatastoreSystem;
import com.vmware.vim25.mo.HostStorageSystem;
import com.vmware.vim25.mo.HostSystem;
/**
* API for host storage operations using VMware.
*
* @author jonnymiller
*/
public class HostStorageAPI implements HostRescanAdapter {
private static final String VMW_PSP_RR = "VMW_PSP_RR";
private static final String VMW_PSP_MRU = "VMW_PSP_MRU";
private static final String VMW_PSP_FIXED = "VMW_PSP_FIXED";
public static final List<String> MULTIPATH_POLICY_TYPES = Arrays.asList(VMW_PSP_RR, VMW_PSP_MRU, VMW_PSP_FIXED);
private HostSystem host;
public HostStorageAPI(HostSystem host) {
this.host = host;
}
public HostSystem getHostSystem() {
return host;
}
/**
* Gets the host storage system for the host.
*
* @return the host storage system.
*/
public HostStorageSystem getStorageSystem() {
try {
return host.getHostStorageSystem();
} catch (InvalidProperty e) {
throw new VMWareException(e);
} catch (RuntimeFault e) {
throw new VMWareException(e);
} catch (RemoteException e) {
throw new VMWareException(e);
}
}
/**
* Query to list disks that can be used to contain VMFS datastore extents
*
* @param datastore if provided, finds disks that can contain extents for this datastore
* @return list of available disks
*/
public List<HostScsiDisk> queryAvailableDisksForVmfs(Datastore datastore) {
try {
List<HostScsiDisk> scsiDisks = Lists.newArrayList();
addItems(scsiDisks, host.getHostDatastoreSystem().queryAvailableDisksForVmfs(datastore), HostScsiDisk.class);
return scsiDisks;
} catch (InvalidProperty e) {
throw new VMWareException(e);
} catch (RuntimeFault e) {
throw new VMWareException(e);
} catch (RemoteException e) {
throw new VMWareException(e);
}
}
/**
* Gets the host datastore system for the host.
*
* @return the host datastore system.
*/
public HostDatastoreSystem getDatastoreSystem() {
try {
return host.getHostDatastoreSystem();
} catch (InvalidProperty e) {
throw new VMWareException(e);
} catch (RuntimeFault e) {
throw new VMWareException(e);
} catch (RemoteException e) {
throw new VMWareException(e);
}
}
/**
* Gets supported multipath policies
*
* @return list of multipath policies
*/
public HostPathSelectionPolicyOption[] getPathSelectionPolicyOptions() {
try {
HostStorageSystem storageSystem = getStorageSystem();
return storageSystem.queryPathSelectionPolicyOptions();
} catch (HostConfigFault e) {
throw new VMWareException(e);
} catch (RuntimeFault e) {
throw new VMWareException(e);
} catch (RemoteException e) {
throw new VMWareException(e);
}
}
/**
* Sets the multipath policy on the given lun
*
* @param lun the lun to set the policy on
* @param multipathPolicy name of the multipath policy
*/
public void setMultipathPolicy(HostScsiDisk lun, String multipathPolicy) {
try {
HostStorageSystem storageSystem = getStorageSystem();
HostMultipathInfoLogicalUnitPolicy policy = createMultipathPolicy(multipathPolicy);
storageSystem.setMultipathLunPolicy(lun.getUuid(), policy);
} catch (HostConfigFault e) {
throw new VMWareException(e);
} catch (NotFound e) {
throw new VMWareException(e);
} catch (RuntimeFault e) {
throw new VMWareException(e);
} catch (RemoteException e) {
throw new VMWareException(e);
}
}
/**
* Attaches the lun.
*/
public void attachScsiLun(HostScsiDisk disk) {
try {
HostStorageSystem storageSystem = getStorageSystem();
storageSystem.attachScsiLun(disk.getUuid());
} catch (HostConfigFault e) {
throw new VMWareException(e);
} catch (RuntimeFault e) {
throw new VMWareException(e);
} catch (RemoteException e) {
throw new VMWareException(e);
}
}
/**
* Detaches the lun.
*/
public void detachScsiLun(HostScsiDisk disk) {
try {
HostStorageSystem storageSystem = getStorageSystem();
storageSystem.detachScsiLun(disk.getUuid());
} catch (HostConfigFault e) {
throw new VMWareException(e);
} catch (RuntimeFault e) {
throw new VMWareException(e);
} catch (RemoteException e) {
throw new VMWareException(e);
}
}
/**
* Attaches the datastore.
*/
public void mountDatastore(Datastore datastore) {
try {
HostStorageSystem storageSystem = getStorageSystem();
String vmfsUuid = getVmfsVolumeUuid(datastore);
storageSystem.mountVmfsVolume(vmfsUuid);
} catch (HostConfigFault e) {
throw new VMWareException(e);
} catch (RuntimeFault e) {
throw new VMWareException(e);
} catch (RemoteException e) {
throw new VMWareException(e);
}
}
/**
* Rescans the HBAs on the host.
*/
public void rescanHBAs() {
try {
HostStorageSystem storageSystem = getStorageSystem();
storageSystem.rescanAllHba();
} catch (HostConfigFault e) {
throw new VMWareException(e);
} catch (RuntimeFault e) {
throw new VMWareException(e);
} catch (RemoteException e) {
throw new VMWareException(e);
}
}
/**
* Refreshes the storage on the host.
*/
public void refreshStorage() {
try {
HostStorageSystem storageSystem = getStorageSystem();
storageSystem.rescanAllHba();
storageSystem.rescanVmfs();
} catch (HostConfigFault e) {
throw new VMWareException(e);
} catch (RuntimeFault e) {
throw new VMWareException(e);
} catch (RemoteException e) {
throw new VMWareException(e);
}
}
/**
* Gets the host storage device info.
*
* @return the host storage device info.
*/
public HostStorageDeviceInfo getStorageDeviceInfo() {
HostStorageSystem storageSystem = getStorageSystem();
if (storageSystem != null) {
return storageSystem.getStorageDeviceInfo();
}
else {
return null;
}
}
/**
* Lists all SCSI disks on the host system.
*
* @return the list of SCSI disks.
*/
public List<HostScsiDisk> listScsiDisks() {
List<HostScsiDisk> scsiDisks = Lists.newArrayList();
HostStorageDeviceInfo storageDeviceInfo = getStorageDeviceInfo();
if (storageDeviceInfo != null) {
addItems(scsiDisks, storageDeviceInfo.getScsiLun(), HostScsiDisk.class);
}
return scsiDisks;
}
/**
* Gets the mapping of SCSI disks, mapped by key.
*
* @return the key to SCSI disk mapping.
*/
public Map<String, HostScsiDisk> getScsiDisksByKey() {
Map<String, HostScsiDisk> map = Maps.newLinkedHashMap();
for (HostScsiDisk disk : listScsiDisks()) {
map.put(disk.getKey(), disk);
}
return map;
}
/**
* Gets teh mapping of SCSI disks, mapped by canonical name.
*
* @return the name to SCSI disk mapping.
*/
public Map<String, HostScsiDisk> getScsiDisksByCanonicalName() {
Map<String, HostScsiDisk> map = Maps.newLinkedHashMap();
for (HostScsiDisk disk : listScsiDisks()) {
map.put(disk.getCanonicalName(), disk);
}
return map;
}
/**
* Gets a SCSI disk by key.
*
* @param key the disk key.
* @return the SCSI disk.
*/
public HostScsiDisk getScsiDiskByKey(String key) {
HostStorageDeviceInfo storageDeviceInfo = getStorageDeviceInfo();
if ((storageDeviceInfo != null) && (storageDeviceInfo.getScsiLun() != null)) {
for (ScsiLun lun : storageDeviceInfo.getScsiLun()) {
// Find the LUN with the matching key that is a HostScsiDisk
if (StringUtils.equals(key, lun.getKey()) && (lun instanceof HostScsiDisk)) {
return (HostScsiDisk) lun;
}
}
}
return null;
}
/**
* Finds the SCSI disk for the LUN that is associated with one or more targets, from the
* specified sources. The sources and targets should be either port WWNs or iSCSI IQNs.
*
* @param hlu the host LUN id.
* @param sourceNames the source names (host HBAs) for the LUN.
* @param targetNames the target names (array HBAs) for the LUN.
* @return the SCSI disk.
*/
public HostScsiDisk findLunDisk(int hlu, Collection<String> sourceNames,
Collection<String> targetNames) {
Map<String, HostHostBusAdapter> hbas = getHostBusAdapters();
String diskKey = null;
for (HostScsiTopologyInterface adapter : listScsiTopologyInterfaces()) {
HostHostBusAdapter hba = hbas.get(adapter.getAdapter());
String sourceName = getSourceName(hba);
if (!sourceNames.contains(sourceName) || (adapter.getTarget() == null)) {
continue;
}
for (HostScsiTopologyTarget target : adapter.getTarget()) {
String targetName = getTargetName(target);
if (!targetNames.contains(targetName)) {
continue;
}
HostScsiTopologyLun lun = findLun(target, hlu);
if (lun != null) {
String key = lun.getScsiLun();
if (diskKey == null) {
diskKey = key;
}
// Make sure the LUNs all map to the same SCSI disk
else if (!StringUtils.equals(diskKey, key)) {
throw new IllegalArgumentException("LUN " + hlu
+ " maps to different disks for " + targetNames);
}
}
}
}
if (diskKey == null) {
return null;
}
HostScsiDisk disk = getScsiDiskByKey(diskKey);
return disk;
}
/**
* Lists the host bus adapters.
*
* @return the list of host bus adapters.
*/
public List<HostHostBusAdapter> listHostBusAdapters() {
HostStorageDeviceInfo storageDeviceInfo = getStorageDeviceInfo();
if (storageDeviceInfo != null) {
return createList(storageDeviceInfo.getHostBusAdapter());
}
else {
return Lists.newArrayList();
}
}
/**
* Gets a map of host bus adapters, mapped by key.
*
* @return the key to host bus adapter mapping.
*/
public Map<String, HostHostBusAdapter> getHostBusAdapters() {
Map<String, HostHostBusAdapter> map = Maps.newLinkedHashMap();
for (HostHostBusAdapter hba : listHostBusAdapters()) {
map.put(hba.getKey(), hba);
}
return map;
}
/**
* Finds the host bus adapter in the system with the specified key. This will query the host
* each time, so if many host bus adapters need to be retrieved use {@link #getHostBusAdapters(HostSystem)} instead.
*
* @param key the adapter key.
* @return the host bus adapter.
*/
public HostHostBusAdapter findHostBusAdapter(String key) {
for (HostHostBusAdapter hba : listHostBusAdapters()) {
if (StringUtils.equals(hba.getKey(), key)) {
return hba;
}
}
return null;
}
/**
* Adds iSCSI send targets to the given host.
*
* @param addresses
*/
public void addInternetScsiSendTargets(HostInternetScsiHba hba, String... addresses) {
addInternetScsiSendTargets(getStorageSystem(), hba, addresses);
}
/**
* Adds iSCSI send targets to the host storage system.
*
* @param storageSystem the storage system.
* @param hba the iSCSI host bus adapter.
* @param addresses the address of the targets.
*/
public void addInternetScsiSendTargets(HostStorageSystem storageSystem,
HostInternetScsiHba hba, String... addresses) {
try {
storageSystem.addInternetScsiSendTargets(hba.getDevice(),
createInternetScsiSendTargets(addresses));
} catch (HostConfigFault e) {
throw new VMWareException(e);
} catch (NotFound e) {
throw new VMWareException(e);
} catch (RuntimeFault e) {
throw new VMWareException(e);
} catch (RemoteException e) {
throw new VMWareException(e);
}
}
/**
* Gets the SCSI topology for the host.
*
* @return the SCSI topology.
*/
public HostScsiTopology getScsiTopology() {
HostStorageDeviceInfo storageDeviceInfo = getStorageDeviceInfo();
if (storageDeviceInfo != null) {
return storageDeviceInfo.getScsiTopology();
}
else {
return null;
}
}
/**
* Lists the SCSI topology interfaces for the given host.
*
* @return the SCSI topology.
*/
public List<HostScsiTopologyInterface> listScsiTopologyInterfaces() {
HostScsiTopology scsiTopology = getScsiTopology();
if (scsiTopology != null) {
return createList(scsiTopology.getAdapter());
}
else {
return Lists.newArrayList();
}
}
/**
* Lists the SCSI topology targets on the host system.
*
* @return the list of SCSI topology targets.
*/
public List<HostScsiTopologyTarget> listScsiTopologyTargets() {
List<HostScsiTopologyTarget> targets = Lists.newArrayList();
for (HostScsiTopologyInterface adapter : listScsiTopologyInterfaces()) {
if (adapter.getTarget() == null) {
continue;
}
addItems(targets, adapter.getTarget());
}
return targets;
}
/**
* Creates a VMFS datastore.
*
* @param disk the disk on which to create the datastore.
* @param datastoreName the datastore name.
*/
public Datastore createVmfsDatastore(HostScsiDisk disk, String datastoreName) {
VmfsDatastoreCreateSpec createSpec = getVmfsDatastoreCreateSpec(disk, datastoreName);
try {
Datastore datastore = getDatastoreSystem().createVmfsDatastore(createSpec);
return datastore;
} catch (HostConfigFault e) {
throw new VMWareException(e);
} catch (DuplicateName e) {
throw new VMWareException(e);
} catch (RuntimeFault e) {
throw new VMWareException(e);
} catch (RemoteException e) {
throw new VMWareException(e);
}
}
/**
* Extends a VMFS datastore.
*
* @param disk the disk to use to extend the datastore.
* @param datastore the datastore to extend.
* @return the extended datastore.
*/
public Datastore extendVmfsDatastore(HostScsiDisk disk, Datastore datastore) {
VmfsDatastoreExtendSpec extendSpec = getVmfsDatastoreExtendSpec(disk, datastore);
try {
return getDatastoreSystem().extendVmfsDatastore(datastore, extendSpec);
} catch (HostConfigFault e) {
throw new VMWareException(e);
} catch (NotFound e) {
throw new VMWareException(e);
} catch (RuntimeFault e) {
throw new VMWareException(e);
} catch (RemoteException e) {
throw new VMWareException(e);
}
}
/**
* Expands a VMFS datastore on a given disk.
*
* @param disk the disk on which the expansion should occur.
* @param datastore the datastore.
* @return the expanded datastore.
*/
public Datastore expandVmfsDatastore(HostScsiDisk disk, Datastore datastore) {
VmfsDatastoreExpandSpec expandSpec = getVmfsDatastoreExpandSpec(disk, datastore);
try {
return getDatastoreSystem().expandVmfsDatastore(datastore, expandSpec);
} catch (HostConfigFault e) {
throw new VMWareException(e);
} catch (NotFound e) {
throw new VMWareException(e);
} catch (RuntimeFault e) {
throw new VMWareException(e);
} catch (RemoteException e) {
throw new VMWareException(e);
}
}
/**
* Creates a NAS Datastore
*
* @param datastoreName
* @param remoteHost host name or IP of the NFS/CIFS server
* @param remotePath path of the NAS storage. Ex. "/vol/mystorage"
* @param accessMode
* @param nasType Type of NAS storage CIFS or NFS
* @param userName username for CIFS
* @param password password for CIFS
* @return
*/
public Datastore createNASDatastore(String datastoreName, String remoteHost, String remotePath,
final DataStoreAccessMode accessMode, final NasType nasType, final String userName,
final String password) {
HostNasVolumeSpec hnvs = getNASDatastoreCreateSpec(remoteHost, remotePath, datastoreName,
accessMode, nasType, userName, password);
try {
return getDatastoreSystem().createNasDatastore(hnvs);
} catch (HostConfigFault e) {
throw new VMWareException(e);
} catch (DuplicateName e) {
throw new VMWareException(e);
} catch (AlreadyExists e) {
throw new VMWareException(e);
} catch (RuntimeFault e) {
throw new VMWareException(e);
} catch (RemoteException e) {
throw new VMWareException(e);
}
}
/**
* Creates a read/write NFS datastore
*
* @param datastoreName
* @param remoteHost NFS server host name or IP
* @param remotePath NFS server remote path
* @return
*/
public Datastore createNfsDatastore(String datastoreName, String remoteHost, String remotePath) {
return createNASDatastore(datastoreName, remoteHost, remotePath,
DataStoreAccessMode.readWrite, NasType.NFS, null, null);
}
/**
* Deletes a datastore from the host.
*
* @param datastore the VMFS datastore.
*/
public void deleteDatastore(Datastore datastore) {
try {
getDatastoreSystem().removeDatastore(datastore);
} catch (HostConfigFault e) {
throw new VMWareException(e);
} catch (ResourceInUse e) {
throw new VMWareException(e);
} catch (NotFound e) {
throw new VMWareException(e);
} catch (RuntimeFault e) {
throw new VMWareException(e);
} catch (RemoteException e) {
throw new VMWareException(e);
}
}
/**
* Query for the VMFS datastore create options.
*
* @param disk the disk for the datastore.
* @return the VMFS datastore create options.
*/
public List<VmfsDatastoreOption> queryVmfsDatastoreCreateOptions(HostScsiDisk disk) {
HostDatastoreSystem datastoreSystem = getDatastoreSystem();
try {
return createList(datastoreSystem.queryVmfsDatastoreCreateOptions(disk.getDevicePath()));
} catch (HostConfigFault e) {
throw new VMWareException(e);
} catch (NotFound e) {
throw new VMWareException(e);
} catch (RuntimeFault e) {
throw new VMWareException(e);
} catch (RemoteException e) {
throw new VMWareException(e);
}
}
/**
* Gets a VMFS datastore create spec for the given disk and datastore name.
*
* @param disk the disk.
* @param datastoreName the datastore name.
* @return the VMFS datastore create spec.
*/
public VmfsDatastoreCreateSpec getVmfsDatastoreCreateSpec(HostScsiDisk disk,
String datastoreName) {
List<VmfsDatastoreOption> createOptions = queryVmfsDatastoreCreateOptions(disk);
VmfsDatastoreCreateSpec createSpec = pickBestCreateSpec(createOptions);
if (createSpec == null) {
throw new VMWareException("No VMFS datastore create spec. Volume may already contain a datastore.");
}
createSpec.getVmfs().setVolumeName(datastoreName);
return createSpec;
}
/**
* Picks the best create spec from the list of datastore options.
*
* @param createOptions the list of create options.
* @return the best datastore create spec.
*/
public VmfsDatastoreCreateSpec pickBestCreateSpec(List<VmfsDatastoreOption> createOptions) {
if ((createOptions == null) || createOptions.isEmpty()) {
return null;
}
VmfsDatastoreCreateSpec bestSpec = (VmfsDatastoreCreateSpec) createOptions.get(0).getSpec();
// Choose the create spec that uses the most recent VMFS version
for (int i = 1; i < createOptions.size(); i++) {
VmfsDatastoreOption createOption = createOptions.get(i);
VmfsDatastoreCreateSpec currentSpec = (VmfsDatastoreCreateSpec) createOption.getSpec();
if (currentSpec.getVmfs().getMajorVersion() > bestSpec.getVmfs().getMajorVersion()) {
bestSpec = currentSpec;
}
}
return bestSpec;
}
/**
* Create a multipath policy based on the passed policy name
*
* @param name policy name
* @return multipath policy
*/
public HostMultipathInfoLogicalUnitPolicy createMultipathPolicy(String name) {
if (StringUtils.equalsIgnoreCase(name, VMW_PSP_FIXED)) {
HostMultipathInfoFixedLogicalUnitPolicy policy = new HostMultipathInfoFixedLogicalUnitPolicy();
policy.setPolicy(name);
policy.setPrefer("");
return policy;
} else {
HostMultipathInfoLogicalUnitPolicy policy = new HostMultipathInfoLogicalUnitPolicy();
policy.setPolicy(name);
return policy;
}
}
/**
* Query for the VMFS datastore extend options.
*
* @param disk the disk for the datastore.
* @param datastore the datastore.
* @return the VMFS datastore extend options.
*/
public List<VmfsDatastoreOption> queryVmfsDatastoreExtendOptions(HostScsiDisk disk,
Datastore datastore) {
HostDatastoreSystem datastoreSystem = getDatastoreSystem();
try {
return createList(datastoreSystem.queryVmfsDatastoreExtendOptions(datastore,
disk.getDevicePath(), true));
} catch (HostConfigFault e) {
throw new VMWareException(e);
} catch (NotFound e) {
throw new VMWareException(e);
} catch (RuntimeFault e) {
throw new VMWareException(e);
} catch (RemoteException e) {
throw new VMWareException(e);
}
}
/**
* Gets the first VMFS datastore extend spec.
*
* @param disk the disk.
* @param datastore the datastore.
* @return the VMFS datastore extend spec.
*/
public VmfsDatastoreExtendSpec getVmfsDatastoreExtendSpec(HostScsiDisk disk, Datastore datastore) {
List<VmfsDatastoreOption> extendOptions = queryVmfsDatastoreExtendOptions(disk, datastore);
VmfsDatastoreExtendSpec extendSpec = pickBestExtendSpec(extendOptions);
if (extendSpec == null) {
throw new VMWareException("No VMFS datastore extend spec");
}
return extendSpec;
}
/**
* Picks the best extend spec. This just picks the first extend spec.
*
* @param extendOptions the available extend options.
* @return the extend spec.
*/
public VmfsDatastoreExtendSpec pickBestExtendSpec(List<VmfsDatastoreOption> extendOptions) {
if ((extendOptions == null) || extendOptions.isEmpty()) {
return null;
}
VmfsDatastoreExtendSpec bestSpec = (VmfsDatastoreExtendSpec) extendOptions.get(0).getSpec();
return bestSpec;
}
/**
* Query for the VMFS datastore expand options.
*
* @param datastore the datastore.
* @return the VMFS datastore expand options.
*/
public List<VmfsDatastoreOption> queryVmfsDatastoreExpandOptions(Datastore datastore) {
HostDatastoreSystem datastoreSystem = getDatastoreSystem();
try {
return createList(datastoreSystem.queryVmfsDatastoreExpandOptions(datastore));
} catch (HostConfigFault e) {
throw new VMWareException(e);
} catch (NotFound e) {
throw new VMWareException(e);
} catch (RuntimeFault e) {
throw new VMWareException(e);
} catch (RemoteException e) {
throw new VMWareException(e);
}
}
/**
* Gets the best VMFS datastore expand spec.
*
* @param datastore the datastore.
* @return the VMFS datastore expand spec.
*/
public VmfsDatastoreExpandSpec getVmfsDatastoreExpandSpec(HostScsiDisk disk, Datastore datastore) {
List<VmfsDatastoreOption> expandOptions = queryVmfsDatastoreExpandOptions(datastore);
VmfsDatastoreExpandSpec extendSpec = pickBestExpandSpec(disk, expandOptions);
if (extendSpec == null) {
throw new VMWareException("No VMFS datastore expand spec");
}
return extendSpec;
}
/**
* Picks the best expand spec. This picks an expand spec that uses the given disk.
*
* @param disk the disk that was expanded.
* @param expandOptions the available expand options.
* @return the expand spec.
*/
public VmfsDatastoreExpandSpec pickBestExpandSpec(HostScsiDisk disk, List<VmfsDatastoreOption> expandOptions) {
if ((expandOptions == null) || expandOptions.isEmpty()) {
return null;
}
for (VmfsDatastoreOption option : expandOptions) {
VmfsDatastoreExpandSpec spec = (VmfsDatastoreExpandSpec) option.getSpec();
String diskName = spec.getExtent().getDiskName();
if (StringUtils.equals(diskName, disk.getCanonicalName())) {
return spec;
}
}
return null;
}
/**
* Creates NAS volume spec required to create a NAS Datastore
*
* @param remoteHost
* @param remotePath
* @param datastoreName
* @param accessMode
* @param nasType
* @param userName
* @param password
* @return
*/
public HostNasVolumeSpec getNASDatastoreCreateSpec(String remoteHost, String remotePath,
String datastoreName, DataStoreAccessMode accessMode, NasType nasType, String userName,
String password) {
HostNasVolumeSpec hnvs = new HostNasVolumeSpec();
hnvs.setRemoteHost(remoteHost);
hnvs.setRemotePath(remotePath);
hnvs.setLocalPath(datastoreName);
hnvs.setType(nasType.toString());
hnvs.setAccessMode(accessMode.toString()); // "readWrite" or "readOnly"
hnvs.setUserName(userName);
hnvs.setPassword(password);
return hnvs;
}
/**
* Lists the disks associated with the datastore on this host.
*
* @param datastore the datastore.
* @return the list of SCSI disks that make up the datastore.
*
* @throws IllegalArgumentException if the datastore is not a VMFS datastore.
*/
public List<HostScsiDisk> listDisks(Datastore datastore) {
List<HostScsiDisk> disks = Lists.newArrayList();
for (HostScsiDisk disk : getDisksByPartition(datastore).values()) {
if (disk != null) {
disks.add(disk);
}
}
return disks;
}
/**
* Unmount Vmfs datastore from this host storage system
*
* @param datastore the datastore
*/
public void unmountVmfsDatastore(Datastore datastore) {
try {
String vmfsUuid = getVmfsVolumeUuid(datastore);
host.getHostStorageSystem().unmountVmfsVolume(vmfsUuid);
} catch (RemoteException e) {
throw new VMWareException(e);
}
}
/**
* Get the Vmfs volume uuid from the datastore on this host
*
* @param datastore the datastore
* @return
*/
private String getVmfsVolumeUuid(Datastore datastore) {
String uuid = null;
for (HostFileSystemMountInfo mount : new HostStorageAPI(host)
.getStorageSystem().getFileSystemVolumeInfo().getMountInfo()) {
if (mount.getVolume() instanceof HostVmfsVolume
&& datastore.getName().equals(mount.getVolume().getName())) {
HostVmfsVolume volume = (HostVmfsVolume) mount.getVolume();
return volume.getUuid();
}
}
return uuid;
}
/**
* Gets the disks associated with the datastore mapped by partition.
*
* @param datastore the datastore.
* @return the disks mapped by partition.
*/
public Map<HostScsiDiskPartition, HostScsiDisk> getDisksByPartition(Datastore datastore) {
if (!(datastore.getInfo() instanceof VmfsDatastoreInfo)) {
throw new IllegalArgumentException(datastore.getName() + " is not a VMFS datastore");
}
Map<HostScsiDiskPartition, HostScsiDisk> disks = Maps.newLinkedHashMap();
Map<String, HostScsiDisk> disksByName = getScsiDisksByCanonicalName();
HostVmfsVolume volume = ((VmfsDatastoreInfo) datastore.getInfo()).getVmfs();
for (HostScsiDiskPartition partition : volume.getExtent()) {
HostScsiDisk disk = disksByName.get(partition.getDiskName());
disks.put(partition, disk);
}
return disks;
}
/**
* Converts a WWN to a normalized form for ease of comparison.
*
* @param wwn a world wide name.
* @return the normalized WWN.
*/
public static String normalizeWwn(String wwn) {
wwn = StringUtils.lowerCase(wwn);
wwn = StringUtils.replace(wwn, ":", "");
wwn = StringUtils.leftPad(wwn, 16, '0');
return wwn;
}
/**
* Converts a WWN to a normalized form for ease of comparison.
*
* @param wwn a world wide name.
* @return the normalized WWN.
*/
public static String normalizeWwn(long wwn) {
return normalizeWwn(Long.toHexString(wwn));
}
/**
* Gets the source name of the host bus adapter. This is either the WWN or IQN for FibreChannel
* or iSCSI, respectively.
*
* @param hba the host bus adapter.
* @return the source name (WWN or IQN).
*/
public static String getSourceName(HostHostBusAdapter hba) {
if (hba instanceof HostFibreChannelHba) {
long wwpn = ((HostFibreChannelHba) hba).getPortWorldWideName();
return normalizeWwn(wwpn);
}
if (hba instanceof HostInternetScsiHba) {
return ((HostInternetScsiHba) hba).getIScsiName();
}
return null;
}
/**
* Gets the target name of the SCSI topology target. This is either the WWN or IQN for
* FibreChannel or iSCSI, respectively.
*
* @param target the SCSI topology target.
* @return the target name (WWN or IQN).
*/
public static String getTargetName(HostScsiTopologyTarget target) {
HostTargetTransport transport = target.getTransport();
if (transport instanceof HostFibreChannelTargetTransport) {
long wwpn = ((HostFibreChannelTargetTransport) transport).getPortWorldWideName();
return normalizeWwn(wwpn);
}
if (transport instanceof HostInternetScsiTargetTransport) {
return ((HostInternetScsiTargetTransport) transport).getIScsiName();
}
return null;
}
/**
* Finds a LUN by HLU within SCSI topology target.
*
* @param target the SCSI topology target.
* @param hlu the host LUN id.
* @return the LUN.
*/
public static HostScsiTopologyLun findLun(HostScsiTopologyTarget target, int hlu) {
if ((target != null) && (target.getLun() != null)) {
for (HostScsiTopologyLun lun : target.getLun()) {
if (lun.getLun() == hlu) {
return lun;
}
}
}
return null;
}
/**
* Finds the LUN by disk within the SCSI topology target.
*
* @param target the SCSI topology target.
* @param disk the disk.
* @return the LUN.
*/
public static HostScsiTopologyLun findLun(HostScsiTopologyTarget target, HostScsiDisk disk) {
if ((target != null) && (target.getLun() != null)) {
for (HostScsiTopologyLun lun : target.getLun()) {
if (StringUtils.equals(disk.getKey(), lun.getScsiLun())) {
return lun;
}
}
}
return null;
}
/**
* Finds a host bus adapter in the collection by iSCSI IQN.
*
* @param hbas the collection of host bus adapters.
* @param iqn the iSCSI IQN.
* @return the iSCSI adapter, or null if no matching adapters.
*/
public static HostInternetScsiHba findHostBusAdapterByIqn(
Collection<? extends HostHostBusAdapter> hbas, String iqn) {
for (HostHostBusAdapter hba : hbas) {
if (hba instanceof HostInternetScsiHba) {
HostInternetScsiHba iscsiHba = (HostInternetScsiHba) hba;
if (StringUtils.equals(iqn, iscsiHba.getIScsiName())) {
return iscsiHba;
}
}
}
return null;
}
/**
* Finds a host bus adapter in the collection by FibreChannel port WWN.
*
* @param hbas the collection of host bus adapters.
* @param portWwn the port WWN.
* @return the FibreChannel adapter, or null if no matching adapters.
*/
public static HostFibreChannelHba findHostBusAdapterByWwn(
Collection<? extends HostHostBusAdapter> hbas, String portWwn) {
portWwn = normalizeWwn(portWwn);
for (HostHostBusAdapter hba : hbas) {
if (hba instanceof HostFibreChannelHba) {
HostFibreChannelHba fcHba = (HostFibreChannelHba) hba;
String wwn = normalizeWwn(fcHba.getPortWorldWideName());
if (StringUtils.equals(portWwn, wwn)) {
return fcHba;
}
}
}
return null;
}
/**
* Creates an array of iSCSI send targets for the given addresses. The addresses may contains an
* address only or an address and port (address:port).
*
* @param addresses the addresses.
* @return the iSCSI send targets.
*/
public static HostInternetScsiHbaSendTarget[] createInternetScsiSendTargets(String... addresses) {
HostInternetScsiHbaSendTarget[] targets = new HostInternetScsiHbaSendTarget[addresses.length];
for (int i = 0; i < addresses.length; i++) {
targets[i] = createInternetScsiSendTarget(addresses[i]);
}
return targets;
}
/**
* Creates an iSCSI sent target for the given address.
*
* @param address the address, may contain the port.
* @return the iSCSI send target.
*/
public static HostInternetScsiHbaSendTarget createInternetScsiSendTarget(String address) {
HostInternetScsiHbaSendTarget target = new HostInternetScsiHbaSendTarget();
if (StringUtils.contains(address, ':')) {
target.setAddress(StringUtils.substringBefore(address, ":"));
target.setPort(NumberUtils.toInt(StringUtils.substringAfter(address, ":")));
}
else {
target.setAddress(address);
}
return target;
}
/**
* Lists the partitions for the datastore. This will only return values for a VMFS datastore.
*
* @param datastore the datastore.
* @return the list of disk partitions for the VMFS datastore.
*/
protected static List<HostScsiDiskPartition> listPartitions(Datastore datastore) {
List<HostScsiDiskPartition> partitions = Lists.newArrayList();
if (datastore.getInfo() instanceof VmfsDatastoreInfo) {
HostVmfsVolume volume = ((VmfsDatastoreInfo) datastore.getInfo()).getVmfs();
addItems(partitions, volume.getExtent());
}
return partitions;
}
/**
* Creates a list from an array of elements (null-safe).
*
* @param array the array, or null.
* @return a list.
*/
protected static <T> List<T> createList(T[] elements) {
if (elements != null) {
return Lists.newArrayList(elements);
}
else {
return Lists.newArrayList();
}
}
/**
* Adds the items to a collection (null-safe).
*
* @param collection the collection to add to.
* @param elements the elements.
*/
protected static <T> void addItems(Collection<T> collection, T[] elements) {
if (elements != null) {
for (T element : elements) {
collection.add(element);
}
}
}
/**
* Adds the items to the collection that are of the correct specific type only (null-safe).
*
* @param collection the collection to add to.
* @param elements the elements
* @param c the specific class that elements must be in order to be added.
*/
protected static <T, V extends T> void addItems(Collection<V> collection, T[] elements,
Class<V> c) {
if (elements != null) {
for (T element : elements) {
if (c.isInstance(element)) {
collection.add((V) element);
}
}
}
}
@Override
public void rescan() throws Exception {
rescanHBAs();
}
}