Skip to content

Commit a6f2ca0

Browse files
authored
Merge pull request #4832 from wastoresh/fsh
Add File Share Snapshot Support
2 parents 7c5ac2a + 561f754 commit a6f2ca0

21 files changed

+204
-54
lines changed

src/Storage/ChangeLog.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818
- Additional information about change #1
1919
-->
2020
## Current Release
21-
21+
* Upgrade to Azure Storage Client Library 8.5.0 and Azure Storage DataMovement Library 0.6.3
22+
* Add File Share Snapshot Support Feature
23+
- Add 'SnapshotTime' parameter to Get-AzureStorageShare
24+
- Add 'IncludeAllSnapshot' parameter to Remove-AzureStorageShare
25+
2226
## Version 3.4.1
2327

2428
## Version 3.4.0

src/Storage/Commands.Storage.Test/Commands.Storage.Test.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,11 @@
122122
<Reference Include="Microsoft.WindowsAzure.Management">
123123
<HintPath>..\..\packages\Microsoft.WindowsAzure.Management.4.1.1\lib\net40\Microsoft.WindowsAzure.Management.dll</HintPath>
124124
</Reference>
125-
<Reference Include="Microsoft.WindowsAzure.Storage, Version=8.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
126-
<HintPath>..\..\packages\WindowsAzure.Storage.8.4.0\lib\net45\Microsoft.WindowsAzure.Storage.dll</HintPath>
125+
<Reference Include="Microsoft.WindowsAzure.Storage, Version=8.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
126+
<HintPath>..\..\packages\WindowsAzure.Storage.8.5.0\lib\net45\Microsoft.WindowsAzure.Storage.dll</HintPath>
127127
</Reference>
128-
<Reference Include="Microsoft.WindowsAzure.Storage.DataMovement, Version=0.6.1.0, Culture=neutral, processorArchitecture=MSIL">
129-
<HintPath>..\..\packages\Microsoft.Azure.Storage.DataMovement.0.6.1\lib\net45\Microsoft.WindowsAzure.Storage.DataMovement.dll</HintPath>
128+
<Reference Include="Microsoft.WindowsAzure.Storage.DataMovement, Version=0.6.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
129+
<HintPath>..\..\packages\Microsoft.Azure.Storage.DataMovement.0.6.3\lib\net45\Microsoft.WindowsAzure.Storage.DataMovement.dll</HintPath>
130130
</Reference>
131131
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
132132
<HintPath>..\..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>

src/Storage/Commands.Storage.Test/Service/MockStorageFileManagement.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ public void SetsAvailableDirectories(params string[] directoryNames)
5353
this.availableDirectoryNames.AddRange(directoryNames);
5454
}
5555

56-
public CloudFileShare GetShareReference(string shareName)
56+
public CloudFileShare GetShareReference(string shareName, DateTimeOffset? snapshotTime = null)
5757
{
58-
return client.GetShareReference(shareName);
58+
return client.GetShareReference(shareName, snapshotTime);
5959
}
6060

6161
public void FetchShareAttributes(CloudFileShare share, AccessCondition accessCondition, FileRequestOptions options, OperationContext operationContext)
@@ -136,7 +136,7 @@ public Task DeleteDirectoryAsync(CloudFileDirectory directory, AccessCondition a
136136
return TaskEx.FromResult(true);
137137
}
138138

139-
public Task DeleteShareAsync(CloudFileShare share, AccessCondition accessCondition, FileRequestOptions options, OperationContext operationContext, CancellationToken cancellationToken)
139+
public Task DeleteShareAsync(CloudFileShare share, DeleteShareSnapshotsOption deleteShareSnapshotsOption, AccessCondition accessCondition, FileRequestOptions options, OperationContext operationContext, CancellationToken cancellationToken)
140140
{
141141
return TaskEx.FromResult(true);
142142
}

src/Storage/Commands.Storage.Test/packages.config

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<package id="Microsoft.Azure.Common.Dependencies" version="1.0.0" targetFramework="net45" />
66
<package id="Microsoft.Azure.KeyVault.Core" version="1.0.0" targetFramework="net45" />
77
<package id="Microsoft.Azure.Management.Resources" version="2.18.11-preview" targetFramework="net45" />
8-
<package id="Microsoft.Azure.Storage.DataMovement" version="0.6.1" targetFramework="net452" />
8+
<package id="Microsoft.Azure.Storage.DataMovement" version="0.6.3" targetFramework="net452" />
99
<package id="Microsoft.Azure.Test.HttpRecorder" version="1.6.7-preview" targetFramework="net45" />
1010
<package id="Microsoft.Bcl" version="1.1.9" targetFramework="net45" />
1111
<package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
@@ -25,7 +25,7 @@
2525
<package id="System.Linq.Queryable" version="4.0.0" targetFramework="net45" />
2626
<package id="System.Net.Requests" version="4.0.11" targetFramework="net45" />
2727
<package id="System.Spatial" version="5.8.2" targetFramework="net45" />
28-
<package id="WindowsAzure.Storage" version="8.4.0" targetFramework="net452" />
28+
<package id="WindowsAzure.Storage" version="8.5.0" targetFramework="net452" />
2929
<package id="xunit" version="2.1.0" targetFramework="net45" />
3030
<package id="xunit.abstractions" version="2.0.0" targetFramework="net45" />
3131
<package id="xunit.assert" version="2.1.0" targetFramework="net45" />

src/Storage/Commands.Storage/Commands.Storage.csproj

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,12 @@
5959
</Reference>
6060
<Reference Include="Microsoft.WindowsAzure.Configuration, Version=1.8.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
6161
<HintPath>..\..\packages\Microsoft.WindowsAzure.ConfigurationManager.1.8.0.0\lib\net35-full\Microsoft.WindowsAzure.Configuration.dll</HintPath>
62-
<Private>True</Private>
6362
</Reference>
64-
<Reference Include="Microsoft.WindowsAzure.Storage, Version=8.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
65-
<HintPath>..\..\packages\WindowsAzure.Storage.8.4.0\lib\net45\Microsoft.WindowsAzure.Storage.dll</HintPath>
63+
<Reference Include="Microsoft.WindowsAzure.Storage, Version=8.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
64+
<HintPath>..\..\packages\WindowsAzure.Storage.8.5.0\lib\net45\Microsoft.WindowsAzure.Storage.dll</HintPath>
6665
</Reference>
67-
<Reference Include="Microsoft.WindowsAzure.Storage.DataMovement, Version=0.6.1.0, Culture=neutral, processorArchitecture=MSIL">
68-
<HintPath>..\..\packages\Microsoft.Azure.Storage.DataMovement.0.6.1\lib\net45\Microsoft.WindowsAzure.Storage.DataMovement.dll</HintPath>
66+
<Reference Include="Microsoft.WindowsAzure.Storage.DataMovement, Version=0.6.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
67+
<HintPath>..\..\packages\Microsoft.Azure.Storage.DataMovement.0.6.3\lib\net45\Microsoft.WindowsAzure.Storage.DataMovement.dll</HintPath>
6968
</Reference>
7069
<Reference Include="System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
7170
<SpecificVersion>False</SpecificVersion>
@@ -242,7 +241,9 @@
242241
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
243242
</None>
244243
<None Include="MSSharedLibKey.snk" />
245-
<None Include="packages.config" />
244+
<None Include="packages.config">
245+
<SubType>Designer</SubType>
246+
</None>
246247
</ItemGroup>
247248
<ItemGroup>
248249
<EmbeddedResource Include="Resources.resx">

src/Storage/Commands.Storage/Common/StorageExtensions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ internal static Uri GenerateUriWithCredentials(
3434

3535
if (string.IsNullOrEmpty(sasToken))
3636
{
37-
return file.Uri;
37+
return file.SnapshotQualifiedUri;
3838
}
3939
else
4040
{
41-
return new Uri(string.Format(CultureInfo.InvariantCulture, "{0}{1}", file.Uri.AbsoluteUri, sasToken));
41+
return new Uri(string.Format(CultureInfo.InvariantCulture, "{0}{1}", file.SnapshotQualifiedUri.AbsoluteUri, sasToken));
4242
}
4343
}
4444

@@ -57,7 +57,7 @@ internal static CloudFile GenerateCopySourceFile(
5757
return file;
5858
}
5959

60-
return new CloudFile(file.Uri, new StorageCredentials(sasToken));
60+
return new CloudFile(file.SnapshotQualifiedUri, new StorageCredentials(sasToken));
6161
}
6262

6363
private static string GetFileSASToken(CloudFile file)

src/Storage/Commands.Storage/Common/Util.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ public static string ConvertToString(this object instance)
199199

200200
if (null != file)
201201
{
202-
return file.Uri.AbsoluteUri;
202+
return file.SnapshotQualifiedUri.AbsoluteUri;
203203
}
204204

205205
return instance.ToString();

src/Storage/Commands.Storage/File/Cmdlet/GetAzureStorageFileCopyState.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ protected async Task MonitorFileCopyStatusAsync(long taskId)
204204

205205
if (file.CopyState == null)
206206
{
207-
ArgumentException e = new ArgumentException(String.Format(Resources.FileCopyTaskNotFound, file.Uri.ToString()));
207+
ArgumentException e = new ArgumentException(String.Format(Resources.FileCopyTaskNotFound, file.SnapshotQualifiedUri.ToString()));
208208
OutputStream.WriteError(internalTaskId, e);
209209
Interlocked.Increment(ref InternalFailedCount);
210210
taskDone = true;

src/Storage/Commands.Storage/File/Cmdlet/GetAzureStorageShare.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ namespace Microsoft.WindowsAzure.Commands.Storage.File.Cmdlet
1818
using Azure.Commands.Common.Authentication.Abstractions;
1919
using Microsoft.WindowsAzure.Commands.Common.Storage;
2020
using Microsoft.WindowsAzure.Storage.File;
21+
using System;
2122
using System.Globalization;
2223
using System.Management.Automation;
2324

@@ -28,7 +29,7 @@ public class GetAzureStorageShare : AzureStorageFileCmdletBase
2829
Position = 0,
2930
Mandatory = true,
3031
ParameterSetName = Constants.SpecificParameterSetName,
31-
HelpMessage = "Name of the file share to be listed.")]
32+
HelpMessage = "Name of the file share to be received.")]
3233
[ValidateNotNullOrEmpty]
3334
public string Name { get; set; }
3435

@@ -38,6 +39,14 @@ public class GetAzureStorageShare : AzureStorageFileCmdletBase
3839
HelpMessage = "A prefix of the file shares to be listed.")]
3940
public string Prefix { get; set; }
4041

42+
[Parameter(
43+
Position = 1,
44+
Mandatory = false,
45+
ParameterSetName = Constants.SpecificParameterSetName,
46+
HelpMessage = "SnapshotTime of the file share snapshot to be received.")]
47+
[ValidateNotNullOrEmpty]
48+
public DateTimeOffset? SnapshotTime { get; set; }
49+
4150
[Parameter(
4251
ValueFromPipeline = true,
4352
ValueFromPipelineByPropertyName = true,
@@ -58,7 +67,7 @@ public override void ExecuteCmdlet()
5867
{
5968
case Constants.SpecificParameterSetName:
6069
NamingUtil.ValidateShareName(this.Name, false);
61-
var share = this.Channel.GetShareReference(this.Name);
70+
var share = this.Channel.GetShareReference(this.Name, this.SnapshotTime);
6271
await this.Channel.FetchShareAttributesAsync(share, null, this.RequestOptions, this.OperationContext, this.CmdletCancellationToken).ConfigureAwait(false);
6372
this.OutputStream.WriteObject(taskId, share);
6473

src/Storage/Commands.Storage/File/Cmdlet/NewAzureStorageFileSasToken.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ public override void ExecuteCmdlet()
183183

184184
if (FullUri)
185185
{
186-
string fullUri = SasTokenHelper.GetFullUriWithSASToken(file.Uri.AbsoluteUri.ToString(), sasToken);
186+
string fullUri = SasTokenHelper.GetFullUriWithSASToken(file.SnapshotQualifiedUri.AbsoluteUri.ToString(), sasToken);
187187

188188
WriteObject(fullUri);
189189
}

src/Storage/Commands.Storage/File/Cmdlet/NewAzureStorageShareSasToken.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ public override void ExecuteCmdlet()
114114

115115
if (FullUri)
116116
{
117-
string fullUri = SasTokenHelper.GetFullUriWithSASToken(fileShare.Uri.AbsoluteUri.ToString(), sasToken);
117+
string fullUri = SasTokenHelper.GetFullUriWithSASToken(fileShare.SnapshotQualifiedUri.AbsoluteUri.ToString(), sasToken);
118118

119119
WriteObject(fullUri);
120120
}

src/Storage/Commands.Storage/File/Cmdlet/RemoveAzureStorageShare.cs

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
namespace Microsoft.WindowsAzure.Commands.Storage.File.Cmdlet
1616
{
17+
using Microsoft.WindowsAzure.Commands.Storage.Common;
18+
using Microsoft.WindowsAzure.Storage;
1719
using Microsoft.WindowsAzure.Storage.File;
1820
using System.Globalization;
1921
using System.Management.Automation;
@@ -44,7 +46,10 @@ public class RemoveAzureStorageShare : AzureStorageFileCmdletBase
4446
[ValidateNotNull]
4547
public CloudFileShare Share { get; set; }
4648

47-
[Parameter(HelpMessage = "Force to remove the share and all content in it")]
49+
[Parameter(HelpMessage = "Remove File Share with all of its snapshots")]
50+
public SwitchParameter IncludeAllSnapshot { get; set; }
51+
52+
[Parameter(HelpMessage = "Force to remove the share with all its snapshots, and all content in them.")]
4853
public SwitchParameter Force
4954
{
5055
get { return force; }
@@ -56,6 +61,15 @@ public SwitchParameter Force
5661

5762
private bool force;
5863

64+
/// <summary>
65+
/// Cmdlet begin processing
66+
/// </summary>
67+
protected override void BeginProcessing()
68+
{
69+
base.BeginProcessing();
70+
OutputStream.ConfirmWriter = (s1, s2, s3) => ShouldContinue(s2, s3);
71+
}
72+
5973
public override void ExecuteCmdlet()
6074
{
6175
CloudFileShare share;
@@ -77,9 +91,54 @@ public override void ExecuteCmdlet()
7791
{
7892
this.RunTask(async taskId =>
7993
{
94+
if (share.IsSnapshot && IncludeAllSnapshot.IsPresent)
95+
{
96+
throw new PSArgumentException(string.Format(CultureInfo.InvariantCulture, "'IncludeAllSnapshot' should only be specified to delete a base share, and should not be specified to delete a Share snapshot: {0}", share.SnapshotQualifiedUri));
97+
}
98+
8099
if (force || ShareIsEmpty(share) || ShouldContinue(string.Format("Remove share and all content in it: {0}", share.Name), ""))
81100
{
82-
await this.Channel.DeleteShareAsync(share, null, this.RequestOptions, this.OperationContext, this.CmdletCancellationToken).ConfigureAwait(false);
101+
DeleteShareSnapshotsOption deleteShareSnapshotsOption = DeleteShareSnapshotsOption.None;
102+
bool retryDeleteSnapshot = false;
103+
104+
//Force means will delete the share anyway, so use 'IncludeSnapshots' to delete the share even has snapshot, or delete will fail when share has snapshot
105+
// To delete a Share shapshot, must use 'None'
106+
if (IncludeAllSnapshot.IsPresent)
107+
{
108+
deleteShareSnapshotsOption = DeleteShareSnapshotsOption.IncludeSnapshots;
109+
}
110+
else
111+
{
112+
retryDeleteSnapshot = true;
113+
}
114+
115+
try
116+
{
117+
await this.Channel.DeleteShareAsync(share, deleteShareSnapshotsOption, null, this.RequestOptions, this.OperationContext, this.CmdletCancellationToken).ConfigureAwait(false);
118+
retryDeleteSnapshot = false;
119+
}
120+
catch (StorageException e)
121+
{
122+
//If x-ms-delete-snapshots is not specified on the request and the share has associated snapshots, the File service returns status code 409 (Conflict).
123+
if (!(e.IsConflictException() && retryDeleteSnapshot))
124+
{
125+
throw;
126+
}
127+
}
128+
129+
if (retryDeleteSnapshot)
130+
{
131+
if (force || await OutputStream.ConfirmAsync(string.Format("This share might have snapshots, remove the share and all snapshots?: {0}", share.Name)).ConfigureAwait(false))
132+
{
133+
deleteShareSnapshotsOption = DeleteShareSnapshotsOption.IncludeSnapshots;
134+
await this.Channel.DeleteShareAsync(share, deleteShareSnapshotsOption, null, this.RequestOptions, this.OperationContext, this.CmdletCancellationToken).ConfigureAwait(false);
135+
}
136+
else
137+
{
138+
string result = string.Format("The remove operation of share '{0}' has been cancelled.", share.Name);
139+
OutputStream.WriteVerbose(taskId, result);
140+
}
141+
}
83142
}
84143

85144
if (this.PassThru)

src/Storage/Commands.Storage/File/Cmdlet/StartAzureStorageFileCopy.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ private void StartCopyFromBlob()
281281
Func<long, Task> taskGenerator = (taskId) => StartAsyncCopy(
282282
taskId,
283283
destFile,
284-
() => this.ConfirmOverwrite(blob.SnapshotQualifiedUri.ToString(), destFile.Uri.ToString()),
284+
() => this.ConfirmOverwrite(blob.SnapshotQualifiedUri.ToString(), destFile.SnapshotQualifiedUri.ToString()),
285285
() => destFile.StartCopyAsync(blob.GenerateCopySourceBlob(), null, null, this.RequestOptions, this.OperationContext, CmdletCancellationToken));
286286

287287
this.RunTask(taskGenerator);
@@ -321,7 +321,7 @@ private void StartCopyFromFile()
321321
Func<long, Task> taskGenerator = (taskId) => StartAsyncCopy(
322322
taskId,
323323
destFile,
324-
() => this.ConfirmOverwrite(sourceFile.Uri.ToString(), destFile.Uri.ToString()),
324+
() => this.ConfirmOverwrite(sourceFile.SnapshotQualifiedUri.ToString(), destFile.SnapshotQualifiedUri.ToString()),
325325
() => destFile.StartCopyAsync(sourceFile.GenerateCopySourceFile(), null, null, this.RequestOptions, this.OperationContext, this.CmdletCancellationToken));
326326

327327
this.RunTask(taskGenerator);
@@ -334,7 +334,7 @@ private void StartCopyFromUri()
334334
Func<long, Task> taskGenerator = (taskId) => StartAsyncCopy(
335335
taskId,
336336
destFile,
337-
() => this.ConfirmOverwrite(this.AbsoluteUri, destFile.Uri.ToString()),
337+
() => this.ConfirmOverwrite(this.AbsoluteUri, destFile.SnapshotQualifiedUri.ToString()),
338338
() => destFile.StartCopyAsync(new Uri(this.AbsoluteUri), null, null, this.RequestOptions, this.OperationContext));
339339

340340
this.RunTask(taskGenerator);

src/Storage/Commands.Storage/File/Cmdlet/StopAzureStorageFileCopy.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ private async Task StopCopyFile(long taskId, IStorageFileManagement localChannel
9999

100100
if (file.CopyState == null || string.IsNullOrEmpty(file.CopyState.CopyId))
101101
{
102-
ArgumentException e = new ArgumentException(String.Format(Resources.FileCopyTaskNotFound, file.Uri.ToString()));
102+
ArgumentException e = new ArgumentException(String.Format(Resources.FileCopyTaskNotFound, file.SnapshotQualifiedUri.ToString()));
103103
OutputStream.WriteError(taskId, e);
104104
}
105105
else
@@ -109,10 +109,10 @@ private async Task StopCopyFile(long taskId, IStorageFileManagement localChannel
109109

110110
if (!Force)
111111
{
112-
string confirmation = String.Format(Resources.ConfirmAbortFileCopyOperation, file.Uri.ToString(), abortCopyId);
112+
string confirmation = String.Format(Resources.ConfirmAbortFileCopyOperation, file.SnapshotQualifiedUri.ToString(), abortCopyId);
113113
if (!await OutputStream.ConfirmAsync(confirmation).ConfigureAwait(false))
114114
{
115-
string cancelMessage = String.Format(Resources.StopCopyOperationCancelled, file.Uri.ToString());
115+
string cancelMessage = String.Format(Resources.StopCopyOperationCancelled, file.SnapshotQualifiedUri.ToString());
116116
OutputStream.WriteVerbose(taskId, cancelMessage);
117117
}
118118
}
@@ -123,7 +123,7 @@ private async Task StopCopyFile(long taskId, IStorageFileManagement localChannel
123123
}
124124

125125
await localChannel.AbortCopyAsync(file, abortCopyId, null, requestOptions, OperationContext, CmdletCancellationToken).ConfigureAwait(false);
126-
string message = String.Format(Resources.StopCopyFileSuccessfully, file.Uri.ToString());
126+
string message = String.Format(Resources.StopCopyFileSuccessfully, file.SnapshotQualifiedUri.ToString());
127127
OutputStream.WriteObject(taskId, message);
128128
}
129129
}

0 commit comments

Comments
 (0)