#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.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Management.Automation;
using SolidFire.Core.Validation;
using System.Management.Automation.Runspaces;
using SolidFire.Core;
using SolidFire.Element.Api;
using System.Linq;
using System;
#endregion
namespace SolidFire.Volume.New
{
///
/// Used to create a schedule that will autonomously make a snapshot of a volume at a defined interval.
/// The snapshot created can be used later as a backup or rollback to ensure the data on a
/// volume or group of volumes is consistent for the point in time in which the snapshot was created.
/// Note: Creating a snapshot is allowed if cluster fullness is at stage 2 or 3.
/// Snapshots are not created when cluster fullness is at stage 4 or 5.
///
[Cmdlet(VerbsCommon.New, "SFSchedule")]
public class NewSFSchedule : SFCmdlet, IDynamicParameters
{
#region Private Data
private List _processedIDs;
private Pipeline _pipeline;
// Prepare the DynamicParameter classes so they're ready when Frequency is selected.
private TimeIntervalDynamicParameters _contextTimeInterval = new TimeIntervalDynamicParameters();
private DaysOfMonthDynamicParameters _contextDaysOfMonth = new DaysOfMonthDynamicParameters();
private DaysOfWeekDynamicParameters _contextDaysOfWeek = new DaysOfWeekDynamicParameters();
#endregion
#region Parameters
[Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, HelpMessage = "Volume IDs to be included in the resulting snapshots.")]
public long[] VolumeID { get; set; }
[Parameter(Position = 1, Mandatory = true, HelpMessage = "Unique name for the schedule.")]
public string ScheduleName { get; set; }
[Parameter(Position = 2, Mandatory = true, HelpMessage = "Used to indicate the frequency at which the snapshot will be made.")]
[ValidateSet("TimeInterval", "DaysOfWeek", "DaysOfMonth")]
public string Frequency { get; set; }
private bool? _paused;
[Parameter(Position = 8, Mandatory = false, HelpMessage = "Use to pause the schedule.")]
public bool Paused { get { return _paused.HasValue ? _paused.Value : false; } set { _paused = value; } }
[Parameter(Position = 9, Mandatory = false, HelpMessage = "Name of the new snapshot.")]
public string SnapshotName { get; set; }
private bool _recurring = true;
[Parameter(Position = 10, Mandatory = false, HelpMessage = "Indicates if the schedule will be recurring or not. Default is true.")]
public bool Recurring { get { return _recurring; } set { _recurring = value; } }
[Parameter(Position = 11, Mandatory = false, HelpMessage = " Include snapshots in replication when paired. Default is false.")]
public bool EnableRemoteReplication { get; set; }
private ulong? _retentionDays;
[Parameter(Position = 12, Mandatory = false, HelpMessage = "Number of days to retain snapshots created by this schedule.")]
public ulong RetentionDays { get { return _retentionDays.HasValue ? _retentionDays.Value : 0; } set { _retentionDays = value; } }
private ulong? _retentionHours;
[Parameter(Position = 13, Mandatory = false, HelpMessage = "Number of hours to retain snapshots created by this schedule.")]
public ulong RetentionHours { get { return _retentionHours.HasValue ? _retentionHours.Value : 0; } set { _retentionHours = value; } }
private ulong? _retentionMinutes;
[Parameter(Position = 14, Mandatory = false, HelpMessage = "Number of minutes to retain snapshots created by this schedule.")]
[ValidateRange(0, 59)]
public ulong RetentionMinutes { get { return _retentionMinutes.HasValue ? _retentionMinutes.Value : 0; } set { _retentionMinutes = value; } }
[Parameter(Position = 15, Mandatory = false, HelpMessage = "Date/Time after which the schedule will be run.")]
[SFValidatePattern(SolidFireValidations.ISO8601DateTimeOrEmptyString, "The argument is not in the format of an ISO-8601 Date String.")]
public string StartingDate { get; set; }
#endregion
#region Cmdlet Overrides
protected override void BeginProcessing()
{
base.BeginProcessing();
CheckConnection(minVersionNumber: 8.0f);
_pipeline = Runspace.DefaultRunspace.CreateNestedPipeline();
_processedIDs = new List();
}
protected override void EndProcessing()
{
var command = new Command("Get-SFSchedule");
command.Parameters.Add("ScheduleID", _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);
base.EndProcessing();
_processedIDs.Clear();
_pipeline = null;
}
protected override void ProcessRecord()
{
base.ProcessRecord();
var request = new CreateScheduleRequest();
var schedule = new Schedule()
{
Name = ScheduleName,
Paused = _paused ?? false,
StartingDate = StartingDate,
Recurring = _recurring
};
request.Schedule = schedule;
var scheduleInfo = new ScheduleInfo()
{
EnableRemoteReplication = EnableRemoteReplication,
SnapshotName = SnapshotName
};
// VolumeIDs can be handed in through either the VolumeID or ScheduleInfo parameters. It will usually be one or the other, not both.
// If both parameters are present, VolumeID will trump ScheduleInfo Volume IDs. The reason is because if someone is piping in an
// existing Schedule but they specify VolumeID in a parameter, it is assumed they want VolumeID to replace the Schedule's existing Volumes list.
// Go through both properties then put the appropriate Volume IDs in the ScheduleInfo.Volumes array.
var volumes = new List();
if (VolumeID != null)
{
volumes.Clear();
volumes.AddRange(VolumeID?.Select(v => v));
}
if (volumes.Count == 0)
{
throw new ParameterBindingException("No VolumeID specified. Unable to Modify schedule without VolumeID or ScheduleInfo.Volumes being passed in");
}
scheduleInfo.VolumeIDs = volumes.ToArray();
// ScheduleInfo.Retention must be in HH:mm:ss format. If any values are passed in, build the string.
if (_retentionDays.HasValue || _retentionHours.HasValue || _retentionMinutes.HasValue)
{
scheduleInfo.Retention = VolumeUtilities.BuildTimeString(_retentionDays.Value, _retentionHours.Value, _retentionMinutes.Value);
}
schedule.ScheduleInfo = scheduleInfo;
// Perform dynamic property assignment based on Frequency
switch (Frequency)
{
case "TimeInterval":
var timeInterval = new TimeIntervalFrequency()
{
Hours = (long)_contextTimeInterval.TimeIntervalHours,
Days = (long)_contextTimeInterval.TimeIntervalDays,
Minutes = (long)_contextTimeInterval.TimeIntervalMinutes
};
schedule.Frequency = timeInterval;
break;
case "DaysOfWeek":
var daysOfWeek = new DaysOfWeekFrequency()
{
Hours = (long)_contextDaysOfWeek.TimeOfDayHour,
Minutes = (long)_contextDaysOfWeek.TimeOfDayMinute
};
var weekdays = new List();
foreach (var day in _contextDaysOfWeek.DaysOfWeekDays)
{
weekdays.Add((Weekday)Enum.Parse(typeof(Weekday), day));
}
daysOfWeek.Weekdays = weekdays.ToArray();
schedule.Frequency = daysOfWeek;
break;
case "DaysOfMonth":
var daysOfMonth = new DaysOfMonthFrequency()
{
Hours = (long)_contextDaysOfMonth.TimeOfDayHour,
Minutes = (long)_contextDaysOfMonth.TimeOfDayMinute,
Monthdays = _contextDaysOfMonth.DaysOfMonthDays.Select(d => (long)d).ToArray()
};
schedule.Frequency = daysOfMonth;
break;
};
var objsFromAPI = SendRequest("CreateSchedule", request);
foreach (var obj in objsFromAPI)
{
_processedIDs.Add(obj.Result.ScheduleID);
}
}
///
/// This is necessary to implement IDynamicParameters. It hands back the corresponding parameter set
/// based on the value in the Frequence parameter.
///
/// DynamicParameter class with parameters for the selected Frequency
public object GetDynamicParameters()
{
switch (Frequency)
{
case "TimeInterval":
return _contextTimeInterval;
case "DaysOfMonth":
return _contextDaysOfMonth;
case "DaysOfWeek":
return _contextDaysOfWeek;
}
return null;
}
#endregion
}
}