Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"appHostPath": "../CommunityToolkit.Aspire.Hosting.Azure.Dapr.AppHost.csproj"
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@


builder.AddProject<Projects.CommunityToolkit_Aspire_Hosting_Dapr_ServiceA>("servicea")
.WithReference(redis)
.PublishAsAzureContainerApp((i,c)=> { })
.WithDaprSidecar(sidecar => sidecar.WithReference(stateStore).WithReference(pubSub))
.WaitFor(redis);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
using Azure.Provisioning.AppContainers;
using Azure.Provisioning.Expressions;
using Azure.Provisioning.KeyVault;
using Azure.Provisioning.Redis;
using Azure.Provisioning.Roles;
using CommunityToolkit.Aspire.Hosting.Azure.Dapr;
using CommunityToolkit.Aspire.Hosting.Dapr;
using AzureRedisResource = Azure.Provisioning.Redis.RedisResource;
using CdkRedisResource = Azure.Provisioning.Redis.RedisResource;
using RedisResource = Aspire.Hosting.ApplicationModel.RedisResource;

namespace Aspire.Hosting;

Expand Down Expand Up @@ -91,16 +93,12 @@

private static void ConfigureForManagedIdentityAuthentication(this IResourceBuilder<IDaprComponentResource> builder, IResourceBuilder<AzureRedisCacheResource> redisBuilder, string componentType)
{
var principalIdParam = new ProvisioningParameter(AzureBicepResource.KnownParameters.PrincipalId, typeof(string));

var configureInfrastructure = (AzureResourceInfrastructure infrastructure) =>
var configureInfrastructure = (AzureResourceInfrastructure infrastructure, UserAssignedIdentity daprIdentity) =>
{
var redisHostParam = redisBuilder.GetOutput(daprConnectionStringKey).AsProvisioningParameter(infrastructure, redisHostKey);

var provisionableResources = infrastructure.GetProvisionableResources();
if (provisionableResources.OfType<ContainerAppManagedEnvironment>().FirstOrDefault()
is ContainerAppManagedEnvironment managedEnvironment &&
provisionableResources.OfType<UserAssignedIdentity>().FirstOrDefault() is UserAssignedIdentity identity)
if (provisionableResources.OfType<ContainerAppManagedEnvironment>().FirstOrDefault() is ContainerAppManagedEnvironment managedEnvironment)
{
var daprComponent = AzureDaprHostingExtensions.CreateDaprComponent(
builder.Resource.Name,
Expand All @@ -115,7 +113,7 @@
new() { Name = redisHostKey, Value = redisHostParam },
new() { Name = "enableTLS", Value = "true" },
new() { Name = "useEntraID", Value = "true" },
new() { Name = "azureClientId", Value = identity.PrincipalId }
new() { Name = "azureClientId", Value = daprIdentity.PrincipalId }
};

// Add state-specific metadata
Expand All @@ -124,6 +122,25 @@
metadata.Add(new ContainerAppDaprMetadata { Name = "actorStateStore", Value = "true" });
}

if (redisBuilder.Resource.AddAsExistingResource(infrastructure) is CdkRedisResource redis)
{
var redisBicepIdentifier = redisBuilder.Resource.GetBicepIdentifier();
var policyBicepIdentifier = $"{redisBicepIdentifier}_contributor";
if (!infrastructure.GetProvisionableResources().OfType<RedisCacheAccessPolicyAssignment>().Any(r => r.BicepIdentifier == policyBicepIdentifier))
{

infrastructure.Add(new RedisCacheAccessPolicyAssignment($"{redisBicepIdentifier}_contributor")
{
Name = BicepFunction.CreateGuid(redis.Id, daprIdentity.PrincipalId, "Data Contributor"),
Parent = redis,
AccessPolicyName = "Data Contributor",
ObjectId = daprIdentity.PrincipalId,
ObjectIdAlias = daprIdentity.Name
});
}

}

daprComponent.Metadata = [.. metadata];

// Add scopes if any exist
Expand All @@ -132,15 +149,18 @@
infrastructure.Add(daprComponent);

infrastructure.TryAdd(redisHostParam);

}
};


//builder.WithRoleAssignments(redisBuilder, RedisBuiltInRole.GetBuiltInRoleName, [RedisBuiltInRole.RedisCacheContributor]);
builder.WithAnnotation(new AzureDaprComponentPublishingAnnotation(configureInfrastructure));

// Configure the Redis resource to output the connection string
redisBuilder.ConfigureInfrastructure(infrastructure =>
{
var redisResource = infrastructure.GetProvisionableResources().OfType<AzureRedisResource>().SingleOrDefault();
var redisResource = infrastructure.GetProvisionableResources().OfType<CdkRedisResource>().SingleOrDefault();
var outputExists = infrastructure.GetProvisionableResources().OfType<ProvisioningOutput>().Any(o => o.BicepIdentifier == daprConnectionStringKey);

if (redisResource is not null && !outputExists)
Expand All @@ -162,7 +182,7 @@
// Configure Key Vault secret store component - this adds the annotation to the same resource
builder.ConfigureKeyVaultSecretsComponent(kvNameParam);

var configureInfrastructure = (AzureResourceInfrastructure infrastructure) =>
var configureInfrastructure = (AzureResourceInfrastructure infrastructure, UserAssignedIdentity daprIdentity) =>
{
var redisHostParam = redisBuilder.GetOutput(daprConnectionStringKey).AsProvisioningParameter(infrastructure, redisHostKey);

Expand All @@ -183,6 +203,7 @@
new() { Name = "redisPassword", SecretRef = "redis-password" }
};

// TODO: Make this configurable - perhaps AddDaprStateStore().AsActorStateStore() or similar
// Add state-specific metadata
if (componentType == "state.redis")
{
Expand All @@ -208,7 +229,7 @@
// Configure the Redis resource to output the connection string and set up Key Vault secret
redisBuilder.ConfigureInfrastructure(infrastructure =>
{
var redisResource = infrastructure.GetProvisionableResources().OfType<AzureRedisResource>().SingleOrDefault();

Check failure on line 232 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / run-tests / Hosting.Azure.Dapr.Redis.Tests-ubuntu-latest

This call will always result in an empty sequence because type 'Azure.Provisioning.Primitives.Provisionable' is incompatible with type 'Aspire.Hosting.Azure.AzureRedisResource' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2021)

Check failure on line 232 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / run-tests / Hosting.Azure.Dapr.Redis.Tests-ubuntu-latest

'AzureRedisResource' is obsolete: 'This class is obsolete and will be removed in a future version. Use AddAzureRedis instead to add an Azure Cache for Redis resource.'

Check failure on line 232 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / run-tests / Hosting.Azure.Dapr.Redis.Tests-ubuntu-latest

This call will always result in an empty sequence because type 'Azure.Provisioning.Primitives.Provisionable' is incompatible with type 'Aspire.Hosting.Azure.AzureRedisResource' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2021)

Check failure on line 232 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / run-tests / Hosting.Azure.Dapr.Redis.Tests-ubuntu-latest

'AzureRedisResource' is obsolete: 'This class is obsolete and will be removed in a future version. Use AddAzureRedis instead to add an Azure Cache for Redis resource.'

Check failure on line 232 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

This call will always result in an empty sequence because type 'Azure.Provisioning.Primitives.Provisionable' is incompatible with type 'Aspire.Hosting.Azure.AzureRedisResource' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2021)

Check failure on line 232 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

'AzureRedisResource' is obsolete: 'This class is obsolete and will be removed in a future version. Use AddAzureRedis instead to add an Azure Cache for Redis resource.'

Check failure on line 232 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

This call will always result in an empty sequence because type 'Azure.Provisioning.Primitives.Provisionable' is incompatible with type 'Aspire.Hosting.Azure.AzureRedisResource' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2021)

Check failure on line 232 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

'AzureRedisResource' is obsolete: 'This class is obsolete and will be removed in a future version. Use AddAzureRedis instead to add an Azure Cache for Redis resource.'

Check failure on line 232 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / run-tests / Hosting.Azure.Dapr.Redis.Tests-windows-latest

This call will always result in an empty sequence because type 'Azure.Provisioning.Primitives.Provisionable' is incompatible with type 'Aspire.Hosting.Azure.AzureRedisResource' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2021)

Check failure on line 232 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / run-tests / Hosting.Azure.Dapr.Redis.Tests-windows-latest

'AzureRedisResource' is obsolete: 'This class is obsolete and will be removed in a future version. Use AddAzureRedis instead to add an Azure Cache for Redis resource.'

Check failure on line 232 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / run-tests / Hosting.Azure.Dapr.Redis.Tests-windows-latest

This call will always result in an empty sequence because type 'Azure.Provisioning.Primitives.Provisionable' is incompatible with type 'Aspire.Hosting.Azure.AzureRedisResource' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2021)

Check failure on line 232 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / run-tests / Hosting.Azure.Dapr.Redis.Tests-windows-latest

'AzureRedisResource' is obsolete: 'This class is obsolete and will be removed in a future version. Use AddAzureRedis instead to add an Azure Cache for Redis resource.'

Check failure on line 232 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

This call will always result in an empty sequence because type 'Azure.Provisioning.Primitives.Provisionable' is incompatible with type 'Aspire.Hosting.Azure.AzureRedisResource' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2021)

Check failure on line 232 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

'AzureRedisResource' is obsolete: 'This class is obsolete and will be removed in a future version. Use AddAzureRedis instead to add an Azure Cache for Redis resource.'

Check failure on line 232 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

This call will always result in an empty sequence because type 'Azure.Provisioning.Primitives.Provisionable' is incompatible with type 'Aspire.Hosting.Azure.AzureRedisResource' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2021)

Check failure on line 232 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

'AzureRedisResource' is obsolete: 'This class is obsolete and will be removed in a future version. Use AddAzureRedis instead to add an Azure Cache for Redis resource.'
if (redisResource is not null)
{
var keyVault = infrastructure.GetProvisionableResources().OfType<KeyVaultService>().SingleOrDefault();
Expand All @@ -224,7 +245,7 @@
Name = "redis-password",
Properties = new SecretProperties
{
Value = redisResource.GetKeys().PrimaryKey

Check failure on line 248 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / run-tests / Hosting.Azure.Dapr.Redis.Tests-ubuntu-latest

'AzureRedisResource' does not contain a definition for 'GetKeys' and no accessible extension method 'GetKeys' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 248 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / run-tests / Hosting.Azure.Dapr.Redis.Tests-ubuntu-latest

'AzureRedisResource' does not contain a definition for 'GetKeys' and no accessible extension method 'GetKeys' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 248 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

'AzureRedisResource' does not contain a definition for 'GetKeys' and no accessible extension method 'GetKeys' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 248 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

'AzureRedisResource' does not contain a definition for 'GetKeys' and no accessible extension method 'GetKeys' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 248 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / run-tests / Hosting.Azure.Dapr.Redis.Tests-windows-latest

'AzureRedisResource' does not contain a definition for 'GetKeys' and no accessible extension method 'GetKeys' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 248 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / run-tests / Hosting.Azure.Dapr.Redis.Tests-windows-latest

'AzureRedisResource' does not contain a definition for 'GetKeys' and no accessible extension method 'GetKeys' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 248 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

'AzureRedisResource' does not contain a definition for 'GetKeys' and no accessible extension method 'GetKeys' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 248 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

'AzureRedisResource' does not contain a definition for 'GetKeys' and no accessible extension method 'GetKeys' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)
}
};

Expand All @@ -237,7 +258,7 @@

infrastructure.Add(new ProvisioningOutput(daprConnectionStringKey, typeof(string))
{
Value = BicepFunction.Interpolate($"{redisResource.HostName}:{redisResource.SslPort}")

Check failure on line 261 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / run-tests / Hosting.Azure.Dapr.Redis.Tests-ubuntu-latest

'AzureRedisResource' does not contain a definition for 'SslPort' and no accessible extension method 'SslPort' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 261 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / run-tests / Hosting.Azure.Dapr.Redis.Tests-ubuntu-latest

'AzureRedisResource' does not contain a definition for 'HostName' and no accessible extension method 'HostName' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 261 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / run-tests / Hosting.Azure.Dapr.Redis.Tests-ubuntu-latest

'AzureRedisResource' does not contain a definition for 'SslPort' and no accessible extension method 'SslPort' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 261 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / run-tests / Hosting.Azure.Dapr.Redis.Tests-ubuntu-latest

'AzureRedisResource' does not contain a definition for 'HostName' and no accessible extension method 'HostName' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 261 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

'AzureRedisResource' does not contain a definition for 'SslPort' and no accessible extension method 'SslPort' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 261 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

'AzureRedisResource' does not contain a definition for 'HostName' and no accessible extension method 'HostName' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 261 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

'AzureRedisResource' does not contain a definition for 'SslPort' and no accessible extension method 'SslPort' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 261 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

'AzureRedisResource' does not contain a definition for 'HostName' and no accessible extension method 'HostName' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 261 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / run-tests / Hosting.Azure.Dapr.Redis.Tests-windows-latest

'AzureRedisResource' does not contain a definition for 'SslPort' and no accessible extension method 'SslPort' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 261 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / run-tests / Hosting.Azure.Dapr.Redis.Tests-windows-latest

'AzureRedisResource' does not contain a definition for 'HostName' and no accessible extension method 'HostName' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 261 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / run-tests / Hosting.Azure.Dapr.Redis.Tests-windows-latest

'AzureRedisResource' does not contain a definition for 'SslPort' and no accessible extension method 'SslPort' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 261 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / run-tests / Hosting.Azure.Dapr.Redis.Tests-windows-latest

'AzureRedisResource' does not contain a definition for 'HostName' and no accessible extension method 'HostName' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 261 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

'AzureRedisResource' does not contain a definition for 'SslPort' and no accessible extension method 'SslPort' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 261 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

'AzureRedisResource' does not contain a definition for 'HostName' and no accessible extension method 'HostName' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 261 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

'AzureRedisResource' does not contain a definition for 'SslPort' and no accessible extension method 'SslPort' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 261 in src/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis/AzureRedisCacheDaprHostingExtensions.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

'AzureRedisResource' does not contain a definition for 'HostName' and no accessible extension method 'HostName' accepting a first argument of type 'AzureRedisResource' could be found (are you missing a using directive or an assembly reference?)
});
}
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Azure;
using Aspire.Hosting.Azure.AppContainers;
using Azure.Provisioning;
using Azure.Provisioning.AppContainers;
using Azure.Provisioning.Authorization;
using Azure.Provisioning.Expressions;
using Azure.Provisioning.Roles;
using CommunityToolkit.Aspire.Hosting.Azure.Dapr;
using CommunityToolkit.Aspire.Hosting.Dapr;

Expand All @@ -12,11 +16,14 @@ namespace Aspire.Hosting;
/// </summary>
public static class AzureContainerAppEnvironmentResourceBuilderExtensions
{
private const string DaprManagedIdentityKey = "daprManagedIdentity";

/// <summary>
/// Configures the Azure Container App Environment resource to use Dapr.
/// This method creates a dedicated managed identity for Dapr components and configures all Dapr components to use it.
/// </summary>
/// <param name="builder"></param>
/// <returns></returns>
/// <param name="builder">The Azure Container App Environment resource builder.</param>
/// <returns>The configured Azure Container App Environment resource builder.</returns>
public static IResourceBuilder<AzureContainerAppEnvironmentResource> WithDaprComponents(
this IResourceBuilder<AzureContainerAppEnvironmentResource> builder)
{
Expand Down Expand Up @@ -53,13 +60,38 @@ public static IResourceBuilder<AzureContainerAppEnvironmentResource> WithDaprCom

return builder.ConfigureInfrastructure(infrastructure =>
{
// Create the Dapr managed identity once
var daprIdentity = new UserAssignedIdentity(DaprManagedIdentityKey);

infrastructure.Add(daprIdentity);

var daprComponentResources = builder.ApplicationBuilder.Resources.OfType<IDaprComponentResource>();

foreach (var daprComponentResource in daprComponentResources)
{
if (daprComponentResource.TryGetLastAnnotation<RoleAssignmentAnnotation>(out var roleAssignmentAnnotation))
{
var target = roleAssignmentAnnotation.Target.AddAsExistingResource(infrastructure);

foreach (var roleDefinition in roleAssignmentAnnotation.Roles)
{
var id = new MemberExpression(new IdentifierExpression(roleAssignmentAnnotation.Target.GetBicepIdentifier()), "id");
var roleAssignment = new RoleAssignment($"{daprComponentResource.Name}{roleDefinition.Name}")
{
Name = BicepFunction.CreateGuid(id, daprIdentity.Id, BicepFunction.GetSubscriptionResourceId("Microsoft.Authorization/roleDefinitions", roleDefinition.Id)),
RoleDefinitionId = BicepFunction.GetSubscriptionResourceId("Microsoft.Authorization/roleDefinitions", roleDefinition.Id),
PrincipalId = daprIdentity.PrincipalId,
PrincipalType = RoleManagementPrincipalType.ServicePrincipal,
Scope = new IdentifierExpression(target.BicepIdentifier)
};

infrastructure.Add(roleAssignment);
}
}

daprComponentResource.TryGetLastAnnotation<AzureDaprComponentPublishingAnnotation>(out var publishingAnnotation);
publishingAnnotation?.PublishingAction(infrastructure, daprIdentity);

publishingAnnotation?.PublishingAction(infrastructure);
}
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Azure;
using Azure.Provisioning.Roles;

namespace CommunityToolkit.Aspire.Hosting.Azure.Dapr;
/// <summary>
Expand All @@ -10,4 +11,4 @@ namespace CommunityToolkit.Aspire.Hosting.Azure.Dapr;
/// allowing customization of the resource infrastructure.</remarks>
/// <param name="PublishingAction">The action to be executed on the <see cref="AzureResourceInfrastructure"/> during the publishing process. This
/// action allows for customization of the infrastructure configuration.</param>
public record AzureDaprComponentPublishingAnnotation(Action<AzureResourceInfrastructure> PublishingAction) : IResourceAnnotation;
public record AzureDaprComponentPublishingAnnotation(Action<AzureResourceInfrastructure, UserAssignedIdentity> PublishingAction) : IResourceAnnotation;
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,27 @@ public static IResourceBuilder<AzureDaprComponentResource> AddAzureDaprResource(
.WithManifestPublishingCallback(azureDaprComponentResource.WriteToManifest);
}

/// <summary>
/// Adds role assignments to the specified Azure resource, allowing the target resource to assume the specified built-in roles.
/// </summary>
/// <typeparam name="T">The type of the resource being configured.</typeparam>
/// <typeparam name="TTarget">The type of the target Azure resource to which roles are assigned.</typeparam>
/// <typeparam name="TBuiltInRole">The type representing built-in roles.</typeparam>
/// <param name="builder">The resource builder for the resource being configured.</param>
/// <param name="target">The resource builder for the target Azure resource to receive role assignments.</param>
/// <param name="getName">A function that returns the name of a role given a built-in role value.</param>
/// <param name="roles">An array of built-in roles to assign to the target resource.</param>
/// <returns>The updated resource builder with role assignments applied.</returns>
public static IResourceBuilder<T> WithRoleAssignments<T, TTarget, TBuiltInRole>(this IResourceBuilder<T> builder, IResourceBuilder<TTarget> target, Func<TBuiltInRole, string> getName, TBuiltInRole[] roles)
where T : IResource
where TTarget : AzureProvisioningResource
where TBuiltInRole : notnull
{
builder.WithAnnotation(new RoleAssignmentAnnotation(target.Resource, CreateRoleDefinitions(roles, getName)));
return builder;
}


/// <summary>
/// Adds scopes to the specified Dapr component in a container app managed environment.
/// </summary>
Expand Down Expand Up @@ -96,4 +117,10 @@ public static ContainerAppManagedEnvironmentDaprComponent CreateDaprComponent(
Version = version
};
}

private static HashSet<RoleDefinition> CreateRoleDefinitions<TBuiltInRole>(IReadOnlyList<TBuiltInRole> roles, Func<TBuiltInRole, string> getName)
where TBuiltInRole : notnull
{
return [.. roles.Select(r => new RoleDefinition(r.ToString()!, getName(r)))];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Azure.Provisioning;
using Azure.Provisioning.AppContainers;
using Azure.Provisioning.Expressions;
using Azure.Provisioning.KeyVault;
using Azure.Provisioning.Roles;
using CommunityToolkit.Aspire.Hosting.Azure.Dapr;
using CommunityToolkit.Aspire.Hosting.Dapr;

Expand All @@ -17,6 +17,8 @@ public static class AzureKeyVaultDaprHostingExtensions
private const string secretStoreComponentKey = "secretStoreComponent";
private const string secretStore = nameof(secretStore);



/// <summary>
/// Configures the Key Vault secret store component for the Dapr component resource.
/// </summary>
Expand All @@ -27,9 +29,9 @@ public static IResourceBuilder<IDaprComponentResource> ConfigureKeyVaultSecretsC
{
ArgumentNullException.ThrowIfNull(builder, nameof(builder));

var principalIdParameter = new ProvisioningParameter(AzureBicepResource.KnownParameters.PrincipalId, typeof(string));
//TODO: We may need to actually add the key vault resource here as well - I'm not sure if aspire automatically adds it anymore or not

var configureInfrastructure = (AzureResourceInfrastructure infrastructure) =>
var configureInfrastructure = (AzureResourceInfrastructure infrastructure, UserAssignedIdentity daprIdentity) =>
{
if (infrastructure.GetProvisionableResources().OfType<ContainerAppManagedEnvironment>().FirstOrDefault() is ContainerAppManagedEnvironment managedEnvironment)
{
Expand All @@ -43,12 +45,11 @@ public static IResourceBuilder<IDaprComponentResource> ConfigureKeyVaultSecretsC
daprComponent.Scopes = [];
daprComponent.Metadata = [
new ContainerAppDaprMetadata { Name = "vaultName", Value = kvNameParam },
new ContainerAppDaprMetadata { Name = "azureClientId", Value = principalIdParameter }
new ContainerAppDaprMetadata { Name = "azureClientId", Value = daprIdentity.PrincipalId }
];

infrastructure.Add(daprComponent);
infrastructure.Add(kvNameParam);
infrastructure.Add(principalIdParameter);

infrastructure.Add(new ProvisioningOutput(secretStoreComponentKey, typeof(string))
{
Expand Down
Loading