/* * Copyright (c) 2012-2015 iWave Software LLC * All Rights Reserved */ /** * */ package com.iwave.ext.netapp; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import netapp.manage.NaElement; import org.apache.commons.beanutils.ConvertUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.iwave.ext.netapp.model.CifsAcl; import com.iwave.ext.netapp.model.DiskDetailInfo; import com.iwave.ext.netapp.model.ExportsRuleInfo; import com.iwave.ext.netapp.model.NetAppDevice; import com.iwave.ext.netapp.model.Qtree; import com.iwave.ext.netapp.model.Quota; import com.iwave.ext.netapp.utils.ExportRule; @SuppressWarnings({ "findbugs:WMI_WRONG_MAP_ITERATOR" }) /** * @author sdorcas * All calls from iWO NetApp services must delegate to this class */ public class NetAppFacade { private Logger log = Logger.getLogger(getClass()); Server server = null; String _vFilerName = null; public NetAppFacade(String host, int port, String username, String password, boolean useHTTPS) { this(host, port, username, password, useHTTPS, null); } public NetAppFacade(String host, int port, String username, String password, boolean useHTTPS, String vFilerName) { if (log.isDebugEnabled()) { String vFiler = (vFilerName != null ? vFilerName : ""); log.debug("Connecting to NetApp server: " + host + ":" + port + ":" + vFiler); } _vFilerName = vFilerName; server = new Server(host, port, username, password, useHTTPS, vFilerName, false); } public static NetAppFacade create(Map<String, String> connectionParams) { return new NetAppFacade(connectionParams.get(NetAppDevice.IP_KEY), Integer.parseInt(connectionParams.get(NetAppDevice.PORT_KEY)), connectionParams.get(NetAppDevice.USR_KEY), connectionParams.get(NetAppDevice.PWD_KEY), Boolean.parseBoolean(connectionParams.get(NetAppDevice.SECURE_KEY))); } /***** Aggregate Ops ********/ /** * Returns a list of aggregates. * * @param name - Optional. If provided only the aggregate info for the * the name aggregate is returned. If null or empty all aggregates are * returned. * @return - list of aggregates. */ public List<AggregateInfo> listAggregates(String name) { if (log.isDebugEnabled()) { log.debug("Listing Aggregates. Params [name]: " + name); } Aggregate aggr = new Aggregate(server.getNaServer(), name); boolean listAll = false; if (name == null || name.isEmpty()) { listAll = true; } return aggr.listAllAggregates(listAll); } /***** Initiator Group operations *********/ /** * Creates a new initiator group * * @param name - Name of initiator group * @param type - One of "iscsi", "fcp" * @param type - OS type of initiator group * @throws NetAppException */ public IGroupInfo createIGroup(String name, IGroupType type, LunOSType osType) { if (log.isDebugEnabled()) { log.debug("Creating new IGroup. Params [name,type,os-type]: " + name + "," + type + "," + osType); } IGroup igroup = new IGroup(server.getNaServer(), name); igroup.createIGroup(type, osType); IGroupInfo info = new IGroupInfo(); info.setName(name); info.setType(type); info.setOsType(osType); return info; } /** * Destroys an initiator group. Best practice is to unmap all * LUNs prior to deletion. * * @param name * @param forceDelete * @return success =true/false */ public boolean destroyIGroup(String name, boolean forceDelete) { if (log.isDebugEnabled()) { log.debug("Destroying IGroup. Params [name,force]: " + name + "," + forceDelete); } IGroup igroup = new IGroup(server.getNaServer(), name); return igroup.destroyIGroup(forceDelete); } /** * Add initiator to group * * @param groupName - Initiator Group name * @param initiatorName - Initiator WWN or iSCSI iqn * @throws NetAppException */ public void addInitiatorToIGroup(String groupName, String initiator) { if (log.isDebugEnabled()) { log.debug("Adding initiator to IGroup. Params [groupName,initiator]: " + groupName + "," + initiator); } IGroup igroup = new IGroup(server.getNaServer(), groupName); igroup.addInitiatorToIGroup(initiator); } /** * Remove initiator from group * * @param groupName - Initiator Group name * @param initiatorName - Initiator WWN or iSCSI iqn * @param force - force removal from groups mapped to LUNs * @throws NetAppException */ public void removeInitiatorFromIGroup(String groupName, String initiator, boolean force) { if (log.isDebugEnabled()) { log.debug(String.format("Removing initiator '%s' from group '%s' force=%s", initiator, groupName, force + "")); } IGroup igroup = new IGroup(server.getNaServer(), groupName); igroup.removeInitiatorFromIGroup(initiator, force); } /** * list initiator groups. * * @param groupName - Initiator Group name * @return list of IGroupInfo */ public List<IGroupInfo> listInitiatorGroups(String groupName) { if (log.isDebugEnabled()) { log.debug("Listing initiator groups."); } IGroup igroup = new IGroup(server.getNaServer(), groupName); boolean listAll = false; if (groupName == null || groupName.isEmpty()) { listAll = true; } return igroup.listInitiatorGroups(listAll); } /** * find first group containing specified initiator. * * @param initiator * @return */ public IGroupInfo findIGroup(String initiator) { if (log.isDebugEnabled()) { log.debug("find igroup containing initiator: " + initiator); } IGroup igroup = new IGroup(server.getNaServer(), null); for (IGroupInfo info : igroup.listInitiatorGroups(true)) { if (info.getInitiators().contains(initiator)) { return info; } } return null; } /** * find first group containing exactly the specified initiators. * * @param initiators * @return if not found, returned IGroupInfo.getName() is null and IGroupInfo.getOsType() is set if any of the initiators were found. */ public IGroupInfo findExactGroup(List<String> initiators) { if (log.isDebugEnabled()) { log.debug("find igroup containing all initiators: " + initiators); } IGroupInfo notFound = new IGroupInfo(); notFound.setName(null); IGroup igroup = new IGroup(server.getNaServer(), null); for (IGroupInfo info : igroup.listInitiatorGroups(true)) { ArrayList<String> list = new ArrayList<String>(initiators); for (String initiator : info.getInitiators()) { if (!list.remove(initiator)) { list.add("fail"); } else { notFound.setOsType(info.getOsType()); } } if (list.isEmpty()) { return info; } } return notFound; } /***** LUN ops ************/ /** * Resizes a LUN first taking it offline, performing the resize, and taking in online. * * NOTE: This is the same as resizeLun, however it does NOT change the online state of a Lun * (and thus could fail if the lun is still online) * * @param lunPath - full path to the LUN * @param sizeInBytes - new size of the LUN * @param forceReduce - Forcibly reduce the LUN size. Must be true to reduce the LUN size. * @return size of the altered LUN. Returns -1 if the operation was unsuccessful. */ public long resizeLunOnly(String lunPath, long sizeInBytes, boolean forceReduce) { long actualSize = -1; if (log.isDebugEnabled()) { log.debug("Re-sizing LUN. Params [lunPath,sizeInBytes]: " + lunPath + ", " + sizeInBytes); } Lun lun = new Lun(server.getNaServer(), lunPath); // Resize it actualSize = lun.resizeLun(sizeInBytes, forceReduce); if (log.isDebugEnabled()) { log.debug("LUN resized. New size in bytes = " + actualSize); } return actualSize; } /** * Resizes a LUN first taking it offline, performing the resize, and taking in online. * * @param lunPath - full path to the LUN * @param sizeInBytes - new size of the LUN * @param forceReduce - Forcibly reduce the LUN size. Must be true to reduce the LUN size. * @return size of the altered LUN. Returns -1 if the operation was unsuccessful. */ public long resizeLun(String lunPath, long sizeInBytes, boolean forceReduce) { long actualSize = -1; if (log.isDebugEnabled()) { log.debug("Re-sizing LUN. Params [lunPath,sizeInBytes]: " + lunPath + ", " + sizeInBytes); } Lun lun = new Lun(server.getNaServer(), lunPath); // Take LUN offline lun.setLunOnline(false, false); // Resize it actualSize = lun.resizeLun(sizeInBytes, forceReduce); // Take LUN online lun.setLunOnline(true, false); if (log.isDebugEnabled()) { log.debug("LUN resized. New size in bytes = " + actualSize); } return actualSize; } /** * Sets a LUN online * * @param lunPath - full path to the LUN * @param forceOnline - force the LUN online, bypassing conflict checks * @return - true/false if operation was successful */ public boolean setLunOnline(String lunPath, boolean forceOnline) { if (log.isDebugEnabled()) { log.debug("Setting LUN online. Params [lunPath,forceOnline]: " + lunPath + ", " + forceOnline); } Lun lun = new Lun(server.getNaServer(), lunPath); boolean result = lun.setLunOnline(true, forceOnline); return result; } /** * Sets a LUN offline * * @param lunPath - full path to the LUN * @return - true/false if operation was successful */ public boolean setLunOffline(String lunPath) { if (log.isDebugEnabled()) { log.debug("Setting LUN offline. Params [lunPath]: " + lunPath); } Lun lun = new Lun(server.getNaServer(), lunPath); boolean result = lun.setLunOnline(false, false); return result; } public Lun getLun(String lunPath) { return new Lun(server.getNaServer(), lunPath); } /** * Commissions a new LUN. Creates the LUN, sets a description, and maps the LUN * to a list of initiator groups * * @param lunPath - full Path of the LUN * @param osType - the OS Type for the new LUN * @param sizeInBytes - Size in bytes of the new LUN * @param reserveSpace - true/false to reserve the space * @param description - Optional. Description of the LUN. * @param groupMap - Map of initiator groups to the id LUN will be mapped to. * -1 means auto-assign. on return groupMap is set to the actual Lun ID assigned. * @return - The actual size of the newly created LUN. Value of -1 means it failed. */ public long createLun(String lunPath, LunOSType osType, long sizeInBytes, boolean reserveSpace, String description, Map<String, Integer> groupMap) { if (log.isDebugEnabled()) { StringBuilder sb = new StringBuilder("Creating new LUN. Params [lunPath, " + "osType, sizeInBytes, reserveSpace,description, groupMap]: "); sb.append(lunPath).append(","); sb.append(osType).append(","); sb.append(sizeInBytes).append(","); sb.append(reserveSpace).append(","); sb.append(description).append(","); sb.append(groupMap); log.debug(sb.toString()); } // Create the LUN first Lun lun = new Lun(server.getNaServer(), lunPath); long createdSize = lun.createLunBySize(osType, sizeInBytes, reserveSpace); if (createdSize < 0) { log.error("Commisioning of LUN failed."); return createdSize; // Stop here as the remaing operations will fail. } // Set the description of the lun if provided if (description != null) { lun.setLunDescription(description); } // Now map the LUN to each initiator group in the list for (String group : groupMap.keySet()) { int lunId = groupMap.get(group); int result = lun.mapLun(false, group, lunId); if (result != -1) { groupMap.put(group, result); } else { log.warn("Mapping LUN to initiator group failed. Group: " + group + " id=" + lunId); log.warn("LUN will be deleted."); // Rollback the newly created LUN if it could not be mapped. lun.destroyLun(false); } } return createdSize; } /** * Maps the specified Lun to the InitiatorGroup * * @param lunPath path of Lun to be mapped * @param initiatorGroup Name of initiator Group to be mapped to * @param lunId Lun ID (HLU) of the lun in the initiator group, a value of -1 means the Array will auto assign the lun id * @return The actual lun id that was assigned to this lun */ public int mapLunToInitiatorGroup(String lunPath, String initiatorGroup, int lunId) { Lun lun = new Lun(server.getNaServer(), lunPath); return lun.mapLun(false, initiatorGroup, lunId); } /** * UnMaps the specified Lun from the InitiatorGroup * * @param lunPath path of Lun to be unmapped * @param initiatorGroup Name of initiator Group lun currently mapped to */ public void unmapLunFromInitiatorGroup(String lunPath, String initiatorGroup) { Lun lun = new Lun(server.getNaServer(), lunPath); lun.unmapLun(initiatorGroup); } /** * destroys the LUN. * * @param lunPath - full path to the LUN * @param force - force delete the LUN, even it it is mapped. */ public void deleteLun(String lunPath, boolean force) { if (log.isDebugEnabled()) { log.debug("Deleting LUN. Params [lunPath, force]: " + lunPath + ", " + force); } Lun lun = new Lun(server.getNaServer(), lunPath); lun.destroyLun(force); } /** * Retrieves the lun ID used to identify the mapping of LUN to an initiator group. * A returned value of -1 means an error occured. * * @param lunPath * @param initGroupName * @return */ public int getLunIdFromGroupMapping(String lunPath, String initGroupName) { if (log.isDebugEnabled()) { log.debug("Getting LUN ID from group. Params [lunPath, initGroupName]: " + lunPath + "," + initGroupName); } Lun lun = new Lun(server.getNaServer(), lunPath); return lun.getLunIdForGroup(initGroupName); } /** * Retrieves the lun map used to identify the mapping of LUN to an initiator group. * * @param lunPath * @return */ public Map<String, Integer> getLunMap(String lunPath) { if (log.isDebugEnabled()) { log.debug("Getting LUN Map. Params [lunPath]: " + lunPath); } Lun lun = new Lun(server.getNaServer(), lunPath); return lun.getLunMap(); } /** * List all Luns on the device. If a lun path is specified, only the specified LUN is * returned * * @param lunPath - Optional. If specified only the specified LUN is returned * @return */ public List<LunInfo> listLuns(String lunPath) { if (log.isDebugEnabled()) { log.debug("List LUNs."); } boolean listAll = false; if (lunPath == null || lunPath.isEmpty()) { listAll = true; } Lun lun = new Lun(server.getNaServer(), lunPath); return lun.listLUNs(listAll); } /**** Volume operations *****/ /** * Returns the volumes size as string. * * @param volumeName - Name of the volume. * @return - Size with unit. For example, "100g, 1t, 2048m". */ public String getVolumeSize(String volumeName) { if (log.isDebugEnabled()) { log.debug("Retrieving volume size. Volume: " + volumeName); } Volume vol = new Volume(server.getNaServer(), volumeName); String size = vol.getVolumeSize(); return size; } /** * Takes a volume offline. Note this call does *not* wait for the specified * number of minutes. The delay occurs on the device. * * @param volumeName - name of volume to offline * @param delayInMinutes - number of minutes to wait on the device before * the volume is offline. */ public void setVolumeOffline(String volumeName, int delayInMinutes) { if (log.isDebugEnabled()) { log.debug("Taking volume offline with params[name,delayInMinutes]: " + volumeName + "," + delayInMinutes); } Volume vol = new Volume(server.getNaServer(), volumeName); vol.setVolumeOffline(delayInMinutes); } /** * Creates a new flexible volume, enables and configures SiS. * Only parameters for flexible volumes are provided. * Note the volume may not be operational immediately after this method returns. Use * getVolumeInfo() to query the status of the new volume. * * @param volName - Required. Volume name. * @param containingAggrName - Optional. Name of the aggregate in which to create the volume. Must * be used in conjunction with the size parameter. * @param isSnapLock - true/false to create a SnapLock volume * @param remoteLocation - Optional. Remote host and volume name for the origin of FlexCache. * @param size - Optional. Size (with unit) of the new volume. Ex: 10g, 2000m, 1t. Must be used * in conjunction with containingAggrName. * @param snaplockType - Optional. Type of snaplock volume to be created. * Valid values - "compliance" and "enterprise". * @param spaceReserve - Optional. Type of volume guarantee new volume will use. Valid * values are "none", "file", "volume". * @param enableSis - enables SIS on the new volume. * @param sisSchedule - The SIS schedule in ONTAP format. Example "sat-sun[@0-23]" * @return */ public boolean createFlexibleVolume(String volName, String containingAggrName, boolean isSnapLock, String remoteLocation, String size, String snaplockType, String spaceReserve, boolean enableSis, String sisSchedule) { if (log.isDebugEnabled()) { StringBuilder sb = new StringBuilder("Creating new flexible volume offline with params" + "[volName,aggrName,isSnapLock,remoteLocation,size,snaplockType,spaceReserve," + "enableSis, sisSchedule]:"); sb.append(volName).append(", "); sb.append(containingAggrName).append(", "); sb.append(isSnapLock).append(", "); sb.append(remoteLocation).append(", "); sb.append(size).append(", "); sb.append(snaplockType).append(", "); sb.append(spaceReserve).append(", "); sb.append(enableSis).append(", "); sb.append(sisSchedule); log.debug(sb.toString()); } // First create the volume Volume vol = new Volume(server.getNaServer(), volName); boolean result = vol.createFlexibleVolume(containingAggrName, isSnapLock, remoteLocation, size, snaplockType, spaceReserve); if (!result) { // If the create failed stop here. Subsequent operations will fail return result; } // Otherwise proceed with enabling and configuring SIS if (enableSis) { vol.enableSis(sisSchedule); } return result; } /** * Destroys a volume. * * @param volumeName * @param force * @return */ public boolean destroyVolume(String volumeName, boolean force) { if (log.isDebugEnabled()) { log.debug("Deleting volume with params[name,force]: " + volumeName + "," + force); } Volume vol = new Volume(server.getNaServer(), volumeName); boolean result = vol.destroyVolume(force); return result; } /** * Sets a new size of a volume. * * @param newSize - Size (with unit) of the new volume. Ex: 10g, 2000m, 1t. * * @return - The new size of the volume. */ public String setVolumeSize(String volumeName, String newSize) { Volume vol = new Volume(server.getNaServer(), volumeName); return vol.setVolumeSize(newSize); } /** * Takes a snapshot of the volume. This operation waits for the snapshot to complete on the device. * * @param volumeName - Name of the volume * @param snapshotName - Name of the snapshot * @param isValidLunCloneSnapshot - Optional. True indicates requested by snapvault. * All snapshots for lun clones will be locked. Default is false. * @return - true/false if successful */ public boolean createVolumeSnapshot(String volumeName, String snapshotName, boolean isValidLunCloneSnapshot) { if (log.isDebugEnabled()) { log.debug("Creating snapshot on volume with params[volName,snapshotName,isValidLunCloneSnapshot]: " + volumeName + "," + snapshotName + "," + isValidLunCloneSnapshot); } Volume vol = new Volume(server.getNaServer(), volumeName); // Take a snapshot (synchronous). boolean result = vol.createSnapshot(snapshotName, isValidLunCloneSnapshot, false); return result; } /** * Deletes a snapshot from a volume * * @param volumeName - Name of the volume containing the snapshot * @param snapshotName - Name of the snapshot to be deleted * @return - true/false if the operation was successful. */ public boolean deleteVolumeSnapshot(String volumeName, String snapshotName) { if (log.isDebugEnabled()) { log.debug("Deleting snapshot on volume with params[volName,snapshotName]: " + volumeName + "," + snapshotName); } Volume vol = new Volume(server.getNaServer(), volumeName); boolean result = vol.deleteSnapshot(snapshotName); return result; } /** * Restores a volume to a snapshot. * * @param volumeName - Volume to be restored * @param snapshotName - Snapshot to restore from * @return - true/false if operation was successful */ public boolean restoreVolumeFromSnapshot(String volumeName, String snapshotName) { if (log.isDebugEnabled()) { log.debug("Restoring volume from snapshot with params[volName,snapshotName]: " + volumeName + "," + snapshotName); } Volume vol = new Volume(server.getNaServer(), volumeName); boolean result = vol.restoreVolumeFromSnapshot(snapshotName); return result; } /** * Sets options on a specified volume * * @param volumeName - Name of volume to set options. * @param options - Map(name,value) of options to set. */ public void setVolumeOptions(String volumeName, Map<VolumeOptionType, String> options) { if (options == null) { return; } Volume vol = new Volume(server.getNaServer(), volumeName); StringBuilder optionNV = null; for (Map.Entry<VolumeOptionType, String> e : options.entrySet()) { if (log.isDebugEnabled()) { optionNV = new StringBuilder(); optionNV.append(e.getKey()).append("=").append(e.getValue()); log.debug("Setting option on volume " + volumeName + ". " + optionNV.toString()); } // Set the option vol.setVolumeOption(e.getKey(), e.getValue()); } } /** * Returns the value of a specified volume info attribute * * @param volumeName - Name of the volume * @param attrName - Name of the attribute whose value to return * @return - value of the attribute. */ public String getVolumeInfoAttribute(String volumeName, String attrName) { if (log.isDebugEnabled()) { log.debug("Retrieving volume info attribute[volName,attrName]: " + volumeName + "," + attrName); } Volume vol = new Volume(server.getNaServer(), volumeName); Map<String, String> attrs = vol.getVolumeInfo(true); String attrValue = ""; if (attrs.containsKey(attrName)) { attrValue = attrs.get(attrName); } return attrValue; } public Map<String, String> getVolumeInfoAttributes(String volumeName, boolean verbose) { Volume vol = new Volume(server.getNaServer(), volumeName); return vol.getVolumeInfo(verbose); } /** * Lists all volumes on a Filer. * * @return - list of volumes */ public List<String> listVolumes() { if (log.isDebugEnabled()) { log.debug("List all volumes"); } Volume vol = new Volume(server.getNaServer(), ""); // Vol name is not needed for this List<String> volumes = vol.listVolumes(); return volumes; } /** * Lists all volumes on a Filer. * * @return - list of volumes */ public List<Map<String, String>> listVolumeInfo(String volume, Collection<String> attrs) { if (log.isDebugEnabled()) { log.debug("List all volumes with attributes"); } Volume vol = new Volume(server.getNaServer(), volume); return vol.listVolumeInfo(attrs); } /** * Creates a new CIFS share on the specified volume * * @param mountPath - Path to mount as share * @param shareName - Name of new share * @param comment - Descriptive comment of share * @param maxusers - Optional. Maximum concurrent connections. Use -1 to set this to unlimited. * @param forcegroup - Optional. Name of group to which files created in share belong. * @return */ public boolean addCIFSShare(String mountPath, String shareName, String comment, int maxusers, String forcegroup) { if (log.isDebugEnabled()) { log.debug("Add CIFS share to volume with params[volname,shareName,comment,maxusers]" + mountPath + "," + shareName + "," + comment + "," + maxusers); } FileShare share = new FileShare(server.getNaServer(), mountPath); return share.addCIFSShare(shareName, comment, maxusers, forcegroup); } /** * Deletes a CIFS share, but not the underlying storage * * @param shareName */ public void deleteCIFSShare(String shareName) { if (log.isDebugEnabled()) { log.debug("Delete CIFS share with params[shareName]" + shareName); } FileShare share = new FileShare(server.getNaServer(), ""); share.deleteCIFSShare(shareName); } /** * Lists CIFS Shares. * Most keys in returned Maps are optional. For example, description and maxusers are only returned if they are set. * For exaample: {description=Testing, maxusers=5, share-name=demotest, mount-point=/vol/volscott} * * @param shareName - can contain wildcard * or ? * @return */ public List<Map<String, String>> listCIFSShares(String shareName) { FileShare share = new FileShare(server.getNaServer(), null); return share.listCIFSInfo(shareName); } public void changeCIFSShare(String shareName, Map<String, String> attrs) { FileShare share = new FileShare(server.getNaServer(), null); share.changeCIFSShare(shareName, attrs); } public void changeCIFSShare(String shareName, String attr, String value) { Map<String, String> attrs = Maps.newHashMap(); attrs.put(attr, value); changeCIFSShare(shareName, attrs); } /** * Lists CIFS Access Control Lists. * * @param shareName - can contain wildcard * or ? * @return */ public List<CifsAcl> listCIFSAcls(String shareName) { FileShare share = new FileShare(server.getNaServer(), null); return share.listCIFSAcls(shareName); } /** * set CIFS Access Control List * * @param acl */ public void setCIFSAcl(CifsAcl acl) { FileShare share = new FileShare(server.getNaServer(), null); share.setCIFSAcl(acl); } /** * delete CIFS Access Control List * * @param acl */ public void deleteCIFSAcl(CifsAcl acl) { FileShare share = new FileShare(server.getNaServer(), null); share.deleteCIFSAcl(acl); } /** * Lists NFS Exports. * Keys in returned map are: actual-pathname, anon, nosuid, pathname, read-only, read-write, root, sec-flavor * * NOTE : This method is deprecated as it can fail if an NFS Export has more than one rule {@link #listNFSExportRules(String)} should be * used instead * * @param pathName - only return info about specified path. */ @Deprecated public List<Map<String, String>> listNFSExports(String pathName) { FileShare share = new FileShare(server.getNaServer(), null); return share.listNFSInfo(pathName); } public List<ExportsRuleInfo> listNFSExportRules(String pathName) { FileShare share = new FileShare(server.getNaServer(), null); return share.listNFSExportRules(pathName); } /** * Adds a new NFS share. * * @param mountPath - The mount path * @param exportPath - The exported path of the share. * @param anonymousUid - All hosts with this uid have root access to the directory. Use * -1 to leave 'unspecified' * @param roHosts - List of hosts with read-only access * @param roAddAll - Give all hosts read-only access. If true, roHosts is ignored. * @param rwHosts - List of hosts with read-write access * @param rwAddAll - Give all hosts read-write access. If true, rwHosts is ignored. * @param rootHosts - List of hosts with root access * @param rootAddAll - Give all hosts root access. If true, rootHosts is ignored. * @param securityStyle - List of security styles this share supports. * @return - Returns */ public List<String> addNFSShare(String mountPath, String exportPath, int anonymousUid, List<String> roHosts, boolean roAddAll, List<String> rwHosts, boolean rwAddAll, List<String> rootHosts, boolean rootAddAll, List<NFSSecurityStyle> securityStyle) { FileShare share = new FileShare(server.getNaServer(), mountPath); return share.addNFSShare(exportPath, anonymousUid, roHosts, roAddAll, rwHosts, rwAddAll, rootHosts, rootAddAll, securityStyle); } /** * Deletes a named NFS mounted share. As a convenience this function can also delete all * NFS shares. * * @param mountPath - Path of share to delete * @param deleteAll - If true *ALL* mounted NFS shares will be removed. Be careful! * @return - Returns a list of deleted paths. */ public List<String> deleteNFSShare(String mountPath, boolean deleteAll) { FileShare share = new FileShare(server.getNaServer(), mountPath); return share.deleteNFSShare(deleteAll); } /** * get list of FC WWNs . * * @param verbose - if true, unused port names are also listed * @return */ public List<Map<String, String>> listWWNs(boolean verbose) { NaElement elem = new NaElement("fcp-port-name-list-info"); elem.addNewChild("verbose", Boolean.toString(verbose)); try { List<Map<String, String>> list = Lists.newArrayList(); NaElement result = server.getNaServer().invokeElem(elem); for (NaElement portElem : (List<NaElement>) result.getChildByName("fcp-port-names").getChildren()) { Map<String, String> port = Maps.newHashMap(); for (NaElement portChild : (List<NaElement>) portElem.getChildren()) { port.put(portChild.getName(), portChild.getContent()); } list.add(port); } return list; } catch (Exception e) { String msg = "Failed to get fcp port names"; log.error(msg, e); throw new NetAppException(msg, e); } } /** * get list of iSCSI interfaces . * * @return */ public List<Map<String, String>> listIscsiInterfaceInfo(String interfaceName) { NaElement elem = new NaElement("iscsi-interface-list-info"); if (StringUtils.isNotBlank(interfaceName)) { elem.addNewChild("interface-name", interfaceName); } try { NaElement result = server.getNaServer().invokeElem(elem); List<Map<String, String>> iscsiInterfaceInfos = Lists.newArrayList(); for (NaElement entry : (List<NaElement>) result.getChildByName("iscsi-interface-list-entries").getChildren()) { Map<String, String> iscsiInterfaceInfo = Maps.newHashMap(); for (NaElement child : (List<NaElement>) entry.getChildren()) { String name = child.getName(); String value = child.getContent(); iscsiInterfaceInfo.put(name, value); } iscsiInterfaceInfos.add(iscsiInterfaceInfo); } return iscsiInterfaceInfos; } catch (Exception e) { String msg = "Failed to get iscsi interfaces"; log.error(msg, e); throw new NetAppException(msg, e); } } // /** * get list of iSCSI initiator * * @return */ public List<Map<String, String>> listIscsiInitiatorInfo() { NaElement elem = new NaElement("iscsi-initiator-list-info"); try { NaElement result = server.getNaServer().invokeElem(elem); List<Map<String, String>> iscsiInterfaceInfos = Lists.newArrayList(); for (NaElement entry : (List<NaElement>) result.getChildByName("iscsi-initiator-list-entries").getChildren()) { Map<String, String> iscsiInterfaceInfo = Maps.newHashMap(); for (NaElement child : (List<NaElement>) entry.getChildren()) { String name = child.getName(); String value = child.getContent(); iscsiInterfaceInfo.put(name, value); } iscsiInterfaceInfos.add(iscsiInterfaceInfo); } return iscsiInterfaceInfos; } catch (Exception e) { String msg = "Failed to get iscsi initiators"; log.error(msg, e); throw new NetAppException(msg, e); } } /** * get list of iSCSI initiator * * @return */ public List<Map<String, String>> listIscsiPortalInfo() { NaElement elem = new NaElement("iscsi-portal-list-info"); try { NaElement result = server.getNaServer().invokeElem(elem); List<Map<String, String>> iscsiPortalInfos = Lists.newArrayList(); for (NaElement entry : (List<NaElement>) result.getChildByName("iscsi-portal-list-entries").getChildren()) { Map<String, String> iscsiPortal = Maps.newHashMap(); for (NaElement child : (List<NaElement>) entry.getChildren()) { String name = child.getName(); String value = child.getContent(); iscsiPortal.put(name, value); } iscsiPortalInfos.add(iscsiPortal); } return iscsiPortalInfos; } catch (Exception e) { String msg = "Failed to get iscsi portals"; log.error(msg, e); throw new NetAppException(msg, e); } } /** * Get FC Node Name * * @return Node Name */ public String getFcWWNN() { String nodeName = null; NaElement result = server.invoke("fcp-node-get-name"); if (result != null) { nodeName = result.getChildContent("node-name"); } return nodeName; } /** * */ public List<DiskDetailInfo> listDiskInfo(String disk, String ownershipType) { List<DiskDetailInfo> disks = new ArrayList<DiskDetailInfo>(); NaElement input = new NaElement("disk-list-info"); if (StringUtils.isNotBlank(disk)) { input.addNewChild("disk", disk); } if (StringUtils.isNotBlank(ownershipType)) { input.addNewChild("ownership-type", ownershipType); } NaElement result = server.invoke(input); if (result != null) { NaElement diskDetails = result.getChildByName("disk-details"); if (diskDetails != null) { for (NaElement diskDetailElem : (List<NaElement>) diskDetails.getChildren()) { if (diskDetailElem != null) { DiskDetailInfo diskDetailInfo = new DiskDetailInfo(); diskDetailInfo.setAggregate(diskDetailElem.getChildContent("aggregate")); diskDetailInfo.setDiskModel(diskDetailElem.getChildContent("disk-model")); diskDetailInfo.setDiskType(diskDetailElem.getChildContent("disk-type")); diskDetailInfo.setDiskUid(diskDetailElem.getChildContent("disk-uid")); diskDetailInfo.setName(diskDetailElem.getChildContent("name")); diskDetailInfo.setPool(diskDetailElem.getChildContent("pool")); diskDetailInfo.setRaidGroup(diskDetailElem.getChildContent("raid-group")); diskDetailInfo.setRaidState(diskDetailElem.getChildContent("raid-state")); diskDetailInfo.setRaidType(diskDetailElem.getChildContent("raid-type")); diskDetailInfo.setRpm((Integer) ConvertUtils.convert(diskDetailElem.getChildContent("rpm"), Integer.class)); diskDetailInfo.setPhysicalSpace((Long) ConvertUtils.convert(diskDetailElem.getChildContent("physical-space"), Long.class)); disks.add(diskDetailInfo); } } } } return disks; } /** * @return A list of specific CIFS configuration values */ public Map<String, String> listCIFSConfig() { NaElement elem = new NaElement("cifs-list-config"); Map<String, String> properties = Maps.newHashMap(); try { NaElement result = server.getNaServer().invokeElem(elem); properties.put("NetBIOS-domainName", result.getChildContent("NetBIOS-domainname")); properties.put("DNS-domainName", result.getChildContent("DNS-domainname")); properties.put("NetBIOS-servername", result.getChildContent("NetBIOS-servername")); if (result.getChildByName("DC-connection") != null) { properties.put("DC-Address", result.getChildByName("DC-connection") .getChildByName("connection-info") .getChildByName("favored-address") .getChildByName("address-info") .getChildContent("ip-address")); } else if (result.getChildByName("LDAP-connection") != null) { properties.put("DC-Address", result.getChildByName("LDAP-connection") .getChildByName("connection-info") .getChildByName("favored-address") .getChildByName("address-info") .getChildContent("ip-address")); } } catch (Exception e) { String msg = "Failed to get array system info"; log.error(msg, e); throw new NetAppException(msg, e); } return properties; } /** * get array system-info. * * @return map of name/values as returned from system-get-info API */ public Map<String, String> systemInfo() { HashMap<String, String> info = new HashMap<String, String>(); NaElement elem = new NaElement("system-get-info"); NaElement result = null; /* * For example: {partner-system-id=0142226671, board-speed=1666, system-name=iWaveTST0, * cpu-serial-number=8006251, system-serial-number=700000567389, memory-size=4096, * number-of-processors=2, system-id=0142223979, partner-system-name=iWaveTST1, * system-revision=B0, controller-address=A, vendor-id=NetApp, system-machine-type=FAS2040, * system-model=FAS2040, board-type=System Board XVII, cpu-processor-id=0x6ec, cpu-part-number=110-00133, * supports-raid-array=false, cpu-revision=A4, cpu-firmware-release=6.1, cpu-microcode-version=85} */ try { result = server.getNaServer().invokeElem(elem).getChildByName("system-info"); for (NaElement child : (List<NaElement>) result.getChildren()) { String name = child.getName(); info.put(name, child.getContent()); } return info; } catch (Exception e) { String msg = "Failed to get array system info"; log.error(msg, e); throw new NetAppException(msg, e); } } /** * get array system-info. * * @return map of name/values as returned from system-get-info API */ public Map<String, String> systemVersion() { HashMap<String, String> info = new HashMap<String, String>(); NaElement elem = new NaElement("system-get-version"); NaElement result = null; try { result = server.getNaServer().invokeElem(elem).getChildByName("version"); if (result != null) { String name = result.getName(); info.put(name, result.getContent()); } result = server.getNaServer().invokeElem(elem).getChildByName("is-clustered"); if (result != null) { String name = result.getName(); info.put(name, result.getContent()); } return info; } catch (Exception e) { String msg = "Failed to get array system version " + e.getMessage(); log.error(msg, e); throw new NetAppException(msg, e); } } /** * get iSCSI target node name. * * @return */ public String getNodeName() { NaElement elem = new NaElement("iscsi-node-get-name"); try { NaElement result = server.getNaServer().invokeElem(elem); return result.getChildContent("node-name"); } catch (Exception e) { String msg = "Failed to get iSCSI node name"; log.error(msg, e); throw new NetAppException(msg, e); } } /** * get netbios aliases. * * @return */ public List<String> getNetbiosAliases() { NaElement elem = new NaElement("cifs-nbalias-names-get"); List<String> names = Lists.newArrayList(); try { NaElement result = server.getNaServer().invokeElem(elem).getChildByName("nbalias-names"); if (result != null) { for (NaElement name : (List<NaElement>) result.getChildren()) { names.add(name.getContent()); } } return names; } catch (Exception e) { String msg = "Failed to get netbios aliases"; log.error(msg, e); throw new NetAppException(msg, e); } } /** * Sets the security style of a QTree * * @param path full path of the QTree (i.e. /vol/MyVolume/MyTree) * @param type either ntfs, unix, mixed */ public void setQTreeSecurityStyle(String path, String type) { String output = invokeCliCommand(new String[] { "qtree", "security", path, type }); // Either blank, or a Quota warning message, means we're successful if (!StringUtils.isBlank(output) && !output.startsWith("qtree: Changing the security style")) { throw new NetAppException(output); } } public void setQTreeOplocks(String qtreePath, String oplocks) { String infoString = "NetAppFacade::setQTreeOplocks -> Trying to set oplocks = " + oplocks + " on qtree = " + qtreePath; log.info(infoString); NaElement elem = new NaElement("system-cli"); NaElement argsarray = new NaElement("args"); argsarray.addChildElem(new NaElement("arg", "qtree")); argsarray.addChildElem(new NaElement("arg", "oplocks")); argsarray.addChildElem(new NaElement("arg", qtreePath)); argsarray.addChildElem(new NaElement("arg", oplocks)); elem.addChildElem(argsarray); try { server.getNaServer().invokeElem(elem); } catch (Exception e) { String msg = "NetAppFacade::setQTreeOplocks -> Failed to invoke CLI command "; log.error(msg, e); throw new NetAppException(msg, e); } } /** * Invokes a CLI command through the API * * @param args * @return */ public String invokeCliCommand(String args[]) { String cliResult; NaElement elem = new NaElement("system-cli"); NaElement argsarray = new NaElement("args"); for (int i = 0; i < args.length; i++) { argsarray.addNewChild("arg", args[i]); } elem.addChildElem(argsarray); // Call the NetApp API try { NaElement result = server.getNaServer().invokeElem(elem); cliResult = result.getChildContent("cli-output"); return cliResult; } catch (Exception e) { String msg = "Failed to invoke CLI command "; log.error(msg, e); throw new NetAppException(msg, e); } } public List<Quota> listQuotas() { return listQuotas(null, null); } public List<Quota> listQuotasByPath(String path) { return listQuotas(path, null); } public List<Quota> listQuotasByVolume(String volume) { return listQuotas(null, volume); } public List<Quota> listQuotas(String path, String volume) { if (log.isDebugEnabled()) { log.debug("Retrieving quotas"); } QuotaCommands quotaCommands = new QuotaCommands(this.server.getNaServer()); return quotaCommands.quotaReport(path, volume); } public List<Qtree> listQtrees() { return listQtrees(null); } public List<Qtree> listQtrees(String volume) { if (log.isDebugEnabled()) { log.debug("Retrieving qtrees"); } QtreeCommands qtreeCommands = new QtreeCommands(this.server.getNaServer()); return qtreeCommands.listQtree(volume); } /** * Creates a Qtree rooted in the specified volume. * * @param qtree the Qtree name. * @param volume the volume name. */ public void createQtree(String qtree, String volume) { if (log.isDebugEnabled()) { log.debug("Creating Qtree " + qtree + " in volume " + volume); } QtreeCommands commands = new QtreeCommands(server.getNaServer()); commands.createQtree(qtree, volume); } /** * Deletes the qtree at the given path (/vol/<volume>/<qtree>) * * @param path the qtree path. * @param force whether to force deletion even if the qtree is not empty. */ public void deleteQtree(String path, boolean force) { if (log.isDebugEnabled()) { log.debug("Deleting Qtree " + path); } QtreeCommands commands = new QtreeCommands(server.getNaServer()); commands.deleteQtree(path, force); } /** * Creates a Qtree rooted in the specified volume. * * @param qtree the Qtree name. * @param volume the volume name. * @param mode the permissions on the qtree (similar to unix file permissions, 0755 for example) */ public void createQtree(String qtree, String volume, String mode) { if (log.isDebugEnabled()) { log.debug("Creating Qtree " + qtree + " in volume " + volume + " [mode=" + mode + "]"); } QtreeCommands commands = new QtreeCommands(server.getNaServer()); commands.createQtree(qtree, volume, mode); } /** * Gets a tree quota for the given volume and path. * * @param volume the volume name. * @param path the path for the quota. * @return the quota. */ public Quota getQuota(String volume, String quotaTarget, String quotaType, String qtree) { if (log.isDebugEnabled()) { log.debug("Getting " + quotaType + " quota for volume " + volume + ", quotaTarget " + quotaTarget); } QuotaCommands commands = new QuotaCommands(server.getNaServer()); return commands.getQuota(volume, quotaTarget, quotaType, qtree); } /** * Gets a tree quota for the given volume and path. * * @param volume the volume name or volume path. * @param path the path for the quota. * @return the quota. */ public Quota getTreeQuota(String volume, String path) { if (log.isDebugEnabled()) { log.debug("Getting tree quota for volume " + volume + ", path " + path); } QuotaCommands commands = new QuotaCommands(server.getNaServer()); return commands.getTreeQuota(volume, path); } /** * Sets a disk-limit tree quota. If the tree quota doesn't already exist, it is created. The * volume can be specified as a name only, or as the volume path (/vol/<volume-name>). The disk * limit and threshold values are specified in KB. * * @param volume the volume name or volume path containing the path to apply quota. * @param path the path which will have a disk limit applied. * @param diskLimitInKB the disk limit in KB. * @param thresholdInKB the threshold in KB after which a message will be logged. The threshold * is only set if it is greater than 0. */ public void setDiskLimitTreeQuota(String volume, String path, long diskLimitInKB, long thresholdInKB) { if (log.isDebugEnabled()) { log.debug("Setting disk limit tree quota of " + diskLimitInKB + " KB to " + path); } QuotaCommands commands = new QuotaCommands(server.getNaServer()); commands.setDiskLimitTreeQuota(volume, path, diskLimitInKB, thresholdInKB); } /** * Addss a disk-limit tree quota. The volume can be specified as a name only, * or as the volume path (/vol/<volume-name>). The disk limit and threshold values are specified * in KB. * * @param volume the volume name or volume path containing the path to apply quota. * @param path the path which will have a disk limit applied. * @param diskLimitInKB the disk limit in KB. * @param thresholdInKB the threshold in KB after which a message will be logged. The threshold * is only set if it is greater than 0. */ public void addDiskLimitTreeQuota(String volume, String path, long diskLimitInKB, long thresholdInKB) { if (log.isDebugEnabled()) { log.debug("Setting disk limit tree quota of " + diskLimitInKB + " KB to " + path); } QuotaCommands commands = new QuotaCommands(server.getNaServer()); commands.addDiskLimitTreeQuota(volume, path, diskLimitInKB, thresholdInKB); } public void modifyDiskLimitTreeQuota(String volume, String path, long diskLimitInKB, long thresholdInKB) { if (log.isDebugEnabled()) { log.debug("Modifying disk limit tree quota of " + diskLimitInKB + " KB to " + path); } QuotaCommands commands = new QuotaCommands(server.getNaServer()); commands.modifyDiskLimitTreeQuota(volume, path, diskLimitInKB, thresholdInKB); } public void deleteQuota(String volume, String quotaTarget, String quotaType, String qtree) { if (log.isDebugEnabled()) { log.debug("Deleting " + quotaType + " quota on " + quotaTarget); } QuotaCommands commands = new QuotaCommands(server.getNaServer()); commands.deleteQuota(volume, quotaTarget, quotaType, qtree); } public void deleteTreeQuota(String volume, String path) { if (log.isDebugEnabled()) { log.debug("Deleting tree quota for " + path); } QuotaCommands commands = new QuotaCommands(server.getNaServer()); commands.deleteTreeQuota(volume, path); } /** * Returns the current status of Quotas on the specified volume */ public QuotaCommands.QuotaStatus getQuotaStatus(String volume) { QuotaCommands commands = new QuotaCommands(server.getNaServer()); return commands.getQuotaStatus(volume); } /** * Starts a Resize Quota operation on the specified volume. * * This only starts the resize operation and returns immediately, {@link #getQuotaStatus(String)} should be used * to find out when the current status of the operation */ public void startQuotaResize(String volume) { QuotaCommands commands = new QuotaCommands(server.getNaServer()); commands.startResize(volume); } /** * Starts to turn quotas on for a volume. A successful return from this API does not mean that quotas are on, * merely that an attempt to start it has been triggered */ public void turnQuotaOn(String volume) { QuotaCommands commands = new QuotaCommands(server.getNaServer()); commands.turnQuotaOn(volume); } /** * Turns the quota subsystem off for a volume */ public void turnQuotaOff(String volume) { QuotaCommands commands = new QuotaCommands(server.getNaServer()); commands.turnQuotaOff(volume); } /** * Reinitialize quota subsystem off for a volume */ public void reintializeQuota(String volume) { QuotaCommands commands = new QuotaCommands(server.getNaServer()); commands.turnQuotaOff(volume); commands.turnQuotaOn(volume); } /** * List of snapshots for a volume * * @param volumeName - Name of the volume containing the snapshots * @return - Collection containing snapshots . */ public Collection<String> listSnapshots(String volumeName) { if (log.isDebugEnabled()) { log.debug("Listing snapshots on volume with params[volName]: " + volumeName); } Volume vol = new Volume(server.getNaServer(), volumeName); Collection<String> attrs = new ArrayList<String>(); attrs.add("name"); return vol.listSnapshots(attrs); } public List<VFilerInfo> listVFilers() { if (log.isDebugEnabled()) { log.debug("Listing vFilers"); } VFiler vFiler = new VFiler(server.getNaServer(), null); return vFiler.listVFilers(true); } public boolean addStorage(String storagePath, String vFilerName) { if (log.isDebugEnabled()) { log.debug("Adding storage to vfiler"); } VFiler vFiler = new VFiler(server.getNaServer(), null); return vFiler.addStorage(storagePath, vFilerName); } /** * Adds a new NFS share. * * @param mountPath - The mount path * @param exportPath - The exported path of the share. * @param anonymousUid - All hosts with this uid have root access to the directory. Use * -1 to leave 'unspecified' * @param roHosts - List of hosts with read-only access * @param roAddAll - Give all hosts read-only access. If true, roHosts is ignored. * @param rwHosts - List of hosts with read-write access * @param rwAddAll - Give all hosts read-write access. If true, rwHosts is ignored. * @param rootHosts - List of hosts with root access * @param rootAddAll - Give all hosts root access. If true, rootHosts is ignored. * @param securityStyle - List of security styles this share supports. * @return - Returns */ public List<String> addNewNFSShare(String exportPath, List<ExportRule> exportRules) { FileShare share = new FileShare(server.getNaServer(), exportPath); return share.addNewNFSShare(exportPath, exportRules); } public List<String> modifyNFSShare(String exportPath, List<ExportRule> exportRules) { FileShare share = new FileShare(server.getNaServer(), exportPath); return share.modifyNFSShare(exportPath, exportRules); } }