#region Copyright /* * Copyright © 2014-2016 NetApp, Inc. All Rights Reserved. * * CONFIDENTIALITY NOTICE: THIS SOFTWARE CONTAINS CONFIDENTIAL INFORMATION OF * NETAPP, INC. USE, DISCLOSURE OR REPRODUCTION IS PROHIBITED WITHOUT THE PRIOR * EXPRESS WRITTEN PERMISSION OF NETAPP, INC. */ #endregion #region Using Directives using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Management.Automation; using System.Security; using System.Text; using SolidFire.Core.Objects; using SolidFire.Exceptions; #endregion namespace SolidFire.Core.Helpers { /// /// public static class SolidFireUtilities { private static SessionState _sessionState; /// /// Enum used to identify the type of endpoint a connection is attempting to use. /// public enum SFEndPoint { /// /// The endpoint is a cluster. /// Cluster = 1, /// /// The endpoint is a node. /// Node = 2, /// /// The endpoint is either node or cluster /// Both = 3 }; public static bool _testMode = false; /// /// Static member that points to the Powershell SesionState. /// public static SessionState SessionState { get { if (_sessionState == null) { if (_testMode) { return null; } throw new Exception("No SFConnections are available. Call Connect-SFCluster before attempting any other commands."); } return _sessionState; } set { _sessionState = _sessionState ?? value; } } public static bool LogRequests { get { var psVariable = SessionState.PSVariable.Get("SFLogRequests"); if (psVariable != null) { return (bool)psVariable.Value; } return false; } set { var objPsVariable = new PSVariable("SFLogRequests", value, ScopedItemOptions.AllScope); SessionState.PSVariable.Set(objPsVariable); } } public static bool LogResponses { get { var psVariable = SessionState.PSVariable.Get("SFLogResponses"); if (psVariable != null) { return (bool)psVariable.Value; } return false; } set { var objPsVariable = new PSVariable("SFLogResponses", value, ScopedItemOptions.AllScope); SessionState.PSVariable.Set(objPsVariable); } } /// /// Static member that holds the current connection object. /// public static SFConnection SFConnection { get { var psVariable = SessionState.PSVariable.Get("SFConnection"); if (psVariable != null) { return (SFConnection)psVariable.Value; } return null; } set { var objPsVariable = new PSVariable("SFConnection", value, ScopedItemOptions.AllScope); SessionState.PSVariable.Set(objPsVariable); } } /// /// Static member that holds the list of connection objects. /// public static List SFConnections { get { var psVariable = SessionState.PSVariable.Get("SFConnections"); if (psVariable != null) { return (List)psVariable.Value; } else { return new List(); } } set { var objPsVariable = new PSVariable("SFConnections", value, ScopedItemOptions.AllScope); SessionState.PSVariable.Set(objPsVariable); } } public static SFConnection GetSFConnection(Cmdlet instance, string name) { const WildcardOptions options = WildcardOptions.IgnoreCase | WildcardOptions.Compiled; var wildcard = new WildcardPattern(name, options); var nameMatchedConn = SFConnections.FirstOrDefault(c => wildcard.IsMatch(c.Name)); if (nameMatchedConn == null) { var targetMatchedConn = SFConnections.FirstOrDefault(c => wildcard.IsMatch(c.Target)); if (targetMatchedConn == null) { var errorRecord = new ErrorRecord(new Exception("Unable to find SFConnection with Name or Target/IP like '" + name + "'."), "ConnectionNameNotFound", ErrorCategory.ObjectNotFound, null); HandleError(errorRecord, instance, true); } else { return targetMatchedConn; } } return nameMatchedConn; } /// /// Helper method to build a SolidFire endpoint API url string. /// /// IP address of machine name of the cluster or node /// Version of the API, for example 7.0 /// Indicate if the address is for node or a cluster (default). This parameter is overridden if port is specified. /// If specified, this will be set as the port in the resulting url. /// public static string BuildUrl(string address, VersionApi version, bool node = false, int? port = null) { if (port.HasValue) { return _buildUrl(address, version, port.Value); } if (node) { return _buildUrl(address, version, 442); } return _buildUrl(address, version, null); } public static string _buildUrl(string address, VersionApi version, int? port) { string versionNumber = version.Number.ToString("F1", CultureInfo.InvariantCulture); return port.HasValue ? string.Format("https://{0}:{2}/json-rpc/{1}", address, versionNumber, port.Value) : string.Format("https://{0}/json-rpc/{1}", address, versionNumber); } /// /// Checks to see if a connection is established and is targeting the correct version and type of endpoint. /// /// The instance of the cmdlet processing the check /// Specify the type of endpoint the current connection must be for the cmdlet /// The connection must greater than or equal to the version specified /// The connection must less than or equal to the version specified /// Throw a terminating error if the connetion is not in the correct state /// public static bool CheckConnection(Cmdlet instance, float minVersionNumber = SolidFireVersionApi.MinVersionApiNumber, SFEndPoint endPoint = SFEndPoint.Cluster, float maxVersionNumber = SolidFireVersionApi.MinVersionApiNumber, bool throwTerminatingError = true, SFConnection connection = null) { bool retval = true; ErrorRecord errorRecord = null; if (connection == null) { connection = SFConnection; } if (connection == null ) { errorRecord = new ErrorRecord( new PSInvalidOperationException("You are not currently connected. A connection is required in order to use the cmdlet."), "ConnectionNotFound", ErrorCategory.OpenError, null); } else if (connection.Element.GetConnectionVersion() < minVersionNumber) { errorRecord = new ErrorRecord(new PSInvalidOperationException(string.Format("The API version you are connected with ({0:N1}) is too low to support this cmdlet. Please connect to your SF cluster using {1:N1} or higher. You can do this by specifying the -VersionApi parameter when using Connect-SFCluster. For more information, type Get-Help Connect-SFCluster.", connection.VersionApiNumber, minVersionNumber)), "VersionApiTooLow", ErrorCategory.InvalidOperation, null); } else if (connection.Node && (SFEndPoint.Node & endPoint) != SFEndPoint.Node) { errorRecord = new ErrorRecord(new PSInvalidOperationException("The API call you are making is not supported for a node. Please connect to a cluster and try again."), "InvalidEndpoint", ErrorCategory.InvalidOperation, null); } else if (!connection.Node && (SFEndPoint.Cluster & endPoint) != SFEndPoint.Cluster) { errorRecord = new ErrorRecord(new PSInvalidOperationException("The API call you are making is not supported for a cluster. Please connect to a node and try again."), "InvalidEndpoint", ErrorCategory.InvalidOperation, null); } // // Check to see if there was an error checking the connection and handle accordingly. // if (errorRecord != null) { retval = false; HandleError(errorRecord, instance, throwTerminatingError); } return (retval); } /// /// Checks to see if there was any error in the webrequest response and throws a terminating error if there is one by default, unless the throwTerminatingError parameter is specified as false. /// /// /// /// /// public static bool HasAPIError(SFError input, Cmdlet instance, bool throwTerminatingError = true) { if (input == null) return false; // error found in response var errDetails = new ErrorDetails(input.Name + ": " + input.Message); var errRecord = new ErrorRecord(new Exception(errDetails.Message), input.Code.ToString(), ErrorCategory.InvalidResult, instance) { ErrorDetails = errDetails }; HandleError(errRecord, instance, throwTerminatingError); return true; } public static void HandleError(ErrorRecord input, Cmdlet instance, bool throwTerminatingError = true) { if (throwTerminatingError) // TODO: Need to look for a global parameter that might override the local one { instance.ThrowTerminatingError(input); } else { instance.WriteError(input); } } /// /// Checks to see if there was any error in the webrequest response returns true for error found, false for no error. Does not throw any warnings or errors to console. /// /// /// /// public static bool CheckForErrorNoOutput(SFError input, Cmdlet instance) { if (input == null) return false; // error found in response var errDetails = new ErrorDetails(input.Name + ": " + input.Message); var errRecord = new ErrorRecord(new Exception(), input.Code.ToString(), ErrorCategory.InvalidResult, instance) { ErrorDetails = errDetails }; return true; } /// /// Converts a String to a SecureString /// /// /// public static SecureString ConvertToSecureString(this String strPassWord) { SecureString objSecureString = new SecureString(); char[] passwordChars = strPassWord.ToCharArray(); foreach(char c in strPassWord.ToCharArray()) { objSecureString.AppendChar(c); } objSecureString.MakeReadOnly(); return objSecureString; } /// /// Create a new SFConnection from some basic information. /// /// /// /// /// /// optional /// optional /// The new SFConnection public static SFConnection CreateNewConnection(PSCredential credential, string target, bool node, VersionApi apiVersion, int? port = null, int? timeout = null) { return new SFConnection(credential, target, node, apiVersion, port, timeout); } /// /// /// SolidFire ASCII Art Logo public static String SolidFireASCIIArt() { var art = ""; art += " 77 \n"; art += " 7777 \n"; art += " 77 \n"; art += " == \n"; art += " 77IIIIIIIIIIIIIIIIII777 \n"; art += " =7 7= \n"; art += " 7 7 \n"; art += " =7 7= \n"; art += " =7 7= \n"; art += " =77 7777777777777777777 77= \n"; art += " 7777 777777777777777777777 7777 \n"; art += " 7777 7777777777777777777 7777 \n"; art += " =77 77= \n"; art += " =7 7= \n"; art += " 7 7 \n"; art += " 7= =7 \n"; art += " 77= =77 \n"; art += " =7777777777777777777= \n"; art += " \n"; art += " ====IIIIIIIIII===== \n"; art += " =77777= =77777= \n"; art += " =777= =777= \n"; art += " =777= =777=\n"; art += " Fueled By NetApp SolidFire \n"; art += " \n"; return art; } public static void RemoveSFConnections(List connectionsToRemove) { foreach (var sfcn in connectionsToRemove) { // Set the remaining SFConnections to the current list minus the connectionToRemove SFConnections.Remove(sfcn); // Get the current SFConnection object and remove if it matches // the connection that was just removed from the list of connections. if (SFConnection == sfcn) { SFConnection = SFConnections.LastOrDefault(); } } SFConnections = SFConnections; } } }