#region Copyright
/*
* Copyright © 2014-2016 NetApp, Inc. All Rights Reserved.
*
* CONFIDENTIALITY NOTICE: THIS SOFTWARE CONTAINS CONFIDENTIAL INFORMATION OF
* NETAPP, INC. USE, DISCLOSURE OR REPRODUCTION IS PROHIBITED WITHOUT THE PRIOR
* EXPRESS WRITTEN PERMISSION OF NETAPP, INC.
*/
#endregion
#region Using Directives
using System;
using System.Collections;
using System.Collections.Generic;
using System.Management.Automation;
using SolidFire.Core.Helpers;
using System.Management.Automation.Runspaces;
using SolidFire.Core;
using SolidFire.Element.Api;
using SolidFire.Exceptions;
using ElementAccount = SolidFire.Element.Api.Account;
#endregion
namespace SolidFire.Volume.New
{
///
/// NewSFVolume is used to create a new (empty) volume on the cluster by
/// wrapping the CreateVolume API method. When the volume is created
/// successfully it is immediately available for use.
///
/// Volumes created without specified QoS values are created with the
/// default values listed in the Default QoS settings configured for a
/// cluster.
///
[Cmdlet(VerbsCommon.New, "SFVolume", DefaultParameterSetName = "q", ConfirmImpact = ConfirmImpact.Medium)]
public class NewSFVolume : SFCmdlet
{
#region Private Data
///
/// Member for saving the optional minimum iops setting. Implemented
/// as a nullable to help decide if the setting needs to be sent
/// to the api call as JSON data.
///
private int? minIOPS;
///
/// Member for saving the optional maximum iops setting. Implemented
/// as a nullable to help decide if the setting needs to be sent
/// to the api call as JSON data.
///
private int? maxIOPS;
///
/// Member for saving the optional burst iops setting. Implemented
/// as a nullable to help decide if the setting needs to be sent
/// to the api call as JSON data.
///
private int? burstIOPS;
private int? burstTime;
private int? qosPolicyID;
private long? accountID;
private ElementAccount account;
private bool? associateWithQoSPolicy;
private List processedIDs = new List();
private Pipeline pipeline;
#endregion
#region Parameters
///
/// Name of the volume.
///
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, HelpMessage = "Name of the volume access group")]
public String Name { get; set; }
///
/// Account id for the owner of volume.
///
[Parameter(Position = 1, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true,
HelpMessage = "Account ID for the owner of this volume")]
public long AccountID
{
get { return accountID ?? 0; }
set { accountID = value; }
}
///
/// Account information for the owner of the volume.
///
[Parameter(Position = 2, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, HelpMessage = "Account Information for the owner of this volume")]
public ElementAccount Account
{
get { return account; }
set
{
if (value == null) return;
account = value;
}
}
///
/// The volume needs to have 512e emulation enabled or not.
///
[Parameter(Mandatory = true, Position = 3, HelpMessage = "The volume provides 512-byte sector emulation")]
public bool Enable512e { get; set; }
///
/// Total size of the volume, in bytes. Size is rounded up to the nearest 1MB size.
/// This value interpretation can be in GB or GiB by using the GB or GiB switch.
///
[Parameter(Mandatory = true, Position = 4, HelpMessage = "Total size of the volume in GB")]
public Int64 TotalSize { get; set; }
///
/// Switch to specify interpreting the Total Size parameter as GiB instead of Bytes.
///
[Parameter(Mandatory = false, Position = 5, HelpMessage = "Switch used to interpret total size as GB")]
public SwitchParameter GB { get; set; }
///
/// Switch to specify interpreting the Total Size parameter as GiB instead of Bytes.
///
[Parameter(Mandatory = false, Position = 6, HelpMessage = "Switch used to interpret total size as GiB")]
public SwitchParameter GiB { get; set; }
///
/// Attributes to save with the volume.
///
[Parameter(Mandatory = false, Position = 7, HelpMessage = "Attributes to set")]
public Hashtable Attributes { get; set; }
///
/// Minimum iops to set for the volume.
///
[Parameter(Mandatory = false, Position = 8, HelpMessage = "The desired minimum 4KB IOPS to guarantee")]
[Parameter(ParameterSetName = "q")]
public int MinIOPS
{
get { return minIOPS ?? 100; }
set { minIOPS = value; }
}
///
/// Maximum iops to set for the volume.
///
[Parameter(Mandatory = false, Position = 9, HelpMessage = "The desired maximum 4KB IOPS to guarantee")]
[Parameter(ParameterSetName = "q")]
public int MaxIOPS
{
get { return maxIOPS ?? 15000; }
set { maxIOPS = value; }
}
///
/// Burst iops to set for the volume.
///
[Parameter(Mandatory = false, Position = 10, HelpMessage = "The maximum 4KB IOPS allowed for a short time")]
[Parameter(ParameterSetName = "q")]
public int BurstIOPS
{
get { return burstIOPS ?? 15000; }
set { burstIOPS = value; }
}
///
/// Burst iops to set for the volume.
///
[Parameter(Mandatory = false, Position = 11, HelpMessage = "The maximum 4KB IOPS allowed for a short time")]
[Parameter(ParameterSetName = "q")]
public int BurstTime
{
get { return burstTime ?? 0; }
set { burstTime = value; }
}
[Parameter(Mandatory = false, Position = 8,
HelpMessage = "The ID for the policy whose QoS settings should be applied to the specified volumes.")]
[Parameter(ParameterSetName = "p")]
public int QoSPolicyID
{
get { return qosPolicyID ?? 100; }
set { qosPolicyID = value; }
}
[Parameter(Mandatory = false, Position = 9, HelpMessage = "Associate the volume with the specified QoSPolicyID.")]
[Parameter(ParameterSetName = "p")]
public bool AssociateWithQoSPolicy
{
get { return associateWithQoSPolicy ?? true; }
set { associateWithQoSPolicy = value; }
}
#endregion
#region Cmdlet Overrides
///
/// Implementation for checking the status of the connection and
/// compatibility before allowing the cmdlet to continue.
///
protected override void BeginProcessing()
{
base.BeginProcessing();
pipeline = Runspace.DefaultRunspace.CreateNestedPipeline();
if (GB.IsPresent && GiB.IsPresent)
{
var errDetails = new ErrorDetails("GB and GiB are mutually exclusive switches");
var errRecord = new ErrorRecord(new ArgumentException(), errDetails.Message, ErrorCategory.InvalidArgument, this);
ThrowTerminatingError(errRecord);
}
CheckConnection();
}
protected override void EndProcessing()
{
base.EndProcessing();
if (processedIDs.Count > 0)
{
var command = new Command("Get-SFVolume");
command.Parameters.Add("VolumeID", processedIDs);
if (SFConnection != null)
{
command.Parameters.Add("SFConnection", SFConnection);
}
else if (Target != null)
{
command.Parameters.Add("Target", Target);
}
pipeline.Commands.Add(command);
WriteObject(pipeline.Invoke(), true);
processedIDs.Clear();
}
pipeline = null;
}
///
/// Implementation for processing the execution of the cmdlet.
///
protected override void ProcessRecord()
{
base.ProcessRecord();
// Assemble the QOS object
// Do not set default values if nothing has been set by the user
// to use the cluster default settings.
if (account != null)
{
accountID = account.AccountID;
}
if (account == null && AccountID == 0)
{
throw new ParameterException("Unable to determine AccountID. Please use -Account or -AccountID while running this CmdLet.");
}
var request = new CreateVolumeRequest
{
Name = Name,
AccountID = AccountID,
Enable512e = Enable512e,
TotalSize = TotalSize,
};
if (ParameterSetName == "q")
{
if (minIOPS.HasValue || maxIOPS.HasValue || burstIOPS.HasValue || burstTime.HasValue)
{
request.Qos = new QoS
{
MinIOPS = minIOPS,
MaxIOPS = maxIOPS,
BurstIOPS = burstIOPS,
BurstTime = burstTime
};
}
}
else
{
if (associateWithQoSPolicy.HasValue && !qosPolicyID.HasValue)
{
// no new QoSPolicyID or old QosPolicyID
var message = "Missing QosPolicyID. Unable to Associate with QoS Policy because there is no QoSPolicyID to use. Please supply on.";
var errRecord = new ErrorRecord(new VolumeException(message), message, ErrorCategory.InvalidData, this);
SolidFireUtilities.HandleError(errRecord, this);
}
request.QosPolicyID = qosPolicyID;
request.AssociateWithQoSPolicy = AssociateWithQoSPolicy;
}
if (GB.IsPresent)
{
request.TotalSize = request.TotalSize * Convert.ToInt64(Math.Pow(1000, 3));
}
if (GiB.IsPresent)
{
request.TotalSize = request.TotalSize * Convert.ToInt64(Math.Pow(1024, 3));
}
request.Attributes = Attributes;
// Send the request to create the volume.
var objsFromAPI = SendRequest("CreateVolume", request);
foreach (var obj in objsFromAPI)
{
// If there was not an error, save off the ID for writing to the output pipeline after processing.
processedIDs.Add(obj.Result.VolumeID);
}
}
#endregion
}
}