Skip to content

Commit ab6e76d

Browse files
authored
Added privatelink support to keyvault, storage, and monitor (#11525)
* Add storage endpoint * add storage * Add private endpoint connection support to keyvault, storage and monitor * Add private endpoint connection support to keyvault, storage and monitor * Revise according to review * Revise according to review
1 parent 74947e0 commit ab6e76d

File tree

6 files changed

+2719
-29
lines changed

6 files changed

+2719
-29
lines changed

src/Network/Network.Test/ScenarioTests/PrivateLinkServiceTests.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,13 @@ public void TestPrivateEndpointConnectionCRUD()
4040
{
4141
TestRunner.RunTestScript("Test-PrivateEndpointConnectionCRUD");
4242
}
43+
44+
[Fact]
45+
[Trait(Category.AcceptanceType, Category.CheckIn)]
46+
[Trait(Category.Owner, NrpTeamAlias.sdnnrp)]
47+
public void TestStoragePrivateEndpoint()
48+
{
49+
TestRunner.RunTestScript("Test-StoragePrivateEndpoint");
50+
}
4351
}
4452
}

src/Network/Network.Test/ScenarioTests/PrivateLinkServiceTests.ps1

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,3 +205,58 @@ function Test-PrivateEndpointConnectionCRUD
205205
Clean-ResourceGroup $rgname;
206206
}
207207
}
208+
209+
<#
210+
.SYNOPSIS
211+
Test operation for StoragePrivateEndpoint.
212+
#>
213+
function Test-StoragePrivateEndpoint
214+
{
215+
# Setup
216+
$rgname = Get-ResourceGroupName;
217+
$location = Get-ProviderLocation "Microsoft.Network/privateLinkServices" "eastus";
218+
$peName = "mype";
219+
$storageAccount = "xdmsa2";
220+
$subId = getSubscription
221+
222+
try
223+
{
224+
$resourceGroup = New-AzResourceGroup -Name $rgname -Location $location;
225+
New-AzStorageAccount -ResourceGroupName $rgname -AccountName $storageAccount -Location $location -SkuName Standard_GRS
226+
227+
$resourceId = "/subscriptions/$subId/resourceGroups/$rgname/providers/Microsoft.Storage/storageAccounts/$storageAccount";
228+
229+
$peSubnet = New-AzVirtualNetworkSubnetConfig -Name peSubnet -AddressPrefix "11.0.1.0/24" -PrivateEndpointNetworkPolicies "Disabled"
230+
$vnetPE = New-AzVirtualNetwork -Name "vnetPE" -ResourceGroupName $rgname -Location $location -AddressPrefix "11.0.0.0/16" -Subnet $peSubnet
231+
232+
$plsConnection= New-AzPrivateLinkServiceConnection -Name plsConnection -PrivateLinkServiceId $resourceId -GroupId 'blob'
233+
$privateEndpoint = New-AzPrivateEndpoint -ResourceGroupName $rgname -Name $peName -Location $location -Subnet $vnetPE.subnets[0] -PrivateLinkServiceConnection $plsConnection -ByManualRequest
234+
235+
$pecGet = Get-AzPrivateEndpointConnection -PrivateLinkResourceId $resourceId
236+
Assert-NotNull $pecGet;
237+
Assert-AreEqual "Pending" $pecGet.PrivateLinkServiceConnectionState.Status
238+
239+
# Approve Private Endpoint Connection
240+
$pecApprove = Approve-AzPrivateEndpointConnection -ResourceId $pecGet.Id
241+
Assert-NotNull $pecApprove;
242+
Assert-AreEqual "Approved" $pecApprove.PrivateLinkServiceConnectionState.Status
243+
244+
Start-TestSleep 20000
245+
246+
# Remove Private Endpoint Connection
247+
$pecRemove = Remove-AzPrivateEndpointConnection -ResourceId $pecGet.Id -PassThru -Force
248+
Assert-AreEqual true $pecRemove
249+
250+
Start-TestSleep 15000
251+
252+
# Get Private Endpoint Connection again
253+
$pecGet2 = Get-AzPrivateEndpointConnection -PrivateLinkResourceId $resourceId
254+
Assert-Null($pecGet2)
255+
256+
}
257+
finally
258+
{
259+
# Cleanup
260+
Clean-ResourceGroup $rgname;
261+
}
262+
}

src/Network/Network.Test/SessionRecords/Commands.Network.Test.ScenarioTests.PrivateLinkServiceTests/TestStoragePrivateEndpoint.json

Lines changed: 2544 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using Newtonsoft.Json;
2+
using System.Collections.Generic;
3+
4+
namespace Microsoft.Azure.Commands.Network.PrivateLinkService.Models
5+
{
6+
[Rest.Serialization.JsonTransformation]
7+
public partial class TrackedResource : ProxyResource
8+
{
9+
10+
public TrackedResource()
11+
{
12+
CustomInit();
13+
}
14+
15+
public TrackedResource(string id = default(string), string name = default(string), string type = default(string), IList<PrivateEndpointConnection> privateEndpointConnections = default(IList<PrivateEndpointConnection>))
16+
: base(id, name, type)
17+
{
18+
PrivateEndpointConnections = privateEndpointConnections;
19+
CustomInit();
20+
}
21+
22+
partial void CustomInit();
23+
24+
[JsonProperty(PropertyName = "properties.privateEndpointConnections")]
25+
public IList<PrivateEndpointConnection> PrivateEndpointConnections { get; private set; }
26+
27+
}
28+
}

src/Network/Network/PrivateLinkService/PrivateLinkServiceProvider/GenericProvider.cs

Lines changed: 46 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -24,32 +24,26 @@ namespace Microsoft.Azure.Commands.Network.PrivateLinkService.PrivateLinkService
2424
{
2525
internal class GenericProvider : IPrivateLinkProvider
2626
{
27-
28-
private static IDictionary<string, string> _apiVersions = new Dictionary<string, string>{
29-
{"microsoft.sql/servers", "2018-06-01-preview"}
30-
};
31-
3227
#region Constructor
3328
public GenericProvider(NetworkBaseCmdlet baseCmdlet, string subscription, string privateLinkResourceType)
3429
{
3530
this.BaseCmdlet = baseCmdlet;
3631
this._subscription = subscription;
37-
this._privateLinkResourceType = privateLinkResourceType;
38-
this._apiVersion = _apiVersions[privateLinkResourceType?.ToLower()];
32+
this._configuration = ProviderConfiguration.GetProviderConfiguration(privateLinkResourceType);
3933
}
4034
#endregion
4135

4236
#region Interface Implementation
4337

4438
public static bool SupportsPrivateLinkResourceType(string privateLinkResourceType)
4539
{
46-
return _apiVersions.ContainsKey(privateLinkResourceType?.ToLower());
40+
ProviderConfiguration configuration = ProviderConfiguration.GetProviderConfiguration(privateLinkResourceType);
41+
return (configuration != null);
4742
}
4843

4944
public NetworkBaseCmdlet BaseCmdlet { get; set; }
5045
private string _subscription;
51-
private string _privateLinkResourceType;
52-
private string _apiVersion;
46+
private ProviderConfiguration _configuration;
5347

5448
private IAzureRestClient _client;
5549
private IAzureRestClient ServiceClient
@@ -70,36 +64,53 @@ private IAzureRestClient ServiceClient
7064
public PSPrivateEndpointConnection GetPrivateEndpointConnection(string resourceGroupName, string serviceName, string name)
7165
{
7266
string url = BuildPrivateEndpointConnectionURL(resourceGroupName, serviceName, name);
73-
PrivateEndpointConnection connnection = ServiceClient.Operations.GetResouce<PrivateEndpointConnection>(url, _apiVersion);
67+
PrivateEndpointConnection connnection = ServiceClient.Operations.GetResouce<PrivateEndpointConnection>(url, _configuration.ApiVersion);
7468
return ToPsPrivateEndpointConnection(connnection);
7569
}
7670

7771
public List<PSPrivateEndpointConnection> ListPrivateEndpointConnections(string resourceGroupName, string serviceName)
7872
{
7973
var psPECs = new List<PSPrivateEndpointConnection>();
80-
string url = BuildPrivateEndpointConnectionsURL(resourceGroupName, serviceName);
81-
IPage<PrivateEndpointConnection> list = ServiceClient.Operations.GetResoucePage<Page<PrivateEndpointConnection>, PrivateEndpointConnection>(url, _apiVersion);
82-
foreach (var pec in list)
83-
{
84-
var psPec = ToPsPrivateEndpointConnection(pec);
85-
psPECs.Add(psPec);
86-
}
87-
while (list.NextPageLink != null)
74+
if(_configuration.HasConnectionsURI)
8875
{
89-
list = ServiceClient.Operations.GetResoucePage<Page<PrivateEndpointConnection>, PrivateEndpointConnection>(list.NextPageLink, null);
76+
string url = BuildPrivateEndpointConnectionsURL(resourceGroupName, serviceName);
77+
IPage<PrivateEndpointConnection> list = ServiceClient.Operations.GetResoucePage<Page<PrivateEndpointConnection>, PrivateEndpointConnection>(url, _configuration.ApiVersion);
9078
foreach (var pec in list)
9179
{
9280
var psPec = ToPsPrivateEndpointConnection(pec);
9381
psPECs.Add(psPec);
9482
}
83+
while (list.NextPageLink != null)
84+
{
85+
list = ServiceClient.Operations.GetResoucePage<Page<PrivateEndpointConnection>, PrivateEndpointConnection>(list.NextPageLink, null);
86+
foreach (var pec in list)
87+
{
88+
var psPec = ToPsPrivateEndpointConnection(pec);
89+
psPECs.Add(psPec);
90+
}
91+
}
92+
}
93+
else
94+
{
95+
string url = BuildPrivateEndpointConnectionsOwnerURL(resourceGroupName, serviceName);
96+
TrackedResource resource = ServiceClient.Operations.GetResouce<TrackedResource>(url, _configuration.ApiVersion);
97+
if(resource?.PrivateEndpointConnections != null)
98+
{
99+
foreach (var pec in resource.PrivateEndpointConnections)
100+
{
101+
var psPec = ToPsPrivateEndpointConnection(pec);
102+
psPECs.Add(psPec);
103+
}
104+
}
95105
}
106+
96107
return psPECs;
97108
}
98109

99110
public PSPrivateEndpointConnection UpdatePrivateEndpointConnectionStatus(string resourceGroupName, string serviceName, string name, string status, string description = null)
100111
{
101112
string url = BuildPrivateEndpointConnectionURL(resourceGroupName, serviceName, name);
102-
PrivateEndpointConnection privateEndpointConnection = ServiceClient.Operations.GetResouce<PrivateEndpointConnection>(url, _apiVersion);
113+
PrivateEndpointConnection privateEndpointConnection = ServiceClient.Operations.GetResouce<PrivateEndpointConnection>(url, _configuration.ApiVersion);
103114

104115
privateEndpointConnection.PrivateLinkServiceConnectionState.Status = status;
105116

@@ -108,29 +119,29 @@ public PSPrivateEndpointConnection UpdatePrivateEndpointConnectionStatus(string
108119
privateEndpointConnection.PrivateLinkServiceConnectionState.Description = description;
109120
}
110121

111-
ServiceClient.Operations.PutResouce<PrivateEndpointConnection>(url, _apiVersion, privateEndpointConnection);
122+
ServiceClient.Operations.PutResouce<PrivateEndpointConnection>(url, _configuration.ApiVersion, privateEndpointConnection);
112123

113124
return GetPrivateEndpointConnection(resourceGroupName, serviceName, name);
114125
}
115126

116127
public void DeletePrivateEndpointConnection(string resourceGroupName, string serviceName, string name)
117128
{
118129
string url = BuildPrivateEndpointConnectionURL(resourceGroupName, serviceName, name);
119-
ServiceClient.Operations.DeleteResouce(url, _apiVersion);
130+
ServiceClient.Operations.DeleteResouce(url, _configuration.ApiVersion);
120131
}
121132

122133
public PSPrivateLinkResource GetPrivateLinkResource(string resourceGroupName, string serviceName, string name)
123134
{
124135
string url = BuildPrivateLinkResourceURL(resourceGroupName, serviceName, name);
125-
PrivateLinkResource resource = ServiceClient.Operations.GetResouce<PrivateLinkResource>(url, _apiVersion);
136+
PrivateLinkResource resource = ServiceClient.Operations.GetResouce<PrivateLinkResource>(url, _configuration.ApiVersion);
126137
return ToPsPrivateLinkResource(resource);
127138
}
128139

129140
public List<PSPrivateLinkResource> ListPrivateLinkResource(string resourceGroupName, string serviceName)
130141
{
131142
var psPLRs = new List<PSPrivateLinkResource>();
132143
string url = BuildPrivateLinkResourcesURL(resourceGroupName, serviceName);
133-
IPage<PrivateLinkResource> list = ServiceClient.Operations.GetResoucePage<Page<PrivateLinkResource>, PrivateLinkResource>(url, _apiVersion);
144+
IPage<PrivateLinkResource> list = ServiceClient.Operations.GetResoucePage<Page<PrivateLinkResource>, PrivateLinkResource>(url, _configuration.ApiVersion);
134145
foreach (var plr in list)
135146
{
136147
var psPlr = ToPsPrivateLinkResource(plr);
@@ -156,31 +167,37 @@ public List<PSPrivateLinkResource> ListPrivateLinkResource(string resourceGroupN
156167
/// </summary>
157168
private string BuildPrivateLinkResourcesURL(string resourceGroupName, string serviceName)
158169
{
159-
return $"/subscriptions/{_subscription}/resourceGroups/{resourceGroupName}/providers/{_privateLinkResourceType}/{serviceName}/privateLinkResources";
170+
return $"/subscriptions/{_subscription}/resourceGroups/{resourceGroupName}/providers/{_configuration.Type}/{serviceName}/privateLinkResources";
160171
}
161172

162173
/// <summary>
163174
/// /subscriptions/{_subscription}/resourceGroups/{resourceGroupName}/providers/{_privateLinkResourceType}/{serviceName}/privateLinkResources/{name}
164175
/// </summary>
165176
private string BuildPrivateLinkResourceURL(string resourceGroupName, string serviceName, string name)
166177
{
167-
return $"/subscriptions/{_subscription}/resourceGroups/{resourceGroupName}/providers/{_privateLinkResourceType}/{serviceName}/privateLinkResources/{name}";
178+
return $"/subscriptions/{_subscription}/resourceGroups/{resourceGroupName}/providers/{_configuration.Type}/{serviceName}/privateLinkResources/{name}";
168179
}
169180

170181
/// <summary>
171182
/// /subscriptions/{_subscription}/resourceGroups/{resourceGroupName}/providers/{_privateLinkResourceType}/{serviceName}/privateEndpointConnections
172183
/// </summary>
173184
private string BuildPrivateEndpointConnectionsURL(string resourceGroupName, string serviceName)
174185
{
175-
return $"/subscriptions/{_subscription}/resourceGroups/{resourceGroupName}/providers/{_privateLinkResourceType}/{serviceName}/privateEndpointConnections";
186+
return $"/subscriptions/{_subscription}/resourceGroups/{resourceGroupName}/providers/{_configuration.Type}/{serviceName}/privateEndpointConnections";
176187
}
177188

189+
private string BuildPrivateEndpointConnectionsOwnerURL(string resourceGroupName, string serviceName)
190+
{
191+
return $"/subscriptions/{_subscription}/resourceGroups/{resourceGroupName}/providers/{_configuration.Type}/{serviceName}";
192+
}
193+
194+
178195
/// <summary>
179196
/// /subscriptions/{_subscription}/resourceGroups/{resourceGroupName}/providers/{_privateLinkResourceType}/{serviceName}/privateEndpointConnections/{name}
180197
/// </summary>
181198
private string BuildPrivateEndpointConnectionURL(string resourceGroupName, string serviceName, string name)
182199
{
183-
return $"/subscriptions/{_subscription}/resourceGroups/{resourceGroupName}/providers/{_privateLinkResourceType}/{serviceName}/privateEndpointConnections/{name}";
200+
return $"/subscriptions/{_subscription}/resourceGroups/{resourceGroupName}/providers/{_configuration.Type}/{serviceName}/privateEndpointConnections/{name}";
184201
}
185202

186203
private PSPrivateEndpointConnection ToPsPrivateEndpointConnection(PrivateEndpointConnection privateEndpointConnection)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Microsoft.Azure.Commands.Network.PrivateLinkService.PrivateLinkServiceProvider
6+
{
7+
internal class ProviderConfiguration
8+
{
9+
10+
private static IDictionary<string, ProviderConfiguration> _configurations = new Dictionary<string, ProviderConfiguration>();
11+
12+
static ProviderConfiguration()
13+
{
14+
RegisterConfiguration("Microsoft.Sql/servers", "2018-06-01-preview");
15+
RegisterConfiguration("Microsoft.Insights/privateLinkScopes", "2019-10-17-preview");
16+
RegisterConfiguration("Microsoft.Storage/storageAccounts", "2019-06-01", false);
17+
RegisterConfiguration("Microsoft.KeyVault/vaults", "2019-09-01", false);
18+
}
19+
20+
private static void RegisterConfiguration(string type, string apiVersion, bool hasConnectionsURI = true)
21+
{
22+
ProviderConfiguration configuration = new ProviderConfiguration();
23+
configuration.Type = type;
24+
configuration.ApiVersion = apiVersion;
25+
configuration.HasConnectionsURI = hasConnectionsURI;
26+
_configurations.Add(type.ToLower(), configuration);
27+
}
28+
29+
public string Type { get; set; }
30+
public string ApiVersion { get; set; }
31+
public bool HasConnectionsURI { get; set; }
32+
33+
public static ProviderConfiguration GetProviderConfiguration(string type)
34+
{
35+
return _configurations[type?.ToLower()];
36+
}
37+
}
38+
}

0 commit comments

Comments
 (0)