Skip to content

Commit 23c384f

Browse files
authored
[Storage] Support localuser nfsv3 (#25780)
* [Storage] Support localuser nfsv3 * remove suffix s from parameter name
1 parent 73374d0 commit 23c384f

File tree

14 files changed

+1786
-101
lines changed

14 files changed

+1786
-101
lines changed

src/Storage/Storage.Management.Test/ScenarioTests/StorageAccountTests.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,13 @@ public void TestAzureStorageLocalUserSftp()
289289
TestRunner.RunTestScript("Test-AzureStorageLocalUserSftp");
290290
}
291291

292+
[Fact]
293+
[Trait(Category.AcceptanceType, Category.CheckIn)]
294+
public void TestAzureStorageLocalUserNFSV3()
295+
{
296+
TestRunner.RunTestScript("Test-AzureStorageLocalUserNFSV3");
297+
}
298+
292299
[Fact]
293300
[Trait(Category.AcceptanceType, Category.CheckIn)]
294301
public void TestStorageAccountAllowedCopyScope()

src/Storage/Storage.Management.Test/ScenarioTests/StorageAccountTests.ps1

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2441,6 +2441,96 @@ function Test-AzureStorageLocalUserSftp
24412441
}
24422442
}
24432443

2444+
2445+
<#
2446+
.SYNOPSIS
2447+
Test AzureStorageLocalUserNFSV3
2448+
.DESCRIPTION
2449+
SmokeTest
2450+
#>
2451+
function Test-AzureStorageLocalUserNFSV3
2452+
{
2453+
# Setup
2454+
$rgname = Get-StorageManagementTestResourceName;
2455+
2456+
try
2457+
{
2458+
# Test
2459+
$stoname = 'sto' + $rgname;
2460+
$stotype = 'Standard_LRS';
2461+
$loc = Get-ProviderLocation_Canary ResourceManagement;
2462+
$kind = 'StorageV2'
2463+
2464+
New-AzResourceGroup -Name $rgname -Location $loc;
2465+
New-AzStorageAccount -ResourceGroupName $rgname -Name $stoname -Location $loc -Type $stotype -Kind $kind -EnableSftp $true -EnableHierarchicalNamespace $true -EnableNfsV3 $true -EnableLocalUser $true `
2466+
-EnableExtendedGroup $true -NetworkRuleSet (@{bypass="AzureServices";defaultAction="deny"})
2467+
2468+
Retry-IfException { $global:sto = Get-AzStorageAccount -ResourceGroupName $rgname -Name $stoname; }
2469+
Assert-AreEqual $stoname $sto.StorageAccountName;
2470+
Assert-AreEqual $stotype $sto.Sku.Name;
2471+
Assert-AreEqual $loc.ToLower().Replace(" ", "") $sto.Location;
2472+
Assert-AreEqual $kind $sto.Kind;
2473+
Assert-AreEqual $true $sto.EnableSftp;
2474+
Assert-AreEqual $true $sto.EnableNfsV3;
2475+
Assert-AreEqual $true $sto.EnableLocalUser;
2476+
Assert-AreEqual $true $sto.EnableExtendedGroups;
2477+
2478+
Retry-IfException { $global:sto = Set-AzStorageAccount -ResourceGroupName $rgname -Name $stoname -EnableExtendedGroup $false }
2479+
Assert-AreEqual $false $sto.EnableExtendedGroups;
2480+
2481+
Retry-IfException { $global:sto = Set-AzStorageAccount -ResourceGroupName $rgname -Name $stoname -EnableExtendedGroup $true }
2482+
Assert-AreEqual $true $sto.EnableExtendedGroups;
2483+
2484+
# create local user
2485+
$userName1 = "nfsv3_70005"
2486+
$localuser1 = Set-AzStorageLocalUser -ResourceGroupName $rgname -StorageAccountName $stoname -UserName $userName1 -HomeDirectory /test -IsNfSv3Enabled $true -ExtendedGroup 1,2,3,4,5
2487+
Assert-AreEqual $userName1 $localuser1.Name;
2488+
Assert-AreEqual "/test" $localuser1.HomeDirectory;
2489+
Assert-AreEqual 5 $localuser1.ExtendedGroups.Count;
2490+
Assert-AreEqual $true $localuser1.IsNfSv3Enabled;
2491+
2492+
$userName2 = "testuser2"
2493+
$localuser2 = Set-AzStorageLocalUser -ResourceGroupName $rgname -StorageAccountName $stoname -UserName $userName2 -HomeDirectory "/dir1"
2494+
Assert-AreEqual $userName2 $localuser2.Name;
2495+
Assert-Null $localuser2.HasSharedKey;
2496+
Assert-Null $localuser2.HasSshKey;
2497+
Assert-Null $localuser2.HasSshPassword;
2498+
Assert-AreEqual "/dir1" $localuser2.HomeDirectory;
2499+
Assert-Null $localuser2.PermissionScopes;
2500+
Assert-Null $localuser2.SshAuthorizedKeys;
2501+
2502+
# update local user
2503+
$localuser1 = Set-AzStorageLocalUser -ResourceGroupName $rgname -StorageAccountName $stoname -UserName $userName1 -HomeDirectory /test -ExtendedGroup 1,2,3
2504+
Assert-AreEqual $userName1 $localuser1.Name;
2505+
Assert-AreEqual "/test" $localuser1.HomeDirectory;
2506+
Assert-AreEqual 3 $localuser1.ExtendedGroups.Count;
2507+
2508+
#list all nfsv3 local users
2509+
$localusers = Get-AzStorageLocalUser -ResourceGroupName $rgname -StorageAccountName $stoname -IncludeNFSv3
2510+
Assert-AreEqual 1 $localusers.Count;
2511+
Assert-AreEqual $userName1 $localusers[0].Name;
2512+
2513+
#list all none-nfsv3 local users
2514+
$localusers = Get-AzStorageLocalUser -ResourceGroupName $rgname -StorageAccountName $stoname
2515+
Assert-AreEqual 1 $localusers.Count;
2516+
Assert-AreEqual $userName2 $localusers[0].Name;
2517+
2518+
# remove local user
2519+
Remove-AzStorageLocalUser -ResourceGroupName $rgname -StorageAccountName $stoname -UserName $userName1
2520+
$localusers = Get-AzStorageLocalUser -ResourceGroupName $rgname -StorageAccountName $stoname
2521+
Assert-AreEqual 1 $localusers.Count;
2522+
Assert-AreEqual $userName2 $localusers[0].Name;
2523+
2524+
#clean up
2525+
Remove-AzStorageAccount -Force -ResourceGroupName $rgname -Name $stoname;
2526+
}
2527+
finally
2528+
{
2529+
# Cleanup
2530+
Clean-ResourceGroup $rgname
2531+
}
2532+
}
2533+
24442534
<#
24452535
.SYNOPSIS
24462536
Test Test-StorageAccountAllowedCopyScope

src/Storage/Storage.Management.Test/SessionRecords/Microsoft.Azure.Commands.Management.Storage.Test.ScenarioTests.StorageAccountTests/TestAzureStorageLocalUserNFSV3.json

Lines changed: 1434 additions & 0 deletions
Large diffs are not rendered by default.

src/Storage/Storage.Management/ChangeLog.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@
1818
- Additional information about change #1
1919
-->
2020
## Upcoming Release
21+
* Supported local user IsNfSv3Enabled and ExtendedGroup
22+
- `Set-AzStorageLocalUser`
23+
* Supported list local user with IncludeNFSv3
24+
- `Get-AzStorageLocalUser`
25+
* Supported EnableExtendedGroup when creating and updating a storage account
26+
- `New-AzStorageAccount`
27+
- `Set-AzStorageAccount`
2128

2229
## Version 7.2.0
2330
* Upgraded Microsoft.Azure.Storage.DataMovement to 2.0.5

src/Storage/Storage.Management/Models/PSLocalUser.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
using Microsoft.Azure.Management.Storage.Models;
1616
using Microsoft.WindowsAzure.Commands.Common.Attributes;
1717
using System.Collections.Generic;
18+
using System.Linq;
1819

1920
namespace Microsoft.Azure.Commands.Management.Storage.Models
2021
{
@@ -38,7 +39,9 @@ public PSLocalUser(LocalUser user, string ResourceGroupName, string StorageAccou
3839
this.HasSshKey = user.HasSshKey;
3940
this.HasSshPassword = user.HasSshPassword;
4041
this.SshAuthorizedKeys = PSSshPublicKey.GetPSSshPublicKeys(user.SshAuthorizedKeys);
41-
this.PermissionScopes = PSPermissionScope.GetPSPermissionScopes(user.PermissionScopes);
42+
this.PermissionScopes = PSPermissionScope.GetPSPermissionScopes(user.PermissionScopes);
43+
this.IsNfSv3Enabled = user.IsNfSv3Enabled;
44+
this.ExtendedGroups = user.ExtendedGroups == null ? null : user.ExtendedGroups.ToArray();
4245
this.GroupId = user.GroupId;
4346
this.AllowAclAuthorization = user.AllowAclAuthorization;
4447
this.UserId = user.UserId;
@@ -55,6 +58,8 @@ public LocalUser ParseLocalUser()
5558
user.HasSshPassword = this.HasSshPassword;
5659
user.SshAuthorizedKeys = PSSshPublicKey.ParseSshPublicKeyss(this.SshAuthorizedKeys);
5760
user.PermissionScopes = PSPermissionScope.ParsePermissionScopes(this.PermissionScopes);
61+
user.IsNfSv3Enabled = this.IsNfSv3Enabled;
62+
user.ExtendedGroups = this.ExtendedGroups is null ? null : new List<int?>(this.ExtendedGroups);
5863
user.GroupId = this.GroupId;
5964
user.AllowAclAuthorization = this.AllowAclAuthorization;
6065
return user;
@@ -82,6 +87,8 @@ public LocalUser ParseLocalUser()
8287
public bool? HasSshPassword { get; set; }
8388
public PSSshPublicKey[] SshAuthorizedKeys { get; set; }
8489
public PSPermissionScope[] PermissionScopes { get; set; }
90+
public int?[] ExtendedGroups { get; set; }
91+
public bool? IsNfSv3Enabled { get; set; }
8592
public int? GroupId { get; set; }
8693
public bool? AllowAclAuthorization { get; set; }
8794
public int? UserId { get; set; }

src/Storage/Storage.Management/Models/PSStorageAccount.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ public PSStorageAccount(StorageModels.StorageAccount storageAccount)
7676
this.EnableLocalUser = storageAccount.IsLocalUserEnabled;
7777
this.AllowedCopyScope = storageAccount.AllowedCopyScope;
7878
this.DnsEndpointType = storageAccount.DnsEndpointType;
79+
this.EnableExtendedGroups = storageAccount.EnableExtendedGroups;
7980
}
8081
public bool? AllowCrossTenantReplication { get; set; }
8182

@@ -170,6 +171,7 @@ public PSStorageAccount(StorageModels.StorageAccount storageAccount)
170171
public PSImmutableStorageAccount ImmutableStorageWithVersioning { get; set; }
171172
public PSStorageAccountSkuConversionStatus StorageAccountSkuConversionStatus { get; set; }
172173
public string DnsEndpointType { get; set; }
174+
public bool? EnableExtendedGroups { get; set; }
173175

174176
public static PSStorageAccount Create(StorageModels.StorageAccount storageAccount, IStorageManagementClient client)
175177
{

src/Storage/Storage.Management/StorageAccount/GetAzureStorageLocalUser.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public class GetAzureStorageLocalUserCommand : StorageFileBaseCmdlet
6161
HelpMessage = "The name of local user. The username must contain lowercase letters and numbers only. It must be unique only within the storage account.")]
6262
[ValidateNotNullOrEmpty]
6363
public string UserName { get; set; }
64-
64+
6565
[Parameter(Mandatory = false,
6666
HelpMessage = "The maximum number of local users that will be included in the list response")]
6767
[ValidateNotNullOrEmpty]
@@ -71,7 +71,11 @@ public class GetAzureStorageLocalUserCommand : StorageFileBaseCmdlet
7171
HelpMessage = "The filter of username. When specified, only usernames starting with the filter will be listed. The filter must be in format: startswith(name, <prefix>)")]
7272
[ValidateNotNullOrEmpty]
7373
public string Filter { get; set; }
74-
74+
75+
[Parameter(Mandatory = false,
76+
HelpMessage = "Specify to include NFSv3 enabled Local Users in list Local Users.")]
77+
[ValidateNotNullOrEmpty]
78+
public SwitchParameter IncludeNFSv3 { get; set; }
7579

7680
public override void ExecuteCmdlet()
7781
{
@@ -92,8 +96,9 @@ public override void ExecuteCmdlet()
9296
{
9397
var users = this.StorageClient.LocalUsers.List(
9498
this.ResourceGroupName,
95-
this.StorageAccountName, this.MaxPageSize, this.Filter);
96-
99+
this.StorageAccountName, this.MaxPageSize, this.Filter,
100+
include: this.IncludeNFSv3.IsPresent ? "nfsv3" : null);
101+
97102
if (users != null)
98103
{
99104
foreach(LocalUser localUser in users)

src/Storage/Storage.Management/StorageAccount/NewAzureStorageAccount.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,23 @@ public bool EnableLocalUser
247247
}
248248
private bool? enableLocalUser = null;
249249

250+
[Parameter(
251+
Mandatory = false,
252+
HelpMessage = "Enables extended group support with local users feature, if set to true.")]
253+
[ValidateNotNullOrEmpty]
254+
public bool EnableExtendedGroup
255+
{
256+
get
257+
{
258+
return enableExtendedGroup != null ? enableExtendedGroup.Value : false;
259+
}
260+
set
261+
{
262+
enableExtendedGroup = value;
263+
}
264+
}
265+
private bool? enableExtendedGroup = null;
266+
250267
[Parameter(
251268
Mandatory = false,
252269
HelpMessage = "Enable HierarchicalNamespace for the Storage account.")]
@@ -915,6 +932,10 @@ public override void ExecuteCmdlet()
915932
{
916933
createParameters.IsLocalUserEnabled = this.enableLocalUser;
917934
}
935+
if (this.enableExtendedGroup != null)
936+
{
937+
createParameters.EnableExtendedGroups = this.enableExtendedGroup;
938+
}
918939
if (this.AllowedCopyScope != null)
919940
{
920941
createParameters.AllowedCopyScope = this.AllowedCopyScope;

src/Storage/Storage.Management/StorageAccount/SetAzureStorageAccount.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,23 @@ public bool EnableLocalUser
585585
}
586586
private bool? enableLocalUser = null;
587587

588+
[Parameter(
589+
Mandatory = false,
590+
HelpMessage = "Enables extended group support with local users feature, if set to true.")]
591+
[ValidateNotNullOrEmpty]
592+
public bool EnableExtendedGroup
593+
{
594+
get
595+
{
596+
return enableExtendedGroup != null ? enableExtendedGroup.Value : false;
597+
}
598+
set
599+
{
600+
enableExtendedGroup = value;
601+
}
602+
}
603+
private bool? enableExtendedGroup = null;
604+
588605
[Parameter(Mandatory = false, HelpMessage = "Set restrict copy to and from Storage Accounts within a Microsoft Entra tenant or with Private Links to the same VNet. Possible values include: 'PrivateLink', 'AAD'")]
589606
[PSArgumentCompleter("PrivateLink", "AAD")]
590607
[ValidateNotNullOrEmpty]
@@ -927,6 +944,10 @@ public override void ExecuteCmdlet()
927944
{
928945
updateParameters.IsLocalUserEnabled = this.enableLocalUser;
929946
}
947+
if (this.enableExtendedGroup != null)
948+
{
949+
updateParameters.EnableExtendedGroups = this.enableExtendedGroup;
950+
}
930951
if (this.AllowedCopyScope != null)
931952
{
932953
updateParameters.AllowedCopyScope = this.AllowedCopyScope;

src/Storage/Storage.Management/StorageAccount/SetAzureStorageLocalUser.cs

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
using Microsoft.Azure.Commands.Management.Storage.Models;
1616
using Microsoft.Azure.Management.Storage;
1717
using Microsoft.Azure.Management.Storage.Models;
18+
using System.Linq;
1819
using System.Management.Automation;
1920

2021
namespace Microsoft.Azure.Commands.Management.Storage
@@ -140,10 +141,32 @@ public bool HasSshPassword
140141
[ValidateNotNullOrEmpty]
141142
public bool? AllowAclAuthorization { get; set; }
142143

144+
[Parameter(
145+
Mandatory = false,
146+
HelpMessage = "Indicates whether LocalUser belongs to NFSv3 or SFTP.")]
147+
[ValidateNotNullOrEmpty]
148+
public bool IsNfSv3Enabled
149+
{
150+
get
151+
{
152+
return isNfSv3Enabled != null ? isNfSv3Enabled.Value : false;
153+
}
154+
set
155+
{
156+
isNfSv3Enabled = value;
157+
}
158+
}
159+
private bool? isNfSv3Enabled = null;
160+
161+
[Parameter(Mandatory = false,
162+
HelpMessage = "Sets extended Groups of which user is part of, only for NFSv3 User.")]
163+
[ValidateNotNullOrEmpty]
164+
public int[] ExtendedGroup { get; set; }
165+
143166
public override void ExecuteCmdlet()
144167
{
145168
base.ExecuteCmdlet();
146-
169+
147170
if (ShouldProcess(this.UserName, "Create Storage Account LocalUser with name:"))
148171
{
149172
switch (ParameterSetName)
@@ -165,17 +188,40 @@ public override void ExecuteCmdlet()
165188
HasSshPassword = this.hasSshPassword,
166189
PermissionScopes = this.PermissionScope,
167190
SshAuthorizedKeys = this.SshAuthorizedKey,
191+
IsNfSv3Enabled = this.isNfSv3Enabled,
192+
ExtendedGroups = this.ExtendedGroup is null ? null : this.ExtendedGroup.Cast<int?>().ToArray(),
168193
GroupId = this.GroupId,
169194
AllowAclAuthorization = this.AllowAclAuthorization,
170195
};
171196

172-
LocalUser localUser = this.StorageClient.LocalUsers.CreateOrUpdate(
173-
this.ResourceGroupName,
174-
this.StorageAccountName,
175-
this.UserName,
176-
localuser.ParseLocalUser());
197+
try
198+
{
199+
LocalUser localUser = this.StorageClient.LocalUsers.CreateOrUpdate(
200+
this.ResourceGroupName,
201+
this.StorageAccountName,
202+
this.UserName,
203+
localuser.ParseLocalUser());
204+
205+
WriteObject(new PSLocalUser(localUser, this.ResourceGroupName, this.StorageAccountName));
206+
}
177207

178-
WriteObject(new PSLocalUser(localUser, this.ResourceGroupName, this.StorageAccountName));
208+
catch (ErrorResponseException e)
209+
{
210+
if (e.Body != null && e.Body.Error != null && e.Body.Error.Message != null)
211+
{
212+
// sdk will not add the detail error message to exception message for custmized error, so create a new exception with detail error in exception message
213+
ErrorResponseException newex = new ErrorResponseException(e.Body.Error.Message, e);
214+
newex.Request = e.Request;
215+
newex.Response = e.Response;
216+
newex.Source = e.Source;
217+
newex.Body = e.Body;
218+
throw newex;
219+
}
220+
else
221+
{
222+
throw e;
223+
}
224+
}
179225
}
180226
}
181227
}

0 commit comments

Comments
 (0)