-
Notifications
You must be signed in to change notification settings - Fork 351
/
AzureStorageExtensions.cs
223 lines (194 loc) · 12.1 KB
/
AzureStorageExtensions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics.CodeAnalysis;
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Azure;
using Aspire.Hosting.Utils;
using Azure.Provisioning;
using Azure.Provisioning.Storage;
using Azure.ResourceManager.Storage.Models;
namespace Aspire.Hosting;
/// <summary>
/// Extension methods for adding Azure Storage resources to an application model.
/// </summary>
public static class AzureStorageExtensions
{
/// <summary>
/// Adds an Azure Storage resource to the application model.This resource can be used to create Azure blob, table, and queue resources.
/// </summary>
/// <param name="builder">The builder for the distributed application.</param>
/// <param name="name">The name of the resource.</param>
/// <returns></returns>
public static IResourceBuilder<AzureStorageResource> AddAzureStorage(this IDistributedApplicationBuilder builder, string name)
{
#pragma warning disable AZPROVISION001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
return builder.AddAzureStorage(name, null);
#pragma warning restore AZPROVISION001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
}
/// <summary>
/// Adds an Azure Storage resource to the application model.This resource can be used to create Azure blob, table, and queue resources.
/// </summary>
/// <param name="builder">The builder for the distributed application.</param>
/// <param name="name">The name of the resource.</param>
/// <param name="configureResource">Callback to configure the underlying <see cref="global::Azure.Provisioning.Storage.StorageAccount"/> resource.</param>
/// <returns></returns>
[Experimental("AZPROVISION001", UrlFormat = "https://aka.ms/dotnet/aspire/diagnostics#{0}")]
public static IResourceBuilder<AzureStorageResource> AddAzureStorage(this IDistributedApplicationBuilder builder, string name, Action<IResourceBuilder<AzureStorageResource>, ResourceModuleConstruct, StorageAccount>? configureResource)
{
builder.AddAzureProvisioning();
var configureConstruct = (ResourceModuleConstruct construct) =>
{
var storageAccount = construct.AddStorageAccount(
name: name,
kind: StorageKind.StorageV2,
sku: StorageSkuName.StandardGrs
);
// Unfortunately Azure Storage does not list ACA as one of the resource types in which
// the AzureServices firewall policy works. This means that we need this Azure Storage
// account to have its default action set to Allow.
storageAccount.AssignProperty(p => p.NetworkRuleSet.DefaultAction, "'Allow'");
storageAccount.Properties.Tags["aspire-resource-name"] = construct.Resource.Name;
var blobService = new BlobService(construct);
var blobRole = storageAccount.AssignRole(RoleDefinition.StorageBlobDataContributor);
blobRole.AssignProperty(p => p.PrincipalId, construct.PrincipalIdParameter);
blobRole.AssignProperty(p => p.PrincipalType, construct.PrincipalTypeParameter);
var tableRole = storageAccount.AssignRole(RoleDefinition.StorageTableDataContributor);
tableRole.AssignProperty(p => p.PrincipalId, construct.PrincipalIdParameter);
tableRole.AssignProperty(p => p.PrincipalType, construct.PrincipalTypeParameter);
var queueRole = storageAccount.AssignRole(RoleDefinition.StorageQueueDataContributor);
queueRole.AssignProperty(p => p.PrincipalId, construct.PrincipalIdParameter);
queueRole.AssignProperty(p => p.PrincipalType, construct.PrincipalTypeParameter);
storageAccount.AddOutput("blobEndpoint", sa => sa.PrimaryEndpoints.BlobUri);
storageAccount.AddOutput("queueEndpoint", sa => sa.PrimaryEndpoints.QueueUri);
storageAccount.AddOutput("tableEndpoint", sa => sa.PrimaryEndpoints.TableUri);
var resource = (AzureStorageResource)construct.Resource;
var resourceBuilder = builder.CreateResourceBuilder(resource);
configureResource?.Invoke(resourceBuilder, construct, storageAccount);
};
var resource = new AzureStorageResource(name, configureConstruct);
return builder.AddResource(resource)
// These ambient parameters are only available in development time.
.WithParameter(AzureBicepResource.KnownParameters.PrincipalId)
.WithParameter(AzureBicepResource.KnownParameters.PrincipalType)
.WithManifestPublishingCallback(resource.WriteToManifest);
}
/// <summary>
/// Configures an Azure Storage resource to be emulated using Azurite. This resource requires an <see cref="AzureStorageResource"/> to be added to the application model. This version the package defaults to version 3.29.0 of the mcr.microsoft.com/azure-storage/azurite container image.
/// </summary>
/// <param name="builder">The Azure storage resource builder.</param>
/// <param name="configureContainer">Callback that exposes underlying container used for emulation to allow for customization.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<AzureStorageResource> RunAsEmulator(this IResourceBuilder<AzureStorageResource> builder, Action<IResourceBuilder<AzureStorageEmulatorResource>>? configureContainer = null)
{
if (builder.ApplicationBuilder.ExecutionContext.IsPublishMode)
{
return builder;
}
builder.WithEndpoint(name: "blob", targetPort: 10000)
.WithEndpoint(name: "queue", targetPort: 10001)
.WithEndpoint(name: "table", targetPort: 10002)
.WithAnnotation(new ContainerImageAnnotation
{
Registry = "mcr.microsoft.com",
Image = "azure-storage/azurite",
Tag = "3.29.0"
});
if (configureContainer != null)
{
var surrogate = new AzureStorageEmulatorResource(builder.Resource);
var surrogateBuilder = builder.ApplicationBuilder.CreateResourceBuilder(surrogate);
configureContainer(surrogateBuilder);
}
return builder;
}
/// <summary>
/// Adds a bind mount for the data folder to an Azure Storage emulator resource.
/// </summary>
/// <param name="builder">The builder for the <see cref="AzureStorageEmulatorResource"/>.</param>
/// <param name="path">Relative path to the AppHost where emulator storage is persisted between runs. Defaults to the path '.azurite/{builder.Resource.Name}'</param>
/// <param name="isReadOnly">A flag that indicates if this is a read-only mount.</param>
/// <returns>A builder for the <see cref="AzureStorageEmulatorResource"/>.</returns>
public static IResourceBuilder<AzureStorageEmulatorResource> WithDataBindMount(this IResourceBuilder<AzureStorageEmulatorResource> builder, string? path = null, bool isReadOnly = false)
=> builder.WithBindMount(path ?? $".azurite/{builder.Resource.Name}", "/data", isReadOnly);
/// <summary>
/// Adds a named volume for the data folder to an Azure Storage emulator resource.
/// </summary>
/// <param name="builder">The builder for the <see cref="AzureStorageEmulatorResource"/>.</param>
/// <param name="name">The name of the volume. Defaults to an auto-generated name based on the application and resource names.</param>
/// <param name="isReadOnly">A flag that indicates if this is a read-only volume.</param>
/// <returns>A builder for the <see cref="AzureStorageEmulatorResource"/>.</returns>
public static IResourceBuilder<AzureStorageEmulatorResource> WithDataVolume(this IResourceBuilder<AzureStorageEmulatorResource> builder, string? name = null, bool isReadOnly = false)
=> builder.WithVolume(name ?? VolumeNameGenerator.CreateVolumeName(builder, "data"), "/data", isReadOnly);
/// <summary>
/// Modifies the host port that the storage emulator listens on for blob requests.
/// </summary>
/// <param name="builder">Storage emulator resource builder.</param>
/// <param name="port">Host port to use.</param>
/// <returns></returns>
public static IResourceBuilder<AzureStorageEmulatorResource> WithBlobPort(this IResourceBuilder<AzureStorageEmulatorResource> builder, int port)
{
return builder.WithEndpoint("blob", endpoint =>
{
endpoint.Port = port;
});
}
/// <summary>
/// Modifies the host port that the storage emulator listens on for queue requests.
/// </summary>
/// <param name="builder">Storage emulator resource builder.</param>
/// <param name="port">Host port to use.</param>
/// <returns></returns>
public static IResourceBuilder<AzureStorageEmulatorResource> WithQueuePort(this IResourceBuilder<AzureStorageEmulatorResource> builder, int port)
{
return builder.WithEndpoint("queue", endpoint =>
{
endpoint.Port = port;
});
}
/// <summary>
/// Modifies the host port that the storage emulator listens on for table requests.
/// </summary>
/// <param name="builder">Storage emulator resource builder.</param>
/// <param name="port">Host port to use.</param>
/// <returns></returns>
public static IResourceBuilder<AzureStorageEmulatorResource> WithTablePort(this IResourceBuilder<AzureStorageEmulatorResource> builder, int port)
{
return builder.WithEndpoint("table", endpoint =>
{
endpoint.Port = port;
});
}
/// <summary>
/// Creates a builder for the <see cref="AzureBlobStorageResource"/> which can be referenced to get the Azure Storage blob endpoint for the storage account.
/// </summary>
/// <param name="builder">The <see cref="IResourceBuilder{T}"/> for <see cref="AzureStorageResource"/>/</param>
/// <param name="name">The name of the resource.</param>
/// <returns>An <see cref="IResourceBuilder{T}"/> for the <see cref="AzureBlobStorageResource"/>.</returns>
public static IResourceBuilder<AzureBlobStorageResource> AddBlobs(this IResourceBuilder<AzureStorageResource> builder, string name)
{
var resource = new AzureBlobStorageResource(name, builder.Resource);
return builder.ApplicationBuilder.AddResource(resource);
}
/// <summary>
/// Creates a builder for the <see cref="AzureTableStorageResource"/> which can be referenced to get the Azure Storage tables endpoint for the storage account.
/// </summary>
/// <param name="builder">The <see cref="IResourceBuilder{T}"/> for <see cref="AzureStorageResource"/>/</param>
/// <param name="name">The name of the resource.</param>
/// <returns>An <see cref="IResourceBuilder{T}"/> for the <see cref="AzureTableStorageResource"/>.</returns>
public static IResourceBuilder<AzureTableStorageResource> AddTables(this IResourceBuilder<AzureStorageResource> builder, string name)
{
var resource = new AzureTableStorageResource(name, builder.Resource);
return builder.ApplicationBuilder.AddResource(resource);
}
/// <summary>
/// Creates a builder for the <see cref="AzureQueueStorageResource"/> which can be referenced to get the Azure Storage queues endpoint for the storage account.
/// </summary>
/// <param name="builder">The <see cref="IResourceBuilder{T}"/> for <see cref="AzureStorageResource"/>/</param>
/// <param name="name">The name of the resource.</param>
/// <returns>An <see cref="IResourceBuilder{T}"/> for the <see cref="AzureQueueStorageResource"/>.</returns>
public static IResourceBuilder<AzureQueueStorageResource> AddQueues(this IResourceBuilder<AzureStorageResource> builder, string name)
{
var resource = new AzureQueueStorageResource(name, builder.Resource);
return builder.ApplicationBuilder.AddResource(resource);
}
}