#region Copyright /* * Copyright © 2014-2016 NetApp, Inc. All Rights Reserved. * * CONFIDENTIALITY NOTICE: THIS SOFTWARE CONTAINS CONFIDENTIAL INFORMATION OF * NETAPP, INC. USE, DISCLOSURE OR REPRODUCTION IS PROHIBITED WITHOUT THE PRIOR * EXPRESS WRITTEN PERMISSION OF NETAPP, INC. */ #endregion #region Using Directives using System.ComponentModel; using System.Management.Automation; using SolidFire.Core; using SolidFire.Element.Api; using System.Collections; using System.Linq; using SolidFire.Core.Objects; using SolidFire.Exceptions; #endregion namespace SolidFire.Volume.Start { /// /// Start-SFVolumeRestore is used to initialize a bulk volume write session on a specified volume. /// Only two bulk volume processes can run simultaneously on a volume. When the session is initialized, /// data can be written to a SolidFire storage volume from an external backup source. The external data is accessed by a web server running on a SolidFire node. /// Communications and server interaction information for external data access is passed by a script running on the SolidFire storage system. /// [Cmdlet(VerbsLifecycle.Start, "SFVolumeRestore", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.High)] public class StartSFVolumeRestoree : SFCmdlet, IDynamicParameters { #region Private Data // Prepare the DynamicParameter classes so they're ready when Frequency is selected. private RestoreFromS3DynamicParameters _contextRestoreFromS3 = new RestoreFromS3DynamicParameters(); #endregion #region Parameters [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The ID of the volume to be read.")] public long VolumeID { get; set; } [Parameter(Position = 1, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The format of the volume data. Can be: uncompressed or native.")] [ValidateSet("uncompressed", "native", IgnoreCase = false)] public string Format { get; set; } [Parameter(Position = 2, Mandatory = true, HelpMessage = "The source of object data that was created from a previous backup. Can be: SolidFire, Swift, or S3.")] [ValidateSet("SolidFire", "Swift", "S3", IgnoreCase = false)] public string RestoreFrom { get; set; } #endregion #region Cmdlet Overrides protected override void BeginProcessing() { base.BeginProcessing(); CheckConnection(); } protected override void ProcessRecord() { base.ProcessRecord(); var request = new StartBulkVolumeWriteRequest() { VolumeID = VolumeID, Format = Format }; switch (RestoreFrom) { case "S3": _setS3Params(request); break; case "Swift": _setSwiftParams(request); break; } var objsFromAPI = SendRequest("StartBulkVolumeWrite", request); WriteObject(objsFromAPI.Select(obj => obj.Result), true); } #endregion private void _setSwiftParams(StartBulkVolumeWriteRequest request) { var ht = new Hashtable(); var rangeHt = new Hashtable(); rangeHt.Add("lba", 0); rangeHt.Add("blocks", 244224); ht.Add("range", rangeHt); var readHt = new Hashtable(); readHt.Add("endpoint", "swift"); readHt.Add("format", Format); ht.Add("read", readHt); request.Script = "bv_internal.py"; request.ScriptParameters = ht; } private void _setS3Params(StartBulkVolumeWriteRequest request) { var ht = new Hashtable(); var rangeHt = new Hashtable(); rangeHt.Add("lba", 0); rangeHt.Add("blocks", 244224); ht.Add("range", rangeHt); var readHt = new Hashtable(); readHt.Add("awsAccessKeyID", _contextRestoreFromS3.AccessKeyID); readHt.Add("awsSecretAccessKey", _contextRestoreFromS3.SecretAccessKey); readHt.Add("endpoint", "s3"); readHt.Add("format", Format); readHt.Add("hostname", _contextRestoreFromS3.Hostname); readHt.Add("bucket", _contextRestoreFromS3.Bucket); ht.Add("read", readHt); request.Script = "bv_internal.py"; request.ScriptParameters = ht; } /// /// Override the BeforeRequest method in SFCmdlet which is called immediately before a request is made to a specific connection. /// This offers the opportunity to set a parameter in the request object based on the connection. /// /// The request object that can be modified and is about to be used in the HttpRequest. This is passed by ref. /// The API method about to be called in the HttpRequest. This is passed by ref. /// The connection this request is about to be called on. public override void BeforeRequest(ref RpcBase request, ref string method, SFConnection connection) { // Make sure we're working with the proper request object. This should never fail but if it does, throw a RequestException. if (request is StartBulkVolumeWriteRequest) { var startBulkVolueWriteRequest = (StartBulkVolumeWriteRequest)request; // If restoring from S3 or Swift, we need to set the "prefix" value in the ScriptParameters Hashtable using information in the connection. if (RestoreFrom == "S3" || RestoreFrom == "Swift") { // Get the volume by VolumeID or throw a RequestException var activeRequest = new ListActiveVolumesRequest(); activeRequest.StartVolumeID = VolumeID; activeRequest.Limit = 1; var volume = SingleConnectionRequest("ListActiveVolumes", connection, activeRequest); if (volume.Result == null || volume.Result.Volumes.Count() != 1 || volume.Result.Volumes.First().VolumeID != VolumeID) { throw new RequestException(string.Format("Unable to find active volume for VolumeID: {0}", VolumeID)); } var volumeName = volume.Result.Volumes.First().Name; // Pull the "read" Hashtable from the ScriptParameters property in the request object or throw RequestException. var readHt = (Hashtable)startBulkVolueWriteRequest.ScriptParameters["read"]; if (readHt == null) { throw new RequestException("Improper mix of script parameters in 'restore from' request. Unable to find Hashtable 'read' in ScriptParameters Hashtable."); } // Set the prefix value in the read Hashtable using the connection name, volume name, and volume ID readHt.Add("prefix", string.Format("{0}/{1}-{2}", connection.Name, volumeName, VolumeID)); } } } /// /// This is necessary to implement IDynamicParameters. It hands back the corresponding parameter set /// based on the value in the RetoreFrom parameter. /// /// DynamicParameter class with parameters for the selected RestoreFrom value public object GetDynamicParameters() { if (RestoreFrom == "S3") { return _contextRestoreFromS3; } return null; } } }