#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;
}
}
}