From ef60002d9dd2149f4490367d961c199e797138f3 Mon Sep 17 00:00:00 2001 From: Sankaranarayanan Mahadevan Date: Mon, 30 Mar 2015 16:54:02 +0530 Subject: [PATCH 1/9] fixing 404 response message --- .../StorSimpleCmdletBase.cs | 921 +++++++++--------- 1 file changed, 470 insertions(+), 451 deletions(-) diff --git a/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs b/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs index ce9d9fe02b84..50125357ca61 100644 --- a/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs +++ b/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs @@ -28,456 +28,475 @@ namespace Microsoft.WindowsAzure.Commands.StorSimple { - public class StorSimpleCmdletBase : AzurePSCmdlet - { - //this property will determine whether before running the actual commandlet logic, should resource selection be verified - protected bool verifyResourceBeforeCmdletExecute; - - /// - /// default constructor for most commandlets. In this case, Resource check will be verified - /// - public StorSimpleCmdletBase() : this(true) { } - - /// - /// constructor variant if you want to suppress the resource check for your commandlet - /// - /// - public StorSimpleCmdletBase(bool performResourceCheck):base() - { - verifyResourceBeforeCmdletExecute = performResourceCheck; - } - - private StorSimpleClient storSimpleClient; - - internal StorSimpleClient StorSimpleClient - { - get - { - if (this.storSimpleClient == null) - { - this.storSimpleClient = new StorSimpleClient(Profile, Profile.Context.Subscription); - } - storSimpleClient.ClientRequestId = Guid.NewGuid().ToString("D") + "_PS"; - WriteVerbose(string.Format(Resources.ClientRequestIdMessage, storSimpleClient.ClientRequestId)); - return this.storSimpleClient; - } - } - - internal virtual void HandleAsyncTaskResponse(AzureOperationResponse opResponse, string operationName) - { - string msg = string.Empty; - - if (opResponse.StatusCode != HttpStatusCode.Accepted && opResponse.StatusCode != HttpStatusCode.OK) - { - msg = string.Format(Resources.FailureMessageSubmitTask, operationName); - } - - else - { - if (opResponse.GetType().Equals(typeof(TaskResponse))) - { - var taskResponse = opResponse as TaskResponse; - msg = string.Format(Resources.SuccessMessageSubmitTask, operationName, taskResponse.TaskId); - WriteObject(taskResponse.TaskId); - } - - else if (opResponse.GetType().Equals(typeof(GuidTaskResponse))) - { - var guidTaskResponse = opResponse as GuidTaskResponse; - msg = string.Format(Resources.SuccessMessageSubmitTask, operationName, guidTaskResponse.TaskId); - WriteObject(guidTaskResponse.TaskId); - } - } - - WriteVerbose(msg); - } - - internal virtual void HandleDeviceJobResponse(JobResponse jobResponse, string operationName) - { - string msg = string.Format(Resources.SuccessMessageSubmitDeviceJob, operationName, jobResponse.JobId); - WriteObject(jobResponse.JobId); - WriteVerbose(msg); - } - - internal virtual void HandleSyncTaskResponse(TaskStatusInfo taskStatus, string operationName) - { - string msg = string.Empty; - TaskReport taskReport = new TaskReport(taskStatus); - - if (taskStatus.AsyncTaskAggregatedResult != AsyncTaskAggregatedResult.Succeeded) - { - msg = string.Format(Resources.FailureMessageCompleteJob, operationName); - WriteObject(taskReport); - } - - else - { - msg = string.Format(Resources.SuccessMessageCompleteJob, operationName); - WriteObject(taskReport); - } - - WriteVerbose(msg); - } - - private static void StripNamespaces(XDocument doc) - { - var elements = doc.Descendants(); - elements.Attributes().Where(attr => attr.IsNamespaceDeclaration).Remove(); - foreach (var element in elements) - { - element.Name = element.Name.LocalName; - } - } - - internal virtual void HandleException(Exception exception) - { - ErrorRecord errorRecord = null; - var ex = exception; - do - { - Type exType = ex.GetType(); - if(exType == typeof(CloudException)) - { - var cloudEx = ex as CloudException; - if (cloudEx == null) - break; - var response = cloudEx.Response; - try - { - XDocument xDoc = XDocument.Parse(response.Content); - StripNamespaces(xDoc); - string cloudErrorCode = xDoc.Descendants("ErrorCode").FirstOrDefault().Value; - WriteVerbose(string.Format(Resources.CloudExceptionMessage, cloudErrorCode)); - } - catch (Exception) - { - - } - - errorRecord = new ErrorRecord(cloudEx, string.Empty, ErrorCategory.InvalidOperation, null); - break; - } - else if(exType == typeof(WebException)) - { - var webEx = ex as WebException; - if (webEx == null) - break; - try - { - HttpWebResponse response = webEx.Response as HttpWebResponse; - WriteVerbose(string.Format(Resources.WebExceptionMessage, response.StatusCode)); - } - catch (Exception) - { - - } - errorRecord = new ErrorRecord(webEx, string.Empty, ErrorCategory.ConnectionError, null); - break; - } - else if (exType == typeof (FormatException)) - { - var formEx = ex as FormatException; - if (formEx == null) - break; - WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); - errorRecord = new ErrorRecord(formEx, string.Empty, ErrorCategory.InvalidData, null); - } - else if (exType == typeof(NullReferenceException)) - { - var nullEx = ex as NullReferenceException; - if (nullEx == null) - break; - WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); - errorRecord = new ErrorRecord(nullEx, string.Empty, ErrorCategory.InvalidData, null); - break; - } - else if (exType == typeof(ArgumentNullException)) - { - var argEx = ex as ArgumentNullException; - if (argEx == null) - break; - WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); - errorRecord = new ErrorRecord(argEx, string.Empty, ErrorCategory.InvalidData, null); - break; - } - ex = ex.InnerException; - } while (ex != null); - - if(errorRecord == null) - { - errorRecord = new ErrorRecord(exception, string.Empty, ErrorCategory.NotSpecified, null); - } - - WriteError(errorRecord); - } - - protected override void BeginProcessing() - { - base.BeginProcessing(); - if(verifyResourceBeforeCmdletExecute) - VerifyResourceContext(); - } - /// - /// this method verifies that a resource has been selected before this commandlet is executed - /// - private void VerifyResourceContext() - { - if (!CheckResourceContextPresent()) - { - throw GetGenericException(Resources.ResourceContextNotSetMessage, null); - } - } - - private bool CheckResourceContextPresent() - { - var resourceContext = StorSimpleClient.GetResourceContext(); - if (resourceContext == null - || string.IsNullOrEmpty(resourceContext.ResourceId) - || string.IsNullOrEmpty(resourceContext.ResourceName)) - { - return false; - } - return true; - } - - internal bool ValidStorageAccountCred(string storageAccountName, string storageAccountKey, string endpoint) - { - using (System.Management.Automation.PowerShell ps = System.Management.Automation.PowerShell.Create()) - { - bool valid = true; - Random rnd = new Random(); - string testContainerName = string.Format("storsimplesdkvalidation{0}", rnd.Next()); - //create a storage container and then delete it - string validateScript = string.Format( - @"$context = New-AzureStorageContext -StorageAccountName {0} -StorageAccountKey {1} -Endpoint {2};" - + @"New-AzureStorageContainer -Name {3} -Context $context;" - + @"Remove-AzureStorageContainer -Name {3} -Context $context -Force;", - storageAccountName, storageAccountKey, endpoint, testContainerName); - ps.AddScript(validateScript); - ps.Invoke(); - if (ps.HadErrors) - { - var exception = ps.Streams.Error[0].Exception; - string getScript = string.Format( - @"$context = New-AzureStorageContext -StorageAccountName {0} -StorageAccountKey {1};" - + @"Get-AzureStorageContainer -Name {2} -Context $context;", - storageAccountName, storageAccountKey, testContainerName); - ps.AddScript(getScript); - var result = ps.Invoke(); - if (result != null && result.Count > 0) - { - //storage container successfully created and still exists, retry deleting it - int retryCount = 1; - string removeScript = string.Format( - @"$context = New-AzureStorageContext -StorageAccountName {0} -StorageAccountKey {1};" - + @"Remove-AzureStorageContainer -Name {2} -Context $context -Force;", - storageAccountName, storageAccountKey, testContainerName); - do - { - WriteVerbose(string.Format(Resources.StorageAccountCleanupRetryMessage, retryCount)); - ps.AddScript(removeScript); - ps.Invoke(); - Thread.Sleep(retryCount * 1000); - ps.AddScript(getScript); - result = ps.Invoke(); - } while (result != null && result.Count > 0 && ++retryCount <= 5); - } - else - { - valid = false; - HandleException(exception); - } - } - return valid; - } - } - - - internal string GetStorageAccountLocation(string storageAccountName, out bool exist) - { - using (System.Management.Automation.PowerShell ps = System.Management.Automation.PowerShell.Create()) - { - string location = null; - exist = false; - - string script = string.Format(@"Get-AzureStorageAccount -StorageAccountName {0}", storageAccountName); - ps.AddScript(script); - var result = ps.Invoke(); - - if (ps.HadErrors) - { - HandleException(ps.Streams.Error[0].Exception); - WriteVerbose(string.Format(Resources.StorageAccountNotFoundMessage, storageAccountName)); - } - - if (result != null && result.Count > 0) - { - exist = true; - WriteVerbose(string.Format(Resources.StorageAccountFoundMessage, storageAccountName)); - script = string.Format(@"Get-AzureStorageAccount -StorageAccountName {0}" - + @"| Select-Object -ExpandProperty Location", storageAccountName); - ps.AddScript(script); - result = ps.Invoke(); - if (ps.HadErrors) - { - HandleException(ps.Streams.Error[0].Exception); - } - if (result.Count > 0) - { - location = result[0].ToString(); - } - } - return location; - } - } - - internal bool ValidateAndEncryptStorageCred(string name, string key, string endpoint, out string encryptedKey, out string thumbprint) - { - StorSimpleCryptoManager storSimpleCryptoManager = new StorSimpleCryptoManager(StorSimpleClient); - thumbprint = storSimpleCryptoManager.GetSecretsEncryptionThumbprint(); - encryptedKey = null; - if (!string.IsNullOrEmpty(key)) - { - //validate storage account credentials - if (!ValidStorageAccountCred(name, key, endpoint)) - { - WriteVerbose(Resources.StorageCredentialVerificationFailureMessage); - return false; - } - WriteVerbose(Resources.StorageCredentialVerificationSuccessMessage); - WriteVerbose(Resources.EncryptionInProgressMessage); - storSimpleCryptoManager.EncryptSecretWithRakPub(key, out encryptedKey); - } - return true; - } - - /// - /// Helper method to determine if this device has already been configured or not - /// - /// - public bool IsDeviceConfigurationCompleteForDevice(DeviceDetails details) - { - bool data0Configured = false; - - if (details.NetInterfaceList != null) - { - NetInterface data0 = details.NetInterfaceList.Where(x => x.InterfaceId == NetInterfaceId.Data0).ToList().First(); - if (data0 != null - && data0.IsEnabled - && data0.NicIPv4Settings != null - && !string.IsNullOrEmpty(data0.NicIPv4Settings.Controller0IPv4Address)) - data0Configured = true; - } - return data0Configured; - } + using System.Diagnostics.Eventing; + + using Microsoft.WindowsAzure.Management.Scheduler.Models; + + public class StorSimpleCmdletBase : AzurePSCmdlet + { + //this property will determine whether before running the actual commandlet logic, should resource selection be verified + protected bool verifyResourceBeforeCmdletExecute; + + /// + /// default constructor for most commandlets. In this case, Resource check will be verified + /// + public StorSimpleCmdletBase() : this(true) { } + + /// + /// constructor variant if you want to suppress the resource check for your commandlet + /// + /// + public StorSimpleCmdletBase(bool performResourceCheck):base() + { + verifyResourceBeforeCmdletExecute = performResourceCheck; + } + + private StorSimpleClient storSimpleClient; + + internal StorSimpleClient StorSimpleClient + { + get + { + if (this.storSimpleClient == null) + { + this.storSimpleClient = new StorSimpleClient(Profile, Profile.Context.Subscription); + } + storSimpleClient.ClientRequestId = Guid.NewGuid().ToString("D") + "_PS"; + WriteVerbose(string.Format(Resources.ClientRequestIdMessage, storSimpleClient.ClientRequestId)); + return this.storSimpleClient; + } + } + + internal virtual void HandleAsyncTaskResponse(AzureOperationResponse opResponse, string operationName) + { + string msg = string.Empty; + + if (opResponse.StatusCode != HttpStatusCode.Accepted && opResponse.StatusCode != HttpStatusCode.OK) + { + msg = string.Format(Resources.FailureMessageSubmitTask, operationName); + } + + else + { + if (opResponse.GetType().Equals(typeof(TaskResponse))) + { + var taskResponse = opResponse as TaskResponse; + msg = string.Format(Resources.SuccessMessageSubmitTask, operationName, taskResponse.TaskId); + WriteObject(taskResponse.TaskId); + } + + else if (opResponse.GetType().Equals(typeof(GuidTaskResponse))) + { + var guidTaskResponse = opResponse as GuidTaskResponse; + msg = string.Format(Resources.SuccessMessageSubmitTask, operationName, guidTaskResponse.TaskId); + WriteObject(guidTaskResponse.TaskId); + } + } + + WriteVerbose(msg); + } + + internal virtual void HandleDeviceJobResponse(JobResponse jobResponse, string operationName) + { + string msg = string.Format(Resources.SuccessMessageSubmitDeviceJob, operationName, jobResponse.JobId); + WriteObject(jobResponse.JobId); + WriteVerbose(msg); + } + + internal virtual void HandleSyncTaskResponse(TaskStatusInfo taskStatus, string operationName) + { + string msg = string.Empty; + TaskReport taskReport = new TaskReport(taskStatus); + + if (taskStatus.AsyncTaskAggregatedResult != AsyncTaskAggregatedResult.Succeeded) + { + msg = string.Format(Resources.FailureMessageCompleteJob, operationName); + WriteObject(taskReport); + } + + else + { + msg = string.Format(Resources.SuccessMessageCompleteJob, operationName); + WriteObject(taskReport); + } + + WriteVerbose(msg); + } + + private static void StripNamespaces(XDocument doc) + { + var elements = doc.Descendants(); + elements.Attributes().Where(attr => attr.IsNamespaceDeclaration).Remove(); + foreach (var element in elements) + { + element.Name = element.Name.LocalName; + } + } + + internal virtual void HandleException(Exception exception) + { + ErrorRecord errorRecord = null; + var ex = exception; + do + { + Type exType = ex.GetType(); + if(exType == typeof(CloudException)) + { + var cloudEx = ex as CloudException; + if (cloudEx == null) + break; + var response = cloudEx.Response; + try + { + if (response.StatusCode == HttpStatusCode.NotFound) + { + this.WriteVerbose("The requested commandlet is not available"); + var notAvailableException = new Exception("The requested commandlet is not available"); + errorRecord = new ErrorRecord(notAvailableException, string.Empty, ErrorCategory.InvalidOperation, null); + break; + } + else + { + XDocument xDoc = XDocument.Parse(response.Content); + StripNamespaces(xDoc); + string cloudErrorCode = xDoc.Descendants("ErrorCode").FirstOrDefault().Value; + WriteVerbose(string.Format(Resources.CloudExceptionMessage, cloudErrorCode)); + } + } + catch (Exception) + { + + } + + errorRecord = new ErrorRecord(cloudEx, string.Empty, ErrorCategory.InvalidOperation, null); + break; + } + else if(exType == typeof(WebException)) + { + var webEx = ex as WebException; + if (webEx == null) + break; + try + { + HttpWebResponse response = webEx.Response as HttpWebResponse; + if (response.StatusCode == HttpStatusCode.NotFound) + { + this.WriteVerbose(""); + } + + WriteVerbose(string.Format(Resources.WebExceptionMessage, response.StatusCode)); + } + catch (Exception) + { + + } + errorRecord = new ErrorRecord(webEx, string.Empty, ErrorCategory.ConnectionError, null); + break; + } + else if (exType == typeof (FormatException)) + { + var formEx = ex as FormatException; + if (formEx == null) + break; + WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); + errorRecord = new ErrorRecord(formEx, string.Empty, ErrorCategory.InvalidData, null); + } + else if (exType == typeof(NullReferenceException)) + { + var nullEx = ex as NullReferenceException; + if (nullEx == null) + break; + WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); + errorRecord = new ErrorRecord(nullEx, string.Empty, ErrorCategory.InvalidData, null); + break; + } + else if (exType == typeof(ArgumentNullException)) + { + var argEx = ex as ArgumentNullException; + if (argEx == null) + break; + WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); + errorRecord = new ErrorRecord(argEx, string.Empty, ErrorCategory.InvalidData, null); + break; + } + ex = ex.InnerException; + } while (ex != null); + + if(errorRecord == null) + { + errorRecord = new ErrorRecord(exception, string.Empty, ErrorCategory.NotSpecified, null); + } + + WriteError(errorRecord); + } + + protected override void BeginProcessing() + { + base.BeginProcessing(); + if(verifyResourceBeforeCmdletExecute) + VerifyResourceContext(); + } + /// + /// this method verifies that a resource has been selected before this commandlet is executed + /// + private void VerifyResourceContext() + { + if (!CheckResourceContextPresent()) + { + throw GetGenericException(Resources.ResourceContextNotSetMessage, null); + } + } + + private bool CheckResourceContextPresent() + { + var resourceContext = StorSimpleClient.GetResourceContext(); + if (resourceContext == null + || string.IsNullOrEmpty(resourceContext.ResourceId) + || string.IsNullOrEmpty(resourceContext.ResourceName)) + { + return false; + } + return true; + } + + internal bool ValidStorageAccountCred(string storageAccountName, string storageAccountKey, string endpoint) + { + using (System.Management.Automation.PowerShell ps = System.Management.Automation.PowerShell.Create()) + { + bool valid = true; + Random rnd = new Random(); + string testContainerName = string.Format("storsimplesdkvalidation{0}", rnd.Next()); + //create a storage container and then delete it + string validateScript = string.Format( + @"$context = New-AzureStorageContext -StorageAccountName {0} -StorageAccountKey {1} -Endpoint {2};" + + @"New-AzureStorageContainer -Name {3} -Context $context;" + + @"Remove-AzureStorageContainer -Name {3} -Context $context -Force;", + storageAccountName, storageAccountKey, endpoint, testContainerName); + ps.AddScript(validateScript); + ps.Invoke(); + if (ps.HadErrors) + { + var exception = ps.Streams.Error[0].Exception; + string getScript = string.Format( + @"$context = New-AzureStorageContext -StorageAccountName {0} -StorageAccountKey {1};" + + @"Get-AzureStorageContainer -Name {2} -Context $context;", + storageAccountName, storageAccountKey, testContainerName); + ps.AddScript(getScript); + var result = ps.Invoke(); + if (result != null && result.Count > 0) + { + //storage container successfully created and still exists, retry deleting it + int retryCount = 1; + string removeScript = string.Format( + @"$context = New-AzureStorageContext -StorageAccountName {0} -StorageAccountKey {1};" + + @"Remove-AzureStorageContainer -Name {2} -Context $context -Force;", + storageAccountName, storageAccountKey, testContainerName); + do + { + WriteVerbose(string.Format(Resources.StorageAccountCleanupRetryMessage, retryCount)); + ps.AddScript(removeScript); + ps.Invoke(); + Thread.Sleep(retryCount * 1000); + ps.AddScript(getScript); + result = ps.Invoke(); + } while (result != null && result.Count > 0 && ++retryCount <= 5); + } + else + { + valid = false; + HandleException(exception); + } + } + return valid; + } + } + + + internal string GetStorageAccountLocation(string storageAccountName, out bool exist) + { + using (System.Management.Automation.PowerShell ps = System.Management.Automation.PowerShell.Create()) + { + string location = null; + exist = false; + + string script = string.Format(@"Get-AzureStorageAccount -StorageAccountName {0}", storageAccountName); + ps.AddScript(script); + var result = ps.Invoke(); + + if (ps.HadErrors) + { + HandleException(ps.Streams.Error[0].Exception); + WriteVerbose(string.Format(Resources.StorageAccountNotFoundMessage, storageAccountName)); + } + + if (result != null && result.Count > 0) + { + exist = true; + WriteVerbose(string.Format(Resources.StorageAccountFoundMessage, storageAccountName)); + script = string.Format(@"Get-AzureStorageAccount -StorageAccountName {0}" + + @"| Select-Object -ExpandProperty Location", storageAccountName); + ps.AddScript(script); + result = ps.Invoke(); + if (ps.HadErrors) + { + HandleException(ps.Streams.Error[0].Exception); + } + if (result.Count > 0) + { + location = result[0].ToString(); + } + } + return location; + } + } + + internal bool ValidateAndEncryptStorageCred(string name, string key, string endpoint, out string encryptedKey, out string thumbprint) + { + StorSimpleCryptoManager storSimpleCryptoManager = new StorSimpleCryptoManager(StorSimpleClient); + thumbprint = storSimpleCryptoManager.GetSecretsEncryptionThumbprint(); + encryptedKey = null; + if (!string.IsNullOrEmpty(key)) + { + //validate storage account credentials + if (!ValidStorageAccountCred(name, key, endpoint)) + { + WriteVerbose(Resources.StorageCredentialVerificationFailureMessage); + return false; + } + WriteVerbose(Resources.StorageCredentialVerificationSuccessMessage); + WriteVerbose(Resources.EncryptionInProgressMessage); + storSimpleCryptoManager.EncryptSecretWithRakPub(key, out encryptedKey); + } + return true; + } + + /// + /// Helper method to determine if this device has already been configured or not + /// + /// + public bool IsDeviceConfigurationCompleteForDevice(DeviceDetails details) + { + bool data0Configured = false; + + if (details.NetInterfaceList != null) + { + NetInterface data0 = details.NetInterfaceList.Where(x => x.InterfaceId == NetInterfaceId.Data0).ToList().First(); + if (data0 != null + && data0.IsEnabled + && data0.NicIPv4Settings != null + && !string.IsNullOrEmpty(data0.NicIPv4Settings.Controller0IPv4Address)) + data0Configured = true; + } + return data0Configured; + } - /// - /// this method verifies that the devicename parameter specified is completely configured - /// most operations are not allowed on a non-configured device - /// - public void VerifyDeviceConfigurationCompleteForDevice(string deviceId) - { - var details = storSimpleClient.GetDeviceDetails(deviceId); - var data0Configured = IsDeviceConfigurationCompleteForDevice(details); - if (!data0Configured) - throw GetGenericException(Resources.DeviceNotConfiguredMessage, null); - } - - internal string GetHostnameFromEndpoint(string endpoint) - { - return string.Format("blob.{0}", endpoint); - } - - internal string GetEndpointFromHostname(string hostname) - { - return hostname.Substring(hostname.IndexOf('.') + 1); - } - - internal Exception GetGenericException(string exceptionMessage, Exception innerException) - { - return new Exception(exceptionMessage, innerException); - } - - /// - /// Validate that all network configs are valid. - /// - /// Its mandatory to provide either (IPv4 Address and netmask) or IPv6 orefix for an interface that - /// is being enabled. ( Was previously disabled and is now being configured) - /// - /// - internal bool ValidateNetworkConfigs(DeviceDetails details, NetworkConfig[] StorSimpleNetworkConfig) - { - if (StorSimpleNetworkConfig == null) - { - return true; - } - foreach (var netConfig in StorSimpleNetworkConfig) - { - // get corresponding netInterface in device details. - var netInterface = details.NetInterfaceList.FirstOrDefault(x => x.InterfaceId == netConfig.InterfaceAlias); - // If its being enabled and its not Data0, it must have IP Address info - if (netInterface == null || (netInterface.InterfaceId != NetInterfaceId.Data0 && !netInterface.IsEnabled)) - { - // If its not an enabled interface either IPv6(prefix) or IPv4(address and mask) must be provided. - if ((netConfig.IPv4Address == null || netConfig.IPv4Netmask == null) && netConfig.IPv6Prefix == null) - { - WriteVerbose(string.Format(Resources.IPAddressesNotProvidedForNetInterfaceBeingEnabled, StorSimpleContext.ResourceName, details.DeviceProperties.DeviceId)); - WriteObject(null); - return false; - } - } - } - return true; - } - - /// - /// Try to parse an IP Address from the provided string - /// - /// IP Address string - /// - /// Name of the param which is being processed (to be used for errors) - internal bool TrySetIPAddress(string data, out IPAddress ipAddress, string paramName) - { - if (data == null) - { - ipAddress = null; - return true; - } - try - { - ipAddress = IPAddress.Parse(data); - return true; - } - catch (FormatException) - { - ipAddress = null; - WriteVerbose(string.Format(Resources.InvalidIPAddressProvidedMessage, paramName)); - return false; - } - } - - /// - /// Validate that all mandatory data for the first Device Configuration has been provided. - /// - /// bool indicating whether all mandatory data is there or not. - internal bool ValidParamsForFirstDeviceConfiguration(NetworkConfig[] netConfigs, TimeZoneInfo timeZone, string secondaryDnsServer) - { - if (netConfigs == null) - { - return false; - } - // Make sure network config for Data0 has been provided with atleast Controller0 IP Address - var data0 = netConfigs.FirstOrDefault(x => x.InterfaceAlias == NetInterfaceId.Data0); - if (data0 == null || data0.Controller0IPv4Address == null || data0.Controller1IPv4Address == null) - { - return false; - } - // Timezone and Secondary Dns Server are also mandatory - if (timeZone == null || string.IsNullOrEmpty(secondaryDnsServer)) - { - return false; - } - return true; - } - } + /// + /// this method verifies that the devicename parameter specified is completely configured + /// most operations are not allowed on a non-configured device + /// + public void VerifyDeviceConfigurationCompleteForDevice(string deviceId) + { + var details = storSimpleClient.GetDeviceDetails(deviceId); + var data0Configured = IsDeviceConfigurationCompleteForDevice(details); + if (!data0Configured) + throw GetGenericException(Resources.DeviceNotConfiguredMessage, null); + } + + internal string GetHostnameFromEndpoint(string endpoint) + { + return string.Format("blob.{0}", endpoint); + } + + internal string GetEndpointFromHostname(string hostname) + { + return hostname.Substring(hostname.IndexOf('.') + 1); + } + + internal Exception GetGenericException(string exceptionMessage, Exception innerException) + { + return new Exception(exceptionMessage, innerException); + } + + /// + /// Validate that all network configs are valid. + /// + /// Its mandatory to provide either (IPv4 Address and netmask) or IPv6 orefix for an interface that + /// is being enabled. ( Was previously disabled and is now being configured) + /// + /// + internal bool ValidateNetworkConfigs(DeviceDetails details, NetworkConfig[] StorSimpleNetworkConfig) + { + if (StorSimpleNetworkConfig == null) + { + return true; + } + foreach (var netConfig in StorSimpleNetworkConfig) + { + // get corresponding netInterface in device details. + var netInterface = details.NetInterfaceList.FirstOrDefault(x => x.InterfaceId == netConfig.InterfaceAlias); + // If its being enabled and its not Data0, it must have IP Address info + if (netInterface == null || (netInterface.InterfaceId != NetInterfaceId.Data0 && !netInterface.IsEnabled)) + { + // If its not an enabled interface either IPv6(prefix) or IPv4(address and mask) must be provided. + if ((netConfig.IPv4Address == null || netConfig.IPv4Netmask == null) && netConfig.IPv6Prefix == null) + { + WriteVerbose(string.Format(Resources.IPAddressesNotProvidedForNetInterfaceBeingEnabled, StorSimpleContext.ResourceName, details.DeviceProperties.DeviceId)); + WriteObject(null); + return false; + } + } + } + return true; + } + + /// + /// Try to parse an IP Address from the provided string + /// + /// IP Address string + /// + /// Name of the param which is being processed (to be used for errors) + internal bool TrySetIPAddress(string data, out IPAddress ipAddress, string paramName) + { + if (data == null) + { + ipAddress = null; + return true; + } + try + { + ipAddress = IPAddress.Parse(data); + return true; + } + catch (FormatException) + { + ipAddress = null; + WriteVerbose(string.Format(Resources.InvalidIPAddressProvidedMessage, paramName)); + return false; + } + } + + /// + /// Validate that all mandatory data for the first Device Configuration has been provided. + /// + /// bool indicating whether all mandatory data is there or not. + internal bool ValidParamsForFirstDeviceConfiguration(NetworkConfig[] netConfigs, TimeZoneInfo timeZone, string secondaryDnsServer) + { + if (netConfigs == null) + { + return false; + } + // Make sure network config for Data0 has been provided with atleast Controller0 IP Address + var data0 = netConfigs.FirstOrDefault(x => x.InterfaceAlias == NetInterfaceId.Data0); + if (data0 == null || data0.Controller0IPv4Address == null || data0.Controller1IPv4Address == null) + { + return false; + } + // Timezone and Secondary Dns Server are also mandatory + if (timeZone == null || string.IsNullOrEmpty(secondaryDnsServer)) + { + return false; + } + return true; + } + } } \ No newline at end of file From 253b866626c0aef22ca97ef1a0cdb4ec80416038 Mon Sep 17 00:00:00 2001 From: Sankaranarayanan M Date: Mon, 6 Apr 2015 11:59:21 +0530 Subject: [PATCH 2/9] Handling 404 web exceptions with a specific error message. --- .../Properties/Resources.Designer.cs | 11 ++++++++++- .../Commands.StorSimple/Properties/Resources.resx | 4 +++- .../Commands.StorSimple/StorSimpleCmdletBase.cs | 3 +-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/ServiceManagement/StorSimple/Commands.StorSimple/Properties/Resources.Designer.cs b/src/ServiceManagement/StorSimple/Commands.StorSimple/Properties/Resources.Designer.cs index 31f9032287d3..83223daab4fe 100644 --- a/src/ServiceManagement/StorSimple/Commands.StorSimple/Properties/Resources.Designer.cs +++ b/src/ServiceManagement/StorSimple/Commands.StorSimple/Properties/Resources.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34014 +// Runtime Version:4.0.30319.0 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -708,6 +708,15 @@ internal static string NotFoundVolumeMessage { } } + /// + /// Looks up a localized string similar to One or more inputs passed is wrong or the cmdlet that you are trying to use is not available or the StorSimple Manager service end point does not exist.. + /// + internal static string NotFoundWebExceptionMessage { + get { + return ResourceManager.GetString("NotFoundWebExceptionMessage", resourceCulture); + } + } + /// /// Looks up a localized string similar to Registration key parameter is not passed. Validating whether a registration key is already persisted for this resource!. /// diff --git a/src/ServiceManagement/StorSimple/Commands.StorSimple/Properties/Resources.resx b/src/ServiceManagement/StorSimple/Commands.StorSimple/Properties/Resources.resx index eb8d09aed3d0..c8751e431e42 100644 --- a/src/ServiceManagement/StorSimple/Commands.StorSimple/Properties/Resources.resx +++ b/src/ServiceManagement/StorSimple/Commands.StorSimple/Properties/Resources.resx @@ -528,6 +528,8 @@ a special character No settings were provided for updating device details. - + + + One or more inputs passed is wrong or the cmdlet that you are trying to use is not available or the StorSimple Manager service end point does not exist. \ No newline at end of file diff --git a/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs b/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs index e5282c0b6043..af1aacc1f790 100644 --- a/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs +++ b/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs @@ -151,8 +151,7 @@ internal virtual void HandleException(Exception exception) { if (response.StatusCode == HttpStatusCode.NotFound) { - this.WriteVerbose("The requested commandlet is not available"); - var notAvailableException = new Exception("The requested commandlet is not available"); + var notAvailableException = new Exception(Resources.NotFoundWebExceptionMessage); errorRecord = new ErrorRecord(notAvailableException, string.Empty, ErrorCategory.InvalidOperation, null); break; } From 5d43652d648bc1f8e489b2dc167a557abf585a77 Mon Sep 17 00:00:00 2001 From: Sankaranarayanan M Date: Mon, 6 Apr 2015 12:00:49 +0530 Subject: [PATCH 3/9] Cleaning up unnecessary code. --- .../StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs b/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs index af1aacc1f790..1977ede05241 100644 --- a/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs +++ b/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs @@ -179,12 +179,7 @@ internal virtual void HandleException(Exception exception) try { HttpWebResponse response = webEx.Response as HttpWebResponse; - if (response.StatusCode == HttpStatusCode.NotFound) - { - this.WriteVerbose(""); - } - - WriteVerbose(string.Format(Resources.WebExceptionMessage, response.StatusCode)); + WriteVerbose(string.Format(Resources.WebExceptionMessage, response.StatusCode)); } catch (Exception) { From dd04dbc9fb7ac689552bc13255cafa68f821a011 Mon Sep 17 00:00:00 2001 From: Sankaranarayanan M Date: Mon, 6 Apr 2015 14:42:43 +0530 Subject: [PATCH 4/9] Fixing merge error in resource file. --- .../StorSimple/Commands.StorSimple/Properties/Resources.resx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ServiceManagement/StorSimple/Commands.StorSimple/Properties/Resources.resx b/src/ServiceManagement/StorSimple/Commands.StorSimple/Properties/Resources.resx index bf9f806f6256..3efc6c2bc6e0 100644 --- a/src/ServiceManagement/StorSimple/Commands.StorSimple/Properties/Resources.resx +++ b/src/ServiceManagement/StorSimple/Commands.StorSimple/Properties/Resources.resx @@ -531,6 +531,7 @@ a special character One or more inputs passed is wrong or the cmdlet that you are trying to use is not available or the StorSimple Manager service end point does not exist. + Please provide an encryption key consisting of printable ASCII characters From ea5229f5a7e4d33146a9098df11dd5e586d9df90 Mon Sep 17 00:00:00 2001 From: parvezah Date: Tue, 7 Apr 2015 11:12:26 +0530 Subject: [PATCH 5/9] Adding the PersistAzureVMOnFailrue hook for persisting failed provisioning vms. --- .../NewAzureStorSimpleVirtualDeviceCommand.cs | 8 ++++++++ .../Commands.StorSimple/Commands.StorSimple.csproj | 5 +++-- .../Commands.StorSimple/StorSimpleCmdletHelpMessage.cs | 3 ++- .../StorSimple/Commands.StorSimple/packages.config | 2 +- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/ServiceManagement/StorSimple/Commands.StorSimple/Cmdlets/VirtualDevice/NewAzureStorSimpleVirtualDeviceCommand.cs b/src/ServiceManagement/StorSimple/Commands.StorSimple/Cmdlets/VirtualDevice/NewAzureStorSimpleVirtualDeviceCommand.cs index e92df5217a47..39166a3b5f1e 100644 --- a/src/ServiceManagement/StorSimple/Commands.StorSimple/Cmdlets/VirtualDevice/NewAzureStorSimpleVirtualDeviceCommand.cs +++ b/src/ServiceManagement/StorSimple/Commands.StorSimple/Cmdlets/VirtualDevice/NewAzureStorSimpleVirtualDeviceCommand.cs @@ -41,6 +41,9 @@ public class NewAzureStorSimpleVirtualDeviceCommand : StorSimpleCmdletBase [Parameter(Position = 3, Mandatory = true, HelpMessage = StorSimpleCmdletHelpMessage.CreateNewStorageAccount, ParameterSetName = StorSimpleCmdletParameterSet.CreateNewStorageAccount)] public SwitchParameter CreateNewStorageAccount { get; set; } + + [Parameter(DontShow = true, Mandatory = false, HelpMessage = StorSimpleCmdletHelpMessage.PersistAzureVMOnFailrue)] + public SwitchParameter PersistAzureVMOnFailrue { get; set; } public override void ExecuteCmdlet() { @@ -57,6 +60,11 @@ public override void ExecuteCmdlet() StorageAccountName = StorageAccountName }; + if (PersistAzureVMOnFailrue.IsPresent) + { + applianceProvisiongInfo.DeleteAzureCisVMOnFailure = false; + } + var deviceJobResponse = StorSimpleClient.CreateVirtualDevice(applianceProvisiongInfo); HandleDeviceJobResponse(deviceJobResponse, "create"); diff --git a/src/ServiceManagement/StorSimple/Commands.StorSimple/Commands.StorSimple.csproj b/src/ServiceManagement/StorSimple/Commands.StorSimple/Commands.StorSimple.csproj index 64809e1329eb..2dac2eafecea 100644 --- a/src/ServiceManagement/StorSimple/Commands.StorSimple/Commands.StorSimple.csproj +++ b/src/ServiceManagement/StorSimple/Commands.StorSimple/Commands.StorSimple.csproj @@ -82,8 +82,9 @@ ..\..\..\packages\Microsoft.WindowsAzure.Management.Scheduler.6.0.0\lib\net40\Microsoft.WindowsAzure.Management.Scheduler.dll - - ..\..\..\packages\Microsoft.WindowsAzure.Management.StorSimple.1.0.0-preview\lib\net40\Microsoft.WindowsAzure.Management.StorSimple.dll + + False + ..\..\..\packages\Microsoft.WindowsAzure.Management.StorSimple.1.0.1-preview\lib\net40\Microsoft.WindowsAzure.Management.StorSimple.dll ..\..\..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll diff --git a/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletHelpMessage.cs b/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletHelpMessage.cs index 5280605c8f9b..6eb25dc8463a 100644 --- a/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletHelpMessage.cs +++ b/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletHelpMessage.cs @@ -119,6 +119,7 @@ internal static class StorSimpleCmdletHelpMessage public const string ToTime = "End of time interval for which to filter results."; public const string DeviceJobStatus = "Status of job."; public const string DeviceJobType = "Type of job."; - + public const string PersistAzureVMOnFailrue = + "The switch parameter to debug any Provisioning Failrues by skipping deletion of the VM on failrue"; } } diff --git a/src/ServiceManagement/StorSimple/Commands.StorSimple/packages.config b/src/ServiceManagement/StorSimple/Commands.StorSimple/packages.config index e26afc774aae..ffd641880f89 100644 --- a/src/ServiceManagement/StorSimple/Commands.StorSimple/packages.config +++ b/src/ServiceManagement/StorSimple/Commands.StorSimple/packages.config @@ -12,6 +12,6 @@ - + \ No newline at end of file From 65f0610f828e1386886b66b8ec83eda6f7ab6dfe Mon Sep 17 00:00:00 2001 From: parvezah Date: Tue, 7 Apr 2015 14:51:51 +0530 Subject: [PATCH 6/9] Fixing the name space for the virtual device cmdlet --- .../VirtualDevice/NewAzureStorSimpleVirtualDeviceCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ServiceManagement/StorSimple/Commands.StorSimple/Cmdlets/VirtualDevice/NewAzureStorSimpleVirtualDeviceCommand.cs b/src/ServiceManagement/StorSimple/Commands.StorSimple/Cmdlets/VirtualDevice/NewAzureStorSimpleVirtualDeviceCommand.cs index 39166a3b5f1e..5bcbf36b8ad3 100644 --- a/src/ServiceManagement/StorSimple/Commands.StorSimple/Cmdlets/VirtualDevice/NewAzureStorSimpleVirtualDeviceCommand.cs +++ b/src/ServiceManagement/StorSimple/Commands.StorSimple/Cmdlets/VirtualDevice/NewAzureStorSimpleVirtualDeviceCommand.cs @@ -16,7 +16,7 @@ using System.Management.Automation; using Microsoft.WindowsAzure.Management.StorSimple.Models; -namespace Microsoft.WindowsAzure.Commands.StorSimple.Cmdlets.VirtualDevice +namespace Microsoft.WindowsAzure.Commands.StorSimple.Cmdlets { [Cmdlet(VerbsCommon.New, "AzureStorSimpleVirtualDevice"), OutputType(typeof(string))] public class NewAzureStorSimpleVirtualDeviceCommand : StorSimpleCmdletBase From 252044f119ff63f1097dcd798d40175b6ea59736 Mon Sep 17 00:00:00 2001 From: Sankaranarayanan Mahadevan Date: Wed, 8 Apr 2015 17:14:16 +0530 Subject: [PATCH 7/9] Fixed error message, and other cr comments. --- .../Properties/Resources.Designer.cs | 2 +- .../Properties/Resources.resx | 2 +- .../StorSimpleCmdletBase.cs | 20 ++++++++----------- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/ServiceManagement/StorSimple/Commands.StorSimple/Properties/Resources.Designer.cs b/src/ServiceManagement/StorSimple/Commands.StorSimple/Properties/Resources.Designer.cs index 045ecb3c976d..fa0cc9cc4740 100644 --- a/src/ServiceManagement/StorSimple/Commands.StorSimple/Properties/Resources.Designer.cs +++ b/src/ServiceManagement/StorSimple/Commands.StorSimple/Properties/Resources.Designer.cs @@ -718,7 +718,7 @@ internal static string NotFoundVolumeMessage { } /// - /// Looks up a localized string similar to One or more inputs passed is wrong or the cmdlet that you are trying to use is not available or the StorSimple Manager service end point does not exist.. + /// Looks up a localized string similar to One or more inputs passed is wrong or the cmdlet that you are trying to use is not available.. /// internal static string NotFoundWebExceptionMessage { get { diff --git a/src/ServiceManagement/StorSimple/Commands.StorSimple/Properties/Resources.resx b/src/ServiceManagement/StorSimple/Commands.StorSimple/Properties/Resources.resx index 3efc6c2bc6e0..e2ecd60882b0 100644 --- a/src/ServiceManagement/StorSimple/Commands.StorSimple/Properties/Resources.resx +++ b/src/ServiceManagement/StorSimple/Commands.StorSimple/Properties/Resources.resx @@ -530,7 +530,7 @@ a special character No settings were provided for updating device details. - One or more inputs passed is wrong or the cmdlet that you are trying to use is not available or the StorSimple Manager service end point does not exist. + One or more inputs passed is wrong or the cmdlet that you are trying to use is not available. Please provide an encryption key consisting of printable ASCII characters diff --git a/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs b/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs index 1977ede05241..5b21e9d12c66 100644 --- a/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs +++ b/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs @@ -29,10 +29,6 @@ namespace Microsoft.WindowsAzure.Commands.StorSimple { - using System.Diagnostics.Eventing; - - using Microsoft.WindowsAzure.Management.Scheduler.Models; - public class StorSimpleCmdletBase : AzurePSCmdlet { //this property will determine whether before running the actual commandlet logic, should resource selection be verified @@ -151,17 +147,17 @@ internal virtual void HandleException(Exception exception) { if (response.StatusCode == HttpStatusCode.NotFound) { - var notAvailableException = new Exception(Resources.NotFoundWebExceptionMessage); - errorRecord = new ErrorRecord(notAvailableException, string.Empty, ErrorCategory.InvalidOperation, null); - break; + var notAvailableException = new Exception(Resources.NotFoundWebExceptionMessage); + errorRecord = new ErrorRecord(notAvailableException, string.Empty, ErrorCategory.InvalidOperation, null); + break; } else { - XDocument xDoc = XDocument.Parse(response.Content); - StripNamespaces(xDoc); - string cloudErrorCode = xDoc.Descendants("ErrorCode").FirstOrDefault().Value; - WriteVerbose(string.Format(Resources.CloudExceptionMessage, cloudErrorCode)); - } + XDocument xDoc = XDocument.Parse(response.Content); + StripNamespaces(xDoc); + string cloudErrorCode = xDoc.Descendants("ErrorCode").FirstOrDefault().Value; + WriteVerbose(string.Format(Resources.CloudExceptionMessage, cloudErrorCode)); + } } catch (Exception) { From d62f939718d9f927e188f577924ef43d3edaca8c Mon Sep 17 00:00:00 2001 From: Sankaranarayanan Mahadevan Date: Wed, 8 Apr 2015 17:16:50 +0530 Subject: [PATCH 8/9] Fixed spacing length --- .../StorSimpleCmdletBase.cs | 1072 ++++++++--------- 1 file changed, 536 insertions(+), 536 deletions(-) diff --git a/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs b/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs index 5b21e9d12c66..e56bca49975d 100644 --- a/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs +++ b/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs @@ -29,548 +29,548 @@ namespace Microsoft.WindowsAzure.Commands.StorSimple { - public class StorSimpleCmdletBase : AzurePSCmdlet - { - //this property will determine whether before running the actual commandlet logic, should resource selection be verified - protected bool verifyResourceBeforeCmdletExecute; - - /// - /// default constructor for most commandlets. In this case, Resource check will be verified - /// - public StorSimpleCmdletBase() : this(true) { } - - /// - /// constructor variant if you want to suppress the resource check for your commandlet - /// - /// - public StorSimpleCmdletBase(bool performResourceCheck):base() - { - verifyResourceBeforeCmdletExecute = performResourceCheck; - } - - private StorSimpleClient storSimpleClient; - - internal StorSimpleClient StorSimpleClient - { - get - { - if (this.storSimpleClient == null) - { - this.storSimpleClient = new StorSimpleClient(Profile, Profile.Context.Subscription); - } - storSimpleClient.ClientRequestId = Guid.NewGuid().ToString("D") + "_PS"; - WriteVerbose(string.Format(Resources.ClientRequestIdMessage, storSimpleClient.ClientRequestId)); - return this.storSimpleClient; - } - } - - internal virtual void HandleAsyncTaskResponse(AzureOperationResponse opResponse, string operationName) - { - string msg = string.Empty; - - if (opResponse.StatusCode != HttpStatusCode.Accepted && opResponse.StatusCode != HttpStatusCode.OK) - { - msg = string.Format(Resources.FailureMessageSubmitTask, operationName); - } - - else - { - if (opResponse.GetType().Equals(typeof(TaskResponse))) - { - var taskResponse = opResponse as TaskResponse; - msg = string.Format(Resources.SuccessMessageSubmitTask, operationName, taskResponse.TaskId); - WriteObject(taskResponse.TaskId); - } - - else if (opResponse.GetType().Equals(typeof(GuidTaskResponse))) - { - var guidTaskResponse = opResponse as GuidTaskResponse; - msg = string.Format(Resources.SuccessMessageSubmitTask, operationName, guidTaskResponse.TaskId); - WriteObject(guidTaskResponse.TaskId); - } - } - - WriteVerbose(msg); - } - - internal virtual void HandleDeviceJobResponse(JobResponse jobResponse, string operationName) - { - string msg = string.Format(Resources.SuccessMessageSubmitDeviceJob, operationName, jobResponse.JobId); - WriteObject(jobResponse.JobId); - WriteVerbose(msg); - } - - internal virtual void HandleSyncTaskResponse(TaskStatusInfo taskStatus, string operationName) - { - string msg = string.Empty; - TaskReport taskReport = new TaskReport(taskStatus); - - if (taskStatus.AsyncTaskAggregatedResult != AsyncTaskAggregatedResult.Succeeded) - { - msg = string.Format(Resources.FailureMessageCompleteJob, operationName); - WriteObject(taskReport); - } - - else - { - msg = string.Format(Resources.SuccessMessageCompleteJob, operationName); - WriteObject(taskReport); - } - - WriteVerbose(msg); - } - - private static void StripNamespaces(XDocument doc) - { - var elements = doc.Descendants(); - elements.Attributes().Where(attr => attr.IsNamespaceDeclaration).Remove(); - foreach (var element in elements) - { - element.Name = element.Name.LocalName; - } - } - - internal virtual void HandleException(Exception exception) - { - ErrorRecord errorRecord = null; - var ex = exception; - do - { - Type exType = ex.GetType(); - if(exType == typeof(CloudException)) - { - var cloudEx = ex as CloudException; - if (cloudEx == null) - break; - var response = cloudEx.Response; - try - { + public class StorSimpleCmdletBase : AzurePSCmdlet + { + //this property will determine whether before running the actual commandlet logic, should resource selection be verified + protected bool verifyResourceBeforeCmdletExecute; + + /// + /// default constructor for most commandlets. In this case, Resource check will be verified + /// + public StorSimpleCmdletBase() : this(true) { } + + /// + /// constructor variant if you want to suppress the resource check for your commandlet + /// + /// + public StorSimpleCmdletBase(bool performResourceCheck):base() + { + verifyResourceBeforeCmdletExecute = performResourceCheck; + } + + private StorSimpleClient storSimpleClient; + + internal StorSimpleClient StorSimpleClient + { + get + { + if (this.storSimpleClient == null) + { + this.storSimpleClient = new StorSimpleClient(Profile, Profile.Context.Subscription); + } + storSimpleClient.ClientRequestId = Guid.NewGuid().ToString("D") + "_PS"; + WriteVerbose(string.Format(Resources.ClientRequestIdMessage, storSimpleClient.ClientRequestId)); + return this.storSimpleClient; + } + } + + internal virtual void HandleAsyncTaskResponse(AzureOperationResponse opResponse, string operationName) + { + string msg = string.Empty; + + if (opResponse.StatusCode != HttpStatusCode.Accepted && opResponse.StatusCode != HttpStatusCode.OK) + { + msg = string.Format(Resources.FailureMessageSubmitTask, operationName); + } + + else + { + if (opResponse.GetType().Equals(typeof(TaskResponse))) + { + var taskResponse = opResponse as TaskResponse; + msg = string.Format(Resources.SuccessMessageSubmitTask, operationName, taskResponse.TaskId); + WriteObject(taskResponse.TaskId); + } + + else if (opResponse.GetType().Equals(typeof(GuidTaskResponse))) + { + var guidTaskResponse = opResponse as GuidTaskResponse; + msg = string.Format(Resources.SuccessMessageSubmitTask, operationName, guidTaskResponse.TaskId); + WriteObject(guidTaskResponse.TaskId); + } + } + + WriteVerbose(msg); + } + + internal virtual void HandleDeviceJobResponse(JobResponse jobResponse, string operationName) + { + string msg = string.Format(Resources.SuccessMessageSubmitDeviceJob, operationName, jobResponse.JobId); + WriteObject(jobResponse.JobId); + WriteVerbose(msg); + } + + internal virtual void HandleSyncTaskResponse(TaskStatusInfo taskStatus, string operationName) + { + string msg = string.Empty; + TaskReport taskReport = new TaskReport(taskStatus); + + if (taskStatus.AsyncTaskAggregatedResult != AsyncTaskAggregatedResult.Succeeded) + { + msg = string.Format(Resources.FailureMessageCompleteJob, operationName); + WriteObject(taskReport); + } + + else + { + msg = string.Format(Resources.SuccessMessageCompleteJob, operationName); + WriteObject(taskReport); + } + + WriteVerbose(msg); + } + + private static void StripNamespaces(XDocument doc) + { + var elements = doc.Descendants(); + elements.Attributes().Where(attr => attr.IsNamespaceDeclaration).Remove(); + foreach (var element in elements) + { + element.Name = element.Name.LocalName; + } + } + + internal virtual void HandleException(Exception exception) + { + ErrorRecord errorRecord = null; + var ex = exception; + do + { + Type exType = ex.GetType(); + if(exType == typeof(CloudException)) + { + var cloudEx = ex as CloudException; + if (cloudEx == null) + break; + var response = cloudEx.Response; + try + { if (response.StatusCode == HttpStatusCode.NotFound) { - var notAvailableException = new Exception(Resources.NotFoundWebExceptionMessage); - errorRecord = new ErrorRecord(notAvailableException, string.Empty, ErrorCategory.InvalidOperation, null); - break; + var notAvailableException = new Exception(Resources.NotFoundWebExceptionMessage); + errorRecord = new ErrorRecord(notAvailableException, string.Empty, ErrorCategory.InvalidOperation, null); + break; } else { - XDocument xDoc = XDocument.Parse(response.Content); - StripNamespaces(xDoc); - string cloudErrorCode = xDoc.Descendants("ErrorCode").FirstOrDefault().Value; - WriteVerbose(string.Format(Resources.CloudExceptionMessage, cloudErrorCode)); - } + XDocument xDoc = XDocument.Parse(response.Content); + StripNamespaces(xDoc); + string cloudErrorCode = xDoc.Descendants("ErrorCode").FirstOrDefault().Value; + WriteVerbose(string.Format(Resources.CloudExceptionMessage, cloudErrorCode)); + } } - catch (Exception) - { - - } - - errorRecord = new ErrorRecord(cloudEx, string.Empty, ErrorCategory.InvalidOperation, null); - break; - } - else if(exType == typeof(WebException)) - { - var webEx = ex as WebException; - if (webEx == null) - break; - try - { - HttpWebResponse response = webEx.Response as HttpWebResponse; + catch (Exception) + { + + } + + errorRecord = new ErrorRecord(cloudEx, string.Empty, ErrorCategory.InvalidOperation, null); + break; + } + else if(exType == typeof(WebException)) + { + var webEx = ex as WebException; + if (webEx == null) + break; + try + { + HttpWebResponse response = webEx.Response as HttpWebResponse; WriteVerbose(string.Format(Resources.WebExceptionMessage, response.StatusCode)); - } - catch (Exception) - { - - } - errorRecord = new ErrorRecord(webEx, string.Empty, ErrorCategory.ConnectionError, null); - break; - } - else if (exType == typeof (FormatException)) - { - var formEx = ex as FormatException; - if (formEx == null) - break; - WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); - errorRecord = new ErrorRecord(formEx, string.Empty, ErrorCategory.InvalidData, null); - } - else if (exType == typeof(NullReferenceException)) - { - var nullEx = ex as NullReferenceException; - if (nullEx == null) - break; - WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); - errorRecord = new ErrorRecord(nullEx, string.Empty, ErrorCategory.InvalidData, null); - break; - } - else if (exType == typeof(ArgumentNullException)) - { - var argNullEx = ex as ArgumentNullException; - if (argNullEx == null) - break; - WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); - errorRecord = new ErrorRecord(argNullEx, string.Empty, ErrorCategory.InvalidData, null); - break; - } - else if (exType == typeof(ArgumentException)) - { - var argEx = ex as ArgumentException; - if (argEx == null) - break; - WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); - errorRecord = new ErrorRecord(argEx, string.Empty, ErrorCategory.InvalidData, null); - break; - } - ex = ex.InnerException; - } while (ex != null); - - if(errorRecord == null) - { - errorRecord = new ErrorRecord(exception, string.Empty, ErrorCategory.NotSpecified, null); - } - - WriteError(errorRecord); - } - - protected override void BeginProcessing() - { - base.BeginProcessing(); - if(verifyResourceBeforeCmdletExecute) - VerifyResourceContext(); - } - /// - /// this method verifies that a resource has been selected before this commandlet is executed - /// - private void VerifyResourceContext() - { - if (!CheckResourceContextPresent()) - { - throw GetGenericException(Resources.ResourceContextNotSetMessage, null); - } - } - - private bool CheckResourceContextPresent() - { - var resourceContext = StorSimpleClient.GetResourceContext(); - if (resourceContext == null - || string.IsNullOrEmpty(resourceContext.ResourceId) - || string.IsNullOrEmpty(resourceContext.ResourceName)) - { - return false; - } - return true; - } - - internal bool ValidStorageAccountCred(string storageAccountName, string storageAccountKey, string endpoint) - { - using (System.Management.Automation.PowerShell ps = System.Management.Automation.PowerShell.Create()) - { - bool valid = true; - Random rnd = new Random(); - string testContainerName = string.Format("storsimplesdkvalidation{0}", rnd.Next()); - //create a storage container and then delete it - string validateScript = string.Format( - @"$context = New-AzureStorageContext -StorageAccountName {0} -StorageAccountKey {1} -Endpoint {2};" - + @"New-AzureStorageContainer -Name {3} -Context $context;" - + @"Remove-AzureStorageContainer -Name {3} -Context $context -Force;", - storageAccountName, storageAccountKey, endpoint, testContainerName); - ps.AddScript(validateScript); - ps.Invoke(); - if (ps.HadErrors) - { - var exception = ps.Streams.Error[0].Exception; - string getScript = string.Format( - @"$context = New-AzureStorageContext -StorageAccountName {0} -StorageAccountKey {1};" - + @"Get-AzureStorageContainer -Name {2} -Context $context;", - storageAccountName, storageAccountKey, testContainerName); - ps.AddScript(getScript); - var result = ps.Invoke(); - if (result != null && result.Count > 0) - { - //storage container successfully created and still exists, retry deleting it - int retryCount = 1; - string removeScript = string.Format( - @"$context = New-AzureStorageContext -StorageAccountName {0} -StorageAccountKey {1};" - + @"Remove-AzureStorageContainer -Name {2} -Context $context -Force;", - storageAccountName, storageAccountKey, testContainerName); - do - { - WriteVerbose(string.Format(Resources.StorageAccountCleanupRetryMessage, retryCount)); - ps.AddScript(removeScript); - ps.Invoke(); - Thread.Sleep(retryCount * 1000); - ps.AddScript(getScript); - result = ps.Invoke(); - } while (result != null && result.Count > 0 && ++retryCount <= 5); - } - else - { - valid = false; - HandleException(exception); - } - } - return valid; - } - } - - - internal string GetStorageAccountLocation(string storageAccountName, out bool exist) - { - using (System.Management.Automation.PowerShell ps = System.Management.Automation.PowerShell.Create()) - { - string location = null; - exist = false; - - string script = string.Format(@"Get-AzureStorageAccount -StorageAccountName {0}", storageAccountName); - ps.AddScript(script); - var result = ps.Invoke(); - - if (ps.HadErrors) - { - HandleException(ps.Streams.Error[0].Exception); - WriteVerbose(string.Format(Resources.StorageAccountNotFoundMessage, storageAccountName)); - } - - if (result != null && result.Count > 0) - { - exist = true; - WriteVerbose(string.Format(Resources.StorageAccountFoundMessage, storageAccountName)); - script = string.Format(@"Get-AzureStorageAccount -StorageAccountName {0}" - + @"| Select-Object -ExpandProperty Location", storageAccountName); - ps.AddScript(script); - result = ps.Invoke(); - if (ps.HadErrors) - { - HandleException(ps.Streams.Error[0].Exception); - } - if (result.Count > 0) - { - location = result[0].ToString(); - } - } - return location; - } - } - - internal bool ValidateAndEncryptStorageCred(string name, string key, string endpoint, out string encryptedKey, out string thumbprint) - { - StorSimpleCryptoManager storSimpleCryptoManager = new StorSimpleCryptoManager(StorSimpleClient); - thumbprint = storSimpleCryptoManager.GetSecretsEncryptionThumbprint(); - encryptedKey = null; - if (!string.IsNullOrEmpty(key)) - { - //validate storage account credentials - if (!ValidStorageAccountCred(name, key, endpoint)) - { - WriteVerbose(Resources.StorageCredentialVerificationFailureMessage); - return false; - } - WriteVerbose(Resources.StorageCredentialVerificationSuccessMessage); - WriteVerbose(Resources.EncryptionInProgressMessage); - storSimpleCryptoManager.EncryptSecretWithRakPub(key, out encryptedKey); - } - return true; - } - - /// - /// Helper method to determine if this device has already been configured or not - /// - /// - public bool IsDeviceConfigurationCompleteForDevice(DeviceDetails details) - { - bool data0Configured = false; - - if (details.NetInterfaceList != null) - { - NetInterface data0 = details.NetInterfaceList.Where(x => x.InterfaceId == NetInterfaceId.Data0).ToList().First(); - if (data0 != null - && data0.IsEnabled - && data0.NicIPv4Settings != null - && !string.IsNullOrEmpty(data0.NicIPv4Settings.Controller0IPv4Address)) - data0Configured = true; - } - return data0Configured; - } + } + catch (Exception) + { + + } + errorRecord = new ErrorRecord(webEx, string.Empty, ErrorCategory.ConnectionError, null); + break; + } + else if (exType == typeof (FormatException)) + { + var formEx = ex as FormatException; + if (formEx == null) + break; + WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); + errorRecord = new ErrorRecord(formEx, string.Empty, ErrorCategory.InvalidData, null); + } + else if (exType == typeof(NullReferenceException)) + { + var nullEx = ex as NullReferenceException; + if (nullEx == null) + break; + WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); + errorRecord = new ErrorRecord(nullEx, string.Empty, ErrorCategory.InvalidData, null); + break; + } + else if (exType == typeof(ArgumentNullException)) + { + var argNullEx = ex as ArgumentNullException; + if (argNullEx == null) + break; + WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); + errorRecord = new ErrorRecord(argNullEx, string.Empty, ErrorCategory.InvalidData, null); + break; + } + else if (exType == typeof(ArgumentException)) + { + var argEx = ex as ArgumentException; + if (argEx == null) + break; + WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); + errorRecord = new ErrorRecord(argEx, string.Empty, ErrorCategory.InvalidData, null); + break; + } + ex = ex.InnerException; + } while (ex != null); + + if(errorRecord == null) + { + errorRecord = new ErrorRecord(exception, string.Empty, ErrorCategory.NotSpecified, null); + } + + WriteError(errorRecord); + } + + protected override void BeginProcessing() + { + base.BeginProcessing(); + if(verifyResourceBeforeCmdletExecute) + VerifyResourceContext(); + } + /// + /// this method verifies that a resource has been selected before this commandlet is executed + /// + private void VerifyResourceContext() + { + if (!CheckResourceContextPresent()) + { + throw GetGenericException(Resources.ResourceContextNotSetMessage, null); + } + } + + private bool CheckResourceContextPresent() + { + var resourceContext = StorSimpleClient.GetResourceContext(); + if (resourceContext == null + || string.IsNullOrEmpty(resourceContext.ResourceId) + || string.IsNullOrEmpty(resourceContext.ResourceName)) + { + return false; + } + return true; + } + + internal bool ValidStorageAccountCred(string storageAccountName, string storageAccountKey, string endpoint) + { + using (System.Management.Automation.PowerShell ps = System.Management.Automation.PowerShell.Create()) + { + bool valid = true; + Random rnd = new Random(); + string testContainerName = string.Format("storsimplesdkvalidation{0}", rnd.Next()); + //create a storage container and then delete it + string validateScript = string.Format( + @"$context = New-AzureStorageContext -StorageAccountName {0} -StorageAccountKey {1} -Endpoint {2};" + + @"New-AzureStorageContainer -Name {3} -Context $context;" + + @"Remove-AzureStorageContainer -Name {3} -Context $context -Force;", + storageAccountName, storageAccountKey, endpoint, testContainerName); + ps.AddScript(validateScript); + ps.Invoke(); + if (ps.HadErrors) + { + var exception = ps.Streams.Error[0].Exception; + string getScript = string.Format( + @"$context = New-AzureStorageContext -StorageAccountName {0} -StorageAccountKey {1};" + + @"Get-AzureStorageContainer -Name {2} -Context $context;", + storageAccountName, storageAccountKey, testContainerName); + ps.AddScript(getScript); + var result = ps.Invoke(); + if (result != null && result.Count > 0) + { + //storage container successfully created and still exists, retry deleting it + int retryCount = 1; + string removeScript = string.Format( + @"$context = New-AzureStorageContext -StorageAccountName {0} -StorageAccountKey {1};" + + @"Remove-AzureStorageContainer -Name {2} -Context $context -Force;", + storageAccountName, storageAccountKey, testContainerName); + do + { + WriteVerbose(string.Format(Resources.StorageAccountCleanupRetryMessage, retryCount)); + ps.AddScript(removeScript); + ps.Invoke(); + Thread.Sleep(retryCount * 1000); + ps.AddScript(getScript); + result = ps.Invoke(); + } while (result != null && result.Count > 0 && ++retryCount <= 5); + } + else + { + valid = false; + HandleException(exception); + } + } + return valid; + } + } + + + internal string GetStorageAccountLocation(string storageAccountName, out bool exist) + { + using (System.Management.Automation.PowerShell ps = System.Management.Automation.PowerShell.Create()) + { + string location = null; + exist = false; + + string script = string.Format(@"Get-AzureStorageAccount -StorageAccountName {0}", storageAccountName); + ps.AddScript(script); + var result = ps.Invoke(); + + if (ps.HadErrors) + { + HandleException(ps.Streams.Error[0].Exception); + WriteVerbose(string.Format(Resources.StorageAccountNotFoundMessage, storageAccountName)); + } + + if (result != null && result.Count > 0) + { + exist = true; + WriteVerbose(string.Format(Resources.StorageAccountFoundMessage, storageAccountName)); + script = string.Format(@"Get-AzureStorageAccount -StorageAccountName {0}" + + @"| Select-Object -ExpandProperty Location", storageAccountName); + ps.AddScript(script); + result = ps.Invoke(); + if (ps.HadErrors) + { + HandleException(ps.Streams.Error[0].Exception); + } + if (result.Count > 0) + { + location = result[0].ToString(); + } + } + return location; + } + } + + internal bool ValidateAndEncryptStorageCred(string name, string key, string endpoint, out string encryptedKey, out string thumbprint) + { + StorSimpleCryptoManager storSimpleCryptoManager = new StorSimpleCryptoManager(StorSimpleClient); + thumbprint = storSimpleCryptoManager.GetSecretsEncryptionThumbprint(); + encryptedKey = null; + if (!string.IsNullOrEmpty(key)) + { + //validate storage account credentials + if (!ValidStorageAccountCred(name, key, endpoint)) + { + WriteVerbose(Resources.StorageCredentialVerificationFailureMessage); + return false; + } + WriteVerbose(Resources.StorageCredentialVerificationSuccessMessage); + WriteVerbose(Resources.EncryptionInProgressMessage); + storSimpleCryptoManager.EncryptSecretWithRakPub(key, out encryptedKey); + } + return true; + } + + /// + /// Helper method to determine if this device has already been configured or not + /// + /// + public bool IsDeviceConfigurationCompleteForDevice(DeviceDetails details) + { + bool data0Configured = false; + + if (details.NetInterfaceList != null) + { + NetInterface data0 = details.NetInterfaceList.Where(x => x.InterfaceId == NetInterfaceId.Data0).ToList().First(); + if (data0 != null + && data0.IsEnabled + && data0.NicIPv4Settings != null + && !string.IsNullOrEmpty(data0.NicIPv4Settings.Controller0IPv4Address)) + data0Configured = true; + } + return data0Configured; + } - /// - /// this method verifies that the devicename parameter specified is completely configured - /// most operations are not allowed on a non-configured device - /// - public void VerifyDeviceConfigurationCompleteForDevice(string deviceId) - { - var details = storSimpleClient.GetDeviceDetails(deviceId); - var data0Configured = IsDeviceConfigurationCompleteForDevice(details); - if (!data0Configured) - throw GetGenericException(Resources.DeviceNotConfiguredMessage, null); - } - - internal string GetHostnameFromEndpoint(string endpoint) - { - return string.Format("blob.{0}", endpoint); - } - - internal string GetEndpointFromHostname(string hostname) - { - return hostname.Substring(hostname.IndexOf('.') + 1); - } - - internal Exception GetGenericException(string exceptionMessage, Exception innerException) - { - return new Exception(exceptionMessage, innerException); - } - - /// - /// Validate that all network configs are valid. - /// - /// Its mandatory to provide either (IPv4 Address and netmask) or IPv6 orefix for an interface that - /// is being enabled. ( Was previously disabled and is now being configured) - /// - internal void ValidateNetworkConfigs(DeviceDetails details, NetworkConfig[] StorSimpleNetworkConfig) - { - if (StorSimpleNetworkConfig == null) - { - return; - } - foreach (var netConfig in StorSimpleNetworkConfig) - { - // get corresponding netInterface in device details. - var netInterface = details.NetInterfaceList.FirstOrDefault(x => x.InterfaceId == netConfig.InterfaceAlias); - // If its being enabled and its not Data0, it must have IP Address info - if (netInterface == null || (netInterface.InterfaceId != NetInterfaceId.Data0 && !netInterface.IsEnabled)) - { - // If its not an enabled interface either IPv6(prefix) or IPv4(address and mask) must be provided. - if ((netConfig.IPv4Address == null || netConfig.IPv4Netmask == null) && netConfig.IPv6Prefix == null) - { - throw new ArgumentException(string.Format(Resources.IPAddressesNotProvidedForNetInterfaceBeingEnabled, StorSimpleContext.ResourceName, details.DeviceProperties.DeviceId)); - } - } - } - } - - /// - /// Try to parse an IP Address from the provided string - /// - /// IP Address string - /// - /// Name of the param which is being processed (to be used for errors) - internal void TrySetIPAddress(string data, out IPAddress ipAddress, string paramName) - { - if (data == null) - { - ipAddress = null; - return; - } - try - { - ipAddress = IPAddress.Parse(data); - } - catch (FormatException) - { - ipAddress = null; - throw new ArgumentException(string.Format(Resources.InvalidIPAddressProvidedMessage, paramName)); - } - } - - /// - /// Validate that all mandatory data for the first Device Configuration has been provided. - /// - /// bool indicating whether all mandatory data is there or not. - internal bool ValidParamsForFirstDeviceConfiguration(NetworkConfig[] netConfigs, TimeZoneInfo timeZone, string secondaryDnsServer) - { - if (netConfigs == null) - { - return false; - } - // Make sure network config for Data0 has been provided with atleast Controller0 IP Address - var data0 = netConfigs.FirstOrDefault(x => x.InterfaceAlias == NetInterfaceId.Data0); - if (data0 == null || data0.Controller0IPv4Address == null || data0.Controller1IPv4Address == null) - { - return false; - } - // Timezone and Secondary Dns Server are also mandatory - if (timeZone == null || string.IsNullOrEmpty(secondaryDnsServer)) - { - return false; - } - - // There must be atleast one iscsi enabled net interface in the first config - var iscsiEnabledInterfacePresent = netConfigs.Any(x => x.IsIscsiEnabled == true); - if (!iscsiEnabledInterfacePresent) - { - return false; - } - - return true; - } - - /// - /// Validate that the target device is eligible for failover - /// - /// The source device identifier - /// The target device identifier - /// - internal bool ValidTargetDeviceForFailover(string sourceDeviceId, string targetDeviceId) - { - if (sourceDeviceId.Equals(targetDeviceId, StringComparison.InvariantCultureIgnoreCase)) - { - throw new ArgumentException(Resources.DeviceFailoverSourceAndTargetDeviceSameError); - } - - return true; - } - - internal bool IsValidAsciiString(string s) - { - return Regex.IsMatch(s, "[ -~]+"); - } - - /// - /// Validate that the string provided has length within the specified constraints. - /// - /// Throws an ArgumentException with the specified error message if the validation fails. - /// - /// string to be validated - /// minimum allowable length for the string - /// maximum allowable length for the string - /// error message for the exception raised in case of invalid data - internal void ValidateLength(string data, uint minLength, uint maxLength, string errorMessage) - { - if (data.Length < minLength || data.Length > maxLength) - { - throw new ArgumentException(errorMessage); - } - } - - /// - /// Most of the passwords in the device must contain 3 of the following: - /// - a lowercase character - /// - an uppercase character - /// - a number - /// - a special character - /// - /// Raises an ArgumentException with appropriate error message notifying the above - /// conditions when the validation fails. - /// - /// - internal void ValidatePasswordComplexity(string data, string passwordName) - { - string errorMessage = string.Format(Resources.PasswordCharacterCriteriaError, passwordName); - var criteriaFulfilled = 0; - // Regular expressions for lowercase letter, uppercase letter, digit and special char - // respectively - string[] criteriaRegexs = { ".*[a-z]", ".*[A-Z]", ".*\\d", ".*\\W" }; - - foreach(var regexStr in criteriaRegexs){ - // The static IsMatch method is supposed to use an Application-wide cache of compiled regexes - // and hence should save computation time (though not very significant because we are not doing tens of - // thousands of such tests) - if(Regex.IsMatch(data, regexStr)){ - criteriaFulfilled += 1; - } - } - - // If atleast 3 criteria have been fulfilled, then the password is complex enough - if(criteriaFulfilled < 3){ - throw new ArgumentException(errorMessage); - } - } - } + /// + /// this method verifies that the devicename parameter specified is completely configured + /// most operations are not allowed on a non-configured device + /// + public void VerifyDeviceConfigurationCompleteForDevice(string deviceId) + { + var details = storSimpleClient.GetDeviceDetails(deviceId); + var data0Configured = IsDeviceConfigurationCompleteForDevice(details); + if (!data0Configured) + throw GetGenericException(Resources.DeviceNotConfiguredMessage, null); + } + + internal string GetHostnameFromEndpoint(string endpoint) + { + return string.Format("blob.{0}", endpoint); + } + + internal string GetEndpointFromHostname(string hostname) + { + return hostname.Substring(hostname.IndexOf('.') + 1); + } + + internal Exception GetGenericException(string exceptionMessage, Exception innerException) + { + return new Exception(exceptionMessage, innerException); + } + + /// + /// Validate that all network configs are valid. + /// + /// Its mandatory to provide either (IPv4 Address and netmask) or IPv6 orefix for an interface that + /// is being enabled. ( Was previously disabled and is now being configured) + /// + internal void ValidateNetworkConfigs(DeviceDetails details, NetworkConfig[] StorSimpleNetworkConfig) + { + if (StorSimpleNetworkConfig == null) + { + return; + } + foreach (var netConfig in StorSimpleNetworkConfig) + { + // get corresponding netInterface in device details. + var netInterface = details.NetInterfaceList.FirstOrDefault(x => x.InterfaceId == netConfig.InterfaceAlias); + // If its being enabled and its not Data0, it must have IP Address info + if (netInterface == null || (netInterface.InterfaceId != NetInterfaceId.Data0 && !netInterface.IsEnabled)) + { + // If its not an enabled interface either IPv6(prefix) or IPv4(address and mask) must be provided. + if ((netConfig.IPv4Address == null || netConfig.IPv4Netmask == null) && netConfig.IPv6Prefix == null) + { + throw new ArgumentException(string.Format(Resources.IPAddressesNotProvidedForNetInterfaceBeingEnabled, StorSimpleContext.ResourceName, details.DeviceProperties.DeviceId)); + } + } + } + } + + /// + /// Try to parse an IP Address from the provided string + /// + /// IP Address string + /// + /// Name of the param which is being processed (to be used for errors) + internal void TrySetIPAddress(string data, out IPAddress ipAddress, string paramName) + { + if (data == null) + { + ipAddress = null; + return; + } + try + { + ipAddress = IPAddress.Parse(data); + } + catch (FormatException) + { + ipAddress = null; + throw new ArgumentException(string.Format(Resources.InvalidIPAddressProvidedMessage, paramName)); + } + } + + /// + /// Validate that all mandatory data for the first Device Configuration has been provided. + /// + /// bool indicating whether all mandatory data is there or not. + internal bool ValidParamsForFirstDeviceConfiguration(NetworkConfig[] netConfigs, TimeZoneInfo timeZone, string secondaryDnsServer) + { + if (netConfigs == null) + { + return false; + } + // Make sure network config for Data0 has been provided with atleast Controller0 IP Address + var data0 = netConfigs.FirstOrDefault(x => x.InterfaceAlias == NetInterfaceId.Data0); + if (data0 == null || data0.Controller0IPv4Address == null || data0.Controller1IPv4Address == null) + { + return false; + } + // Timezone and Secondary Dns Server are also mandatory + if (timeZone == null || string.IsNullOrEmpty(secondaryDnsServer)) + { + return false; + } + + // There must be atleast one iscsi enabled net interface in the first config + var iscsiEnabledInterfacePresent = netConfigs.Any(x => x.IsIscsiEnabled == true); + if (!iscsiEnabledInterfacePresent) + { + return false; + } + + return true; + } + + /// + /// Validate that the target device is eligible for failover + /// + /// The source device identifier + /// The target device identifier + /// + internal bool ValidTargetDeviceForFailover(string sourceDeviceId, string targetDeviceId) + { + if (sourceDeviceId.Equals(targetDeviceId, StringComparison.InvariantCultureIgnoreCase)) + { + throw new ArgumentException(Resources.DeviceFailoverSourceAndTargetDeviceSameError); + } + + return true; + } + + internal bool IsValidAsciiString(string s) + { + return Regex.IsMatch(s, "[ -~]+"); + } + + /// + /// Validate that the string provided has length within the specified constraints. + /// + /// Throws an ArgumentException with the specified error message if the validation fails. + /// + /// string to be validated + /// minimum allowable length for the string + /// maximum allowable length for the string + /// error message for the exception raised in case of invalid data + internal void ValidateLength(string data, uint minLength, uint maxLength, string errorMessage) + { + if (data.Length < minLength || data.Length > maxLength) + { + throw new ArgumentException(errorMessage); + } + } + + /// + /// Most of the passwords in the device must contain 3 of the following: + /// - a lowercase character + /// - an uppercase character + /// - a number + /// - a special character + /// + /// Raises an ArgumentException with appropriate error message notifying the above + /// conditions when the validation fails. + /// + /// + internal void ValidatePasswordComplexity(string data, string passwordName) + { + string errorMessage = string.Format(Resources.PasswordCharacterCriteriaError, passwordName); + var criteriaFulfilled = 0; + // Regular expressions for lowercase letter, uppercase letter, digit and special char + // respectively + string[] criteriaRegexs = { ".*[a-z]", ".*[A-Z]", ".*\\d", ".*\\W" }; + + foreach(var regexStr in criteriaRegexs){ + // The static IsMatch method is supposed to use an Application-wide cache of compiled regexes + // and hence should save computation time (though not very significant because we are not doing tens of + // thousands of such tests) + if(Regex.IsMatch(data, regexStr)){ + criteriaFulfilled += 1; + } + } + + // If atleast 3 criteria have been fulfilled, then the password is complex enough + if(criteriaFulfilled < 3){ + throw new ArgumentException(errorMessage); + } + } + } } \ No newline at end of file From 3ebf27562fbef4849db76d799cbd47414c7bf48a Mon Sep 17 00:00:00 2001 From: Sankaranarayanan Mahadevan Date: Wed, 8 Apr 2015 17:18:02 +0530 Subject: [PATCH 9/9] Fixing spacing. Using spaces instead of tabs. --- .../StorSimpleCmdletBase.cs | 1088 ++++++++--------- 1 file changed, 544 insertions(+), 544 deletions(-) diff --git a/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs b/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs index e56bca49975d..68e62580078d 100644 --- a/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs +++ b/src/ServiceManagement/StorSimple/Commands.StorSimple/StorSimpleCmdletBase.cs @@ -29,548 +29,548 @@ namespace Microsoft.WindowsAzure.Commands.StorSimple { - public class StorSimpleCmdletBase : AzurePSCmdlet - { - //this property will determine whether before running the actual commandlet logic, should resource selection be verified - protected bool verifyResourceBeforeCmdletExecute; - - /// - /// default constructor for most commandlets. In this case, Resource check will be verified - /// - public StorSimpleCmdletBase() : this(true) { } - - /// - /// constructor variant if you want to suppress the resource check for your commandlet - /// - /// - public StorSimpleCmdletBase(bool performResourceCheck):base() - { - verifyResourceBeforeCmdletExecute = performResourceCheck; - } - - private StorSimpleClient storSimpleClient; - - internal StorSimpleClient StorSimpleClient - { - get - { - if (this.storSimpleClient == null) - { - this.storSimpleClient = new StorSimpleClient(Profile, Profile.Context.Subscription); - } - storSimpleClient.ClientRequestId = Guid.NewGuid().ToString("D") + "_PS"; - WriteVerbose(string.Format(Resources.ClientRequestIdMessage, storSimpleClient.ClientRequestId)); - return this.storSimpleClient; - } - } - - internal virtual void HandleAsyncTaskResponse(AzureOperationResponse opResponse, string operationName) - { - string msg = string.Empty; - - if (opResponse.StatusCode != HttpStatusCode.Accepted && opResponse.StatusCode != HttpStatusCode.OK) - { - msg = string.Format(Resources.FailureMessageSubmitTask, operationName); - } - - else - { - if (opResponse.GetType().Equals(typeof(TaskResponse))) - { - var taskResponse = opResponse as TaskResponse; - msg = string.Format(Resources.SuccessMessageSubmitTask, operationName, taskResponse.TaskId); - WriteObject(taskResponse.TaskId); - } - - else if (opResponse.GetType().Equals(typeof(GuidTaskResponse))) - { - var guidTaskResponse = opResponse as GuidTaskResponse; - msg = string.Format(Resources.SuccessMessageSubmitTask, operationName, guidTaskResponse.TaskId); - WriteObject(guidTaskResponse.TaskId); - } - } - - WriteVerbose(msg); - } - - internal virtual void HandleDeviceJobResponse(JobResponse jobResponse, string operationName) - { - string msg = string.Format(Resources.SuccessMessageSubmitDeviceJob, operationName, jobResponse.JobId); - WriteObject(jobResponse.JobId); - WriteVerbose(msg); - } - - internal virtual void HandleSyncTaskResponse(TaskStatusInfo taskStatus, string operationName) - { - string msg = string.Empty; - TaskReport taskReport = new TaskReport(taskStatus); - - if (taskStatus.AsyncTaskAggregatedResult != AsyncTaskAggregatedResult.Succeeded) - { - msg = string.Format(Resources.FailureMessageCompleteJob, operationName); - WriteObject(taskReport); - } - - else - { - msg = string.Format(Resources.SuccessMessageCompleteJob, operationName); - WriteObject(taskReport); - } - - WriteVerbose(msg); - } - - private static void StripNamespaces(XDocument doc) - { - var elements = doc.Descendants(); - elements.Attributes().Where(attr => attr.IsNamespaceDeclaration).Remove(); - foreach (var element in elements) - { - element.Name = element.Name.LocalName; - } - } - - internal virtual void HandleException(Exception exception) - { - ErrorRecord errorRecord = null; - var ex = exception; - do - { - Type exType = ex.GetType(); - if(exType == typeof(CloudException)) - { - var cloudEx = ex as CloudException; - if (cloudEx == null) - break; - var response = cloudEx.Response; - try - { - if (response.StatusCode == HttpStatusCode.NotFound) - { - var notAvailableException = new Exception(Resources.NotFoundWebExceptionMessage); - errorRecord = new ErrorRecord(notAvailableException, string.Empty, ErrorCategory.InvalidOperation, null); - break; - } - else - { - XDocument xDoc = XDocument.Parse(response.Content); - StripNamespaces(xDoc); - string cloudErrorCode = xDoc.Descendants("ErrorCode").FirstOrDefault().Value; - WriteVerbose(string.Format(Resources.CloudExceptionMessage, cloudErrorCode)); - } - } - catch (Exception) - { - - } - - errorRecord = new ErrorRecord(cloudEx, string.Empty, ErrorCategory.InvalidOperation, null); - break; - } - else if(exType == typeof(WebException)) - { - var webEx = ex as WebException; - if (webEx == null) - break; - try - { - HttpWebResponse response = webEx.Response as HttpWebResponse; - WriteVerbose(string.Format(Resources.WebExceptionMessage, response.StatusCode)); - } - catch (Exception) - { - - } - errorRecord = new ErrorRecord(webEx, string.Empty, ErrorCategory.ConnectionError, null); - break; - } - else if (exType == typeof (FormatException)) - { - var formEx = ex as FormatException; - if (formEx == null) - break; - WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); - errorRecord = new ErrorRecord(formEx, string.Empty, ErrorCategory.InvalidData, null); - } - else if (exType == typeof(NullReferenceException)) - { - var nullEx = ex as NullReferenceException; - if (nullEx == null) - break; - WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); - errorRecord = new ErrorRecord(nullEx, string.Empty, ErrorCategory.InvalidData, null); - break; - } - else if (exType == typeof(ArgumentNullException)) - { - var argNullEx = ex as ArgumentNullException; - if (argNullEx == null) - break; - WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); - errorRecord = new ErrorRecord(argNullEx, string.Empty, ErrorCategory.InvalidData, null); - break; - } - else if (exType == typeof(ArgumentException)) - { - var argEx = ex as ArgumentException; - if (argEx == null) - break; - WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); - errorRecord = new ErrorRecord(argEx, string.Empty, ErrorCategory.InvalidData, null); - break; - } - ex = ex.InnerException; - } while (ex != null); - - if(errorRecord == null) - { - errorRecord = new ErrorRecord(exception, string.Empty, ErrorCategory.NotSpecified, null); - } - - WriteError(errorRecord); - } - - protected override void BeginProcessing() - { - base.BeginProcessing(); - if(verifyResourceBeforeCmdletExecute) - VerifyResourceContext(); - } - /// - /// this method verifies that a resource has been selected before this commandlet is executed - /// - private void VerifyResourceContext() - { - if (!CheckResourceContextPresent()) - { - throw GetGenericException(Resources.ResourceContextNotSetMessage, null); - } - } - - private bool CheckResourceContextPresent() - { - var resourceContext = StorSimpleClient.GetResourceContext(); - if (resourceContext == null - || string.IsNullOrEmpty(resourceContext.ResourceId) - || string.IsNullOrEmpty(resourceContext.ResourceName)) - { - return false; - } - return true; - } - - internal bool ValidStorageAccountCred(string storageAccountName, string storageAccountKey, string endpoint) - { - using (System.Management.Automation.PowerShell ps = System.Management.Automation.PowerShell.Create()) - { - bool valid = true; - Random rnd = new Random(); - string testContainerName = string.Format("storsimplesdkvalidation{0}", rnd.Next()); - //create a storage container and then delete it - string validateScript = string.Format( - @"$context = New-AzureStorageContext -StorageAccountName {0} -StorageAccountKey {1} -Endpoint {2};" - + @"New-AzureStorageContainer -Name {3} -Context $context;" - + @"Remove-AzureStorageContainer -Name {3} -Context $context -Force;", - storageAccountName, storageAccountKey, endpoint, testContainerName); - ps.AddScript(validateScript); - ps.Invoke(); - if (ps.HadErrors) - { - var exception = ps.Streams.Error[0].Exception; - string getScript = string.Format( - @"$context = New-AzureStorageContext -StorageAccountName {0} -StorageAccountKey {1};" - + @"Get-AzureStorageContainer -Name {2} -Context $context;", - storageAccountName, storageAccountKey, testContainerName); - ps.AddScript(getScript); - var result = ps.Invoke(); - if (result != null && result.Count > 0) - { - //storage container successfully created and still exists, retry deleting it - int retryCount = 1; - string removeScript = string.Format( - @"$context = New-AzureStorageContext -StorageAccountName {0} -StorageAccountKey {1};" - + @"Remove-AzureStorageContainer -Name {2} -Context $context -Force;", - storageAccountName, storageAccountKey, testContainerName); - do - { - WriteVerbose(string.Format(Resources.StorageAccountCleanupRetryMessage, retryCount)); - ps.AddScript(removeScript); - ps.Invoke(); - Thread.Sleep(retryCount * 1000); - ps.AddScript(getScript); - result = ps.Invoke(); - } while (result != null && result.Count > 0 && ++retryCount <= 5); - } - else - { - valid = false; - HandleException(exception); - } - } - return valid; - } - } - - - internal string GetStorageAccountLocation(string storageAccountName, out bool exist) - { - using (System.Management.Automation.PowerShell ps = System.Management.Automation.PowerShell.Create()) - { - string location = null; - exist = false; - - string script = string.Format(@"Get-AzureStorageAccount -StorageAccountName {0}", storageAccountName); - ps.AddScript(script); - var result = ps.Invoke(); - - if (ps.HadErrors) - { - HandleException(ps.Streams.Error[0].Exception); - WriteVerbose(string.Format(Resources.StorageAccountNotFoundMessage, storageAccountName)); - } - - if (result != null && result.Count > 0) - { - exist = true; - WriteVerbose(string.Format(Resources.StorageAccountFoundMessage, storageAccountName)); - script = string.Format(@"Get-AzureStorageAccount -StorageAccountName {0}" - + @"| Select-Object -ExpandProperty Location", storageAccountName); - ps.AddScript(script); - result = ps.Invoke(); - if (ps.HadErrors) - { - HandleException(ps.Streams.Error[0].Exception); - } - if (result.Count > 0) - { - location = result[0].ToString(); - } - } - return location; - } - } - - internal bool ValidateAndEncryptStorageCred(string name, string key, string endpoint, out string encryptedKey, out string thumbprint) - { - StorSimpleCryptoManager storSimpleCryptoManager = new StorSimpleCryptoManager(StorSimpleClient); - thumbprint = storSimpleCryptoManager.GetSecretsEncryptionThumbprint(); - encryptedKey = null; - if (!string.IsNullOrEmpty(key)) - { - //validate storage account credentials - if (!ValidStorageAccountCred(name, key, endpoint)) - { - WriteVerbose(Resources.StorageCredentialVerificationFailureMessage); - return false; - } - WriteVerbose(Resources.StorageCredentialVerificationSuccessMessage); - WriteVerbose(Resources.EncryptionInProgressMessage); - storSimpleCryptoManager.EncryptSecretWithRakPub(key, out encryptedKey); - } - return true; - } - - /// - /// Helper method to determine if this device has already been configured or not - /// - /// - public bool IsDeviceConfigurationCompleteForDevice(DeviceDetails details) - { - bool data0Configured = false; - - if (details.NetInterfaceList != null) - { - NetInterface data0 = details.NetInterfaceList.Where(x => x.InterfaceId == NetInterfaceId.Data0).ToList().First(); - if (data0 != null - && data0.IsEnabled - && data0.NicIPv4Settings != null - && !string.IsNullOrEmpty(data0.NicIPv4Settings.Controller0IPv4Address)) - data0Configured = true; - } - return data0Configured; - } - - /// - /// this method verifies that the devicename parameter specified is completely configured - /// most operations are not allowed on a non-configured device - /// - public void VerifyDeviceConfigurationCompleteForDevice(string deviceId) - { - var details = storSimpleClient.GetDeviceDetails(deviceId); - var data0Configured = IsDeviceConfigurationCompleteForDevice(details); - if (!data0Configured) - throw GetGenericException(Resources.DeviceNotConfiguredMessage, null); - } - - internal string GetHostnameFromEndpoint(string endpoint) - { - return string.Format("blob.{0}", endpoint); - } - - internal string GetEndpointFromHostname(string hostname) - { - return hostname.Substring(hostname.IndexOf('.') + 1); - } - - internal Exception GetGenericException(string exceptionMessage, Exception innerException) - { - return new Exception(exceptionMessage, innerException); - } - - /// - /// Validate that all network configs are valid. - /// - /// Its mandatory to provide either (IPv4 Address and netmask) or IPv6 orefix for an interface that - /// is being enabled. ( Was previously disabled and is now being configured) - /// - internal void ValidateNetworkConfigs(DeviceDetails details, NetworkConfig[] StorSimpleNetworkConfig) - { - if (StorSimpleNetworkConfig == null) - { - return; - } - foreach (var netConfig in StorSimpleNetworkConfig) - { - // get corresponding netInterface in device details. - var netInterface = details.NetInterfaceList.FirstOrDefault(x => x.InterfaceId == netConfig.InterfaceAlias); - // If its being enabled and its not Data0, it must have IP Address info - if (netInterface == null || (netInterface.InterfaceId != NetInterfaceId.Data0 && !netInterface.IsEnabled)) - { - // If its not an enabled interface either IPv6(prefix) or IPv4(address and mask) must be provided. - if ((netConfig.IPv4Address == null || netConfig.IPv4Netmask == null) && netConfig.IPv6Prefix == null) - { - throw new ArgumentException(string.Format(Resources.IPAddressesNotProvidedForNetInterfaceBeingEnabled, StorSimpleContext.ResourceName, details.DeviceProperties.DeviceId)); - } - } - } - } - - /// - /// Try to parse an IP Address from the provided string - /// - /// IP Address string - /// - /// Name of the param which is being processed (to be used for errors) - internal void TrySetIPAddress(string data, out IPAddress ipAddress, string paramName) - { - if (data == null) - { - ipAddress = null; - return; - } - try - { - ipAddress = IPAddress.Parse(data); - } - catch (FormatException) - { - ipAddress = null; - throw new ArgumentException(string.Format(Resources.InvalidIPAddressProvidedMessage, paramName)); - } - } - - /// - /// Validate that all mandatory data for the first Device Configuration has been provided. - /// - /// bool indicating whether all mandatory data is there or not. - internal bool ValidParamsForFirstDeviceConfiguration(NetworkConfig[] netConfigs, TimeZoneInfo timeZone, string secondaryDnsServer) - { - if (netConfigs == null) - { - return false; - } - // Make sure network config for Data0 has been provided with atleast Controller0 IP Address - var data0 = netConfigs.FirstOrDefault(x => x.InterfaceAlias == NetInterfaceId.Data0); - if (data0 == null || data0.Controller0IPv4Address == null || data0.Controller1IPv4Address == null) - { - return false; - } - // Timezone and Secondary Dns Server are also mandatory - if (timeZone == null || string.IsNullOrEmpty(secondaryDnsServer)) - { - return false; - } - - // There must be atleast one iscsi enabled net interface in the first config - var iscsiEnabledInterfacePresent = netConfigs.Any(x => x.IsIscsiEnabled == true); - if (!iscsiEnabledInterfacePresent) - { - return false; - } - - return true; - } - - /// - /// Validate that the target device is eligible for failover - /// - /// The source device identifier - /// The target device identifier - /// - internal bool ValidTargetDeviceForFailover(string sourceDeviceId, string targetDeviceId) - { - if (sourceDeviceId.Equals(targetDeviceId, StringComparison.InvariantCultureIgnoreCase)) - { - throw new ArgumentException(Resources.DeviceFailoverSourceAndTargetDeviceSameError); - } - - return true; - } - - internal bool IsValidAsciiString(string s) - { - return Regex.IsMatch(s, "[ -~]+"); - } - - /// - /// Validate that the string provided has length within the specified constraints. - /// - /// Throws an ArgumentException with the specified error message if the validation fails. - /// - /// string to be validated - /// minimum allowable length for the string - /// maximum allowable length for the string - /// error message for the exception raised in case of invalid data - internal void ValidateLength(string data, uint minLength, uint maxLength, string errorMessage) - { - if (data.Length < minLength || data.Length > maxLength) - { - throw new ArgumentException(errorMessage); - } - } - - /// - /// Most of the passwords in the device must contain 3 of the following: - /// - a lowercase character - /// - an uppercase character - /// - a number - /// - a special character - /// - /// Raises an ArgumentException with appropriate error message notifying the above - /// conditions when the validation fails. - /// - /// - internal void ValidatePasswordComplexity(string data, string passwordName) - { - string errorMessage = string.Format(Resources.PasswordCharacterCriteriaError, passwordName); - var criteriaFulfilled = 0; - // Regular expressions for lowercase letter, uppercase letter, digit and special char - // respectively - string[] criteriaRegexs = { ".*[a-z]", ".*[A-Z]", ".*\\d", ".*\\W" }; - - foreach(var regexStr in criteriaRegexs){ - // The static IsMatch method is supposed to use an Application-wide cache of compiled regexes - // and hence should save computation time (though not very significant because we are not doing tens of - // thousands of such tests) - if(Regex.IsMatch(data, regexStr)){ - criteriaFulfilled += 1; - } - } - - // If atleast 3 criteria have been fulfilled, then the password is complex enough - if(criteriaFulfilled < 3){ - throw new ArgumentException(errorMessage); - } - } - } + public class StorSimpleCmdletBase : AzurePSCmdlet + { + //this property will determine whether before running the actual commandlet logic, should resource selection be verified + protected bool verifyResourceBeforeCmdletExecute; + + /// + /// default constructor for most commandlets. In this case, Resource check will be verified + /// + public StorSimpleCmdletBase() : this(true) { } + + /// + /// constructor variant if you want to suppress the resource check for your commandlet + /// + /// + public StorSimpleCmdletBase(bool performResourceCheck):base() + { + verifyResourceBeforeCmdletExecute = performResourceCheck; + } + + private StorSimpleClient storSimpleClient; + + internal StorSimpleClient StorSimpleClient + { + get + { + if (this.storSimpleClient == null) + { + this.storSimpleClient = new StorSimpleClient(Profile, Profile.Context.Subscription); + } + storSimpleClient.ClientRequestId = Guid.NewGuid().ToString("D") + "_PS"; + WriteVerbose(string.Format(Resources.ClientRequestIdMessage, storSimpleClient.ClientRequestId)); + return this.storSimpleClient; + } + } + + internal virtual void HandleAsyncTaskResponse(AzureOperationResponse opResponse, string operationName) + { + string msg = string.Empty; + + if (opResponse.StatusCode != HttpStatusCode.Accepted && opResponse.StatusCode != HttpStatusCode.OK) + { + msg = string.Format(Resources.FailureMessageSubmitTask, operationName); + } + + else + { + if (opResponse.GetType().Equals(typeof(TaskResponse))) + { + var taskResponse = opResponse as TaskResponse; + msg = string.Format(Resources.SuccessMessageSubmitTask, operationName, taskResponse.TaskId); + WriteObject(taskResponse.TaskId); + } + + else if (opResponse.GetType().Equals(typeof(GuidTaskResponse))) + { + var guidTaskResponse = opResponse as GuidTaskResponse; + msg = string.Format(Resources.SuccessMessageSubmitTask, operationName, guidTaskResponse.TaskId); + WriteObject(guidTaskResponse.TaskId); + } + } + + WriteVerbose(msg); + } + + internal virtual void HandleDeviceJobResponse(JobResponse jobResponse, string operationName) + { + string msg = string.Format(Resources.SuccessMessageSubmitDeviceJob, operationName, jobResponse.JobId); + WriteObject(jobResponse.JobId); + WriteVerbose(msg); + } + + internal virtual void HandleSyncTaskResponse(TaskStatusInfo taskStatus, string operationName) + { + string msg = string.Empty; + TaskReport taskReport = new TaskReport(taskStatus); + + if (taskStatus.AsyncTaskAggregatedResult != AsyncTaskAggregatedResult.Succeeded) + { + msg = string.Format(Resources.FailureMessageCompleteJob, operationName); + WriteObject(taskReport); + } + + else + { + msg = string.Format(Resources.SuccessMessageCompleteJob, operationName); + WriteObject(taskReport); + } + + WriteVerbose(msg); + } + + private static void StripNamespaces(XDocument doc) + { + var elements = doc.Descendants(); + elements.Attributes().Where(attr => attr.IsNamespaceDeclaration).Remove(); + foreach (var element in elements) + { + element.Name = element.Name.LocalName; + } + } + + internal virtual void HandleException(Exception exception) + { + ErrorRecord errorRecord = null; + var ex = exception; + do + { + Type exType = ex.GetType(); + if(exType == typeof(CloudException)) + { + var cloudEx = ex as CloudException; + if (cloudEx == null) + break; + var response = cloudEx.Response; + try + { + if (response.StatusCode == HttpStatusCode.NotFound) + { + var notAvailableException = new Exception(Resources.NotFoundWebExceptionMessage); + errorRecord = new ErrorRecord(notAvailableException, string.Empty, ErrorCategory.InvalidOperation, null); + break; + } + else + { + XDocument xDoc = XDocument.Parse(response.Content); + StripNamespaces(xDoc); + string cloudErrorCode = xDoc.Descendants("ErrorCode").FirstOrDefault().Value; + WriteVerbose(string.Format(Resources.CloudExceptionMessage, cloudErrorCode)); + } + } + catch (Exception) + { + + } + + errorRecord = new ErrorRecord(cloudEx, string.Empty, ErrorCategory.InvalidOperation, null); + break; + } + else if(exType == typeof(WebException)) + { + var webEx = ex as WebException; + if (webEx == null) + break; + try + { + HttpWebResponse response = webEx.Response as HttpWebResponse; + WriteVerbose(string.Format(Resources.WebExceptionMessage, response.StatusCode)); + } + catch (Exception) + { + + } + errorRecord = new ErrorRecord(webEx, string.Empty, ErrorCategory.ConnectionError, null); + break; + } + else if (exType == typeof (FormatException)) + { + var formEx = ex as FormatException; + if (formEx == null) + break; + WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); + errorRecord = new ErrorRecord(formEx, string.Empty, ErrorCategory.InvalidData, null); + } + else if (exType == typeof(NullReferenceException)) + { + var nullEx = ex as NullReferenceException; + if (nullEx == null) + break; + WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); + errorRecord = new ErrorRecord(nullEx, string.Empty, ErrorCategory.InvalidData, null); + break; + } + else if (exType == typeof(ArgumentNullException)) + { + var argNullEx = ex as ArgumentNullException; + if (argNullEx == null) + break; + WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); + errorRecord = new ErrorRecord(argNullEx, string.Empty, ErrorCategory.InvalidData, null); + break; + } + else if (exType == typeof(ArgumentException)) + { + var argEx = ex as ArgumentException; + if (argEx == null) + break; + WriteVerbose(string.Format(Resources.InvalidInputMessage, ex.Message)); + errorRecord = new ErrorRecord(argEx, string.Empty, ErrorCategory.InvalidData, null); + break; + } + ex = ex.InnerException; + } while (ex != null); + + if(errorRecord == null) + { + errorRecord = new ErrorRecord(exception, string.Empty, ErrorCategory.NotSpecified, null); + } + + WriteError(errorRecord); + } + + protected override void BeginProcessing() + { + base.BeginProcessing(); + if(verifyResourceBeforeCmdletExecute) + VerifyResourceContext(); + } + /// + /// this method verifies that a resource has been selected before this commandlet is executed + /// + private void VerifyResourceContext() + { + if (!CheckResourceContextPresent()) + { + throw GetGenericException(Resources.ResourceContextNotSetMessage, null); + } + } + + private bool CheckResourceContextPresent() + { + var resourceContext = StorSimpleClient.GetResourceContext(); + if (resourceContext == null + || string.IsNullOrEmpty(resourceContext.ResourceId) + || string.IsNullOrEmpty(resourceContext.ResourceName)) + { + return false; + } + return true; + } + + internal bool ValidStorageAccountCred(string storageAccountName, string storageAccountKey, string endpoint) + { + using (System.Management.Automation.PowerShell ps = System.Management.Automation.PowerShell.Create()) + { + bool valid = true; + Random rnd = new Random(); + string testContainerName = string.Format("storsimplesdkvalidation{0}", rnd.Next()); + //create a storage container and then delete it + string validateScript = string.Format( + @"$context = New-AzureStorageContext -StorageAccountName {0} -StorageAccountKey {1} -Endpoint {2};" + + @"New-AzureStorageContainer -Name {3} -Context $context;" + + @"Remove-AzureStorageContainer -Name {3} -Context $context -Force;", + storageAccountName, storageAccountKey, endpoint, testContainerName); + ps.AddScript(validateScript); + ps.Invoke(); + if (ps.HadErrors) + { + var exception = ps.Streams.Error[0].Exception; + string getScript = string.Format( + @"$context = New-AzureStorageContext -StorageAccountName {0} -StorageAccountKey {1};" + + @"Get-AzureStorageContainer -Name {2} -Context $context;", + storageAccountName, storageAccountKey, testContainerName); + ps.AddScript(getScript); + var result = ps.Invoke(); + if (result != null && result.Count > 0) + { + //storage container successfully created and still exists, retry deleting it + int retryCount = 1; + string removeScript = string.Format( + @"$context = New-AzureStorageContext -StorageAccountName {0} -StorageAccountKey {1};" + + @"Remove-AzureStorageContainer -Name {2} -Context $context -Force;", + storageAccountName, storageAccountKey, testContainerName); + do + { + WriteVerbose(string.Format(Resources.StorageAccountCleanupRetryMessage, retryCount)); + ps.AddScript(removeScript); + ps.Invoke(); + Thread.Sleep(retryCount * 1000); + ps.AddScript(getScript); + result = ps.Invoke(); + } while (result != null && result.Count > 0 && ++retryCount <= 5); + } + else + { + valid = false; + HandleException(exception); + } + } + return valid; + } + } + + + internal string GetStorageAccountLocation(string storageAccountName, out bool exist) + { + using (System.Management.Automation.PowerShell ps = System.Management.Automation.PowerShell.Create()) + { + string location = null; + exist = false; + + string script = string.Format(@"Get-AzureStorageAccount -StorageAccountName {0}", storageAccountName); + ps.AddScript(script); + var result = ps.Invoke(); + + if (ps.HadErrors) + { + HandleException(ps.Streams.Error[0].Exception); + WriteVerbose(string.Format(Resources.StorageAccountNotFoundMessage, storageAccountName)); + } + + if (result != null && result.Count > 0) + { + exist = true; + WriteVerbose(string.Format(Resources.StorageAccountFoundMessage, storageAccountName)); + script = string.Format(@"Get-AzureStorageAccount -StorageAccountName {0}" + + @"| Select-Object -ExpandProperty Location", storageAccountName); + ps.AddScript(script); + result = ps.Invoke(); + if (ps.HadErrors) + { + HandleException(ps.Streams.Error[0].Exception); + } + if (result.Count > 0) + { + location = result[0].ToString(); + } + } + return location; + } + } + + internal bool ValidateAndEncryptStorageCred(string name, string key, string endpoint, out string encryptedKey, out string thumbprint) + { + StorSimpleCryptoManager storSimpleCryptoManager = new StorSimpleCryptoManager(StorSimpleClient); + thumbprint = storSimpleCryptoManager.GetSecretsEncryptionThumbprint(); + encryptedKey = null; + if (!string.IsNullOrEmpty(key)) + { + //validate storage account credentials + if (!ValidStorageAccountCred(name, key, endpoint)) + { + WriteVerbose(Resources.StorageCredentialVerificationFailureMessage); + return false; + } + WriteVerbose(Resources.StorageCredentialVerificationSuccessMessage); + WriteVerbose(Resources.EncryptionInProgressMessage); + storSimpleCryptoManager.EncryptSecretWithRakPub(key, out encryptedKey); + } + return true; + } + + /// + /// Helper method to determine if this device has already been configured or not + /// + /// + public bool IsDeviceConfigurationCompleteForDevice(DeviceDetails details) + { + bool data0Configured = false; + + if (details.NetInterfaceList != null) + { + NetInterface data0 = details.NetInterfaceList.Where(x => x.InterfaceId == NetInterfaceId.Data0).ToList().First(); + if (data0 != null + && data0.IsEnabled + && data0.NicIPv4Settings != null + && !string.IsNullOrEmpty(data0.NicIPv4Settings.Controller0IPv4Address)) + data0Configured = true; + } + return data0Configured; + } + + /// + /// this method verifies that the devicename parameter specified is completely configured + /// most operations are not allowed on a non-configured device + /// + public void VerifyDeviceConfigurationCompleteForDevice(string deviceId) + { + var details = storSimpleClient.GetDeviceDetails(deviceId); + var data0Configured = IsDeviceConfigurationCompleteForDevice(details); + if (!data0Configured) + throw GetGenericException(Resources.DeviceNotConfiguredMessage, null); + } + + internal string GetHostnameFromEndpoint(string endpoint) + { + return string.Format("blob.{0}", endpoint); + } + + internal string GetEndpointFromHostname(string hostname) + { + return hostname.Substring(hostname.IndexOf('.') + 1); + } + + internal Exception GetGenericException(string exceptionMessage, Exception innerException) + { + return new Exception(exceptionMessage, innerException); + } + + /// + /// Validate that all network configs are valid. + /// + /// Its mandatory to provide either (IPv4 Address and netmask) or IPv6 orefix for an interface that + /// is being enabled. ( Was previously disabled and is now being configured) + /// + internal void ValidateNetworkConfigs(DeviceDetails details, NetworkConfig[] StorSimpleNetworkConfig) + { + if (StorSimpleNetworkConfig == null) + { + return; + } + foreach (var netConfig in StorSimpleNetworkConfig) + { + // get corresponding netInterface in device details. + var netInterface = details.NetInterfaceList.FirstOrDefault(x => x.InterfaceId == netConfig.InterfaceAlias); + // If its being enabled and its not Data0, it must have IP Address info + if (netInterface == null || (netInterface.InterfaceId != NetInterfaceId.Data0 && !netInterface.IsEnabled)) + { + // If its not an enabled interface either IPv6(prefix) or IPv4(address and mask) must be provided. + if ((netConfig.IPv4Address == null || netConfig.IPv4Netmask == null) && netConfig.IPv6Prefix == null) + { + throw new ArgumentException(string.Format(Resources.IPAddressesNotProvidedForNetInterfaceBeingEnabled, StorSimpleContext.ResourceName, details.DeviceProperties.DeviceId)); + } + } + } + } + + /// + /// Try to parse an IP Address from the provided string + /// + /// IP Address string + /// + /// Name of the param which is being processed (to be used for errors) + internal void TrySetIPAddress(string data, out IPAddress ipAddress, string paramName) + { + if (data == null) + { + ipAddress = null; + return; + } + try + { + ipAddress = IPAddress.Parse(data); + } + catch (FormatException) + { + ipAddress = null; + throw new ArgumentException(string.Format(Resources.InvalidIPAddressProvidedMessage, paramName)); + } + } + + /// + /// Validate that all mandatory data for the first Device Configuration has been provided. + /// + /// bool indicating whether all mandatory data is there or not. + internal bool ValidParamsForFirstDeviceConfiguration(NetworkConfig[] netConfigs, TimeZoneInfo timeZone, string secondaryDnsServer) + { + if (netConfigs == null) + { + return false; + } + // Make sure network config for Data0 has been provided with atleast Controller0 IP Address + var data0 = netConfigs.FirstOrDefault(x => x.InterfaceAlias == NetInterfaceId.Data0); + if (data0 == null || data0.Controller0IPv4Address == null || data0.Controller1IPv4Address == null) + { + return false; + } + // Timezone and Secondary Dns Server are also mandatory + if (timeZone == null || string.IsNullOrEmpty(secondaryDnsServer)) + { + return false; + } + + // There must be atleast one iscsi enabled net interface in the first config + var iscsiEnabledInterfacePresent = netConfigs.Any(x => x.IsIscsiEnabled == true); + if (!iscsiEnabledInterfacePresent) + { + return false; + } + + return true; + } + + /// + /// Validate that the target device is eligible for failover + /// + /// The source device identifier + /// The target device identifier + /// + internal bool ValidTargetDeviceForFailover(string sourceDeviceId, string targetDeviceId) + { + if (sourceDeviceId.Equals(targetDeviceId, StringComparison.InvariantCultureIgnoreCase)) + { + throw new ArgumentException(Resources.DeviceFailoverSourceAndTargetDeviceSameError); + } + + return true; + } + + internal bool IsValidAsciiString(string s) + { + return Regex.IsMatch(s, "[ -~]+"); + } + + /// + /// Validate that the string provided has length within the specified constraints. + /// + /// Throws an ArgumentException with the specified error message if the validation fails. + /// + /// string to be validated + /// minimum allowable length for the string + /// maximum allowable length for the string + /// error message for the exception raised in case of invalid data + internal void ValidateLength(string data, uint minLength, uint maxLength, string errorMessage) + { + if (data.Length < minLength || data.Length > maxLength) + { + throw new ArgumentException(errorMessage); + } + } + + /// + /// Most of the passwords in the device must contain 3 of the following: + /// - a lowercase character + /// - an uppercase character + /// - a number + /// - a special character + /// + /// Raises an ArgumentException with appropriate error message notifying the above + /// conditions when the validation fails. + /// + /// + internal void ValidatePasswordComplexity(string data, string passwordName) + { + string errorMessage = string.Format(Resources.PasswordCharacterCriteriaError, passwordName); + var criteriaFulfilled = 0; + // Regular expressions for lowercase letter, uppercase letter, digit and special char + // respectively + string[] criteriaRegexs = { ".*[a-z]", ".*[A-Z]", ".*\\d", ".*\\W" }; + + foreach(var regexStr in criteriaRegexs){ + // The static IsMatch method is supposed to use an Application-wide cache of compiled regexes + // and hence should save computation time (though not very significant because we are not doing tens of + // thousands of such tests) + if(Regex.IsMatch(data, regexStr)){ + criteriaFulfilled += 1; + } + } + + // If atleast 3 criteria have been fulfilled, then the password is complex enough + if(criteriaFulfilled < 3){ + throw new ArgumentException(errorMessage); + } + } + } } \ No newline at end of file