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