diff --git a/sdk/provisioning/Azure.Provisioning.CloudMachine/api/Azure.Provisioning.CloudMachine.net8.0.cs b/sdk/provisioning/Azure.Provisioning.CloudMachine/api/Azure.Provisioning.CloudMachine.net8.0.cs index 55b2964a3c0a..dedf17196169 100644 --- a/sdk/provisioning/Azure.Provisioning.CloudMachine/api/Azure.Provisioning.CloudMachine.net8.0.cs +++ b/sdk/provisioning/Azure.Provisioning.CloudMachine/api/Azure.Provisioning.CloudMachine.net8.0.cs @@ -40,11 +40,41 @@ public void AddFeature(Azure.Provisioning.CloudMachine.CloudMachineFeature featu public void AddResource(Azure.Provisioning.Primitives.NamedProvisionableConstruct resource) { } public Azure.Provisioning.ProvisioningPlan Build(Azure.Provisioning.ProvisioningBuildOptions? context = null) { throw null; } } + public partial class EventGridSystemTopicFeature : Azure.Provisioning.CloudMachine.CloudMachineFeature + { + public EventGridSystemTopicFeature(string name, Azure.Provisioning.CloudMachine.CloudMachineFeature source) { } + protected override Azure.Provisioning.Primitives.ProvisionableResource EmitCore(Azure.CloudMachine.CloudMachineInfrastructure infrastructure) { throw null; } + } public partial class FeatureCollection { public FeatureCollection() { } public System.Collections.Generic.IEnumerable FindAll() where T : Azure.Provisioning.CloudMachine.CloudMachineFeature { throw null; } } + public partial class ServiceBusNamespaceFeature : Azure.Provisioning.CloudMachine.CloudMachineFeature + { + public ServiceBusNamespaceFeature(string name, Azure.Provisioning.ServiceBus.ServiceBusSkuName sku = Azure.Provisioning.ServiceBus.ServiceBusSkuName.Standard, Azure.Provisioning.ServiceBus.ServiceBusSkuTier tier = Azure.Provisioning.ServiceBus.ServiceBusSkuTier.Standard) { } + protected override Azure.Provisioning.Primitives.ProvisionableResource EmitCore(Azure.CloudMachine.CloudMachineInfrastructure infrastructure) { throw null; } + } + public partial class ServiceBusSubscriptionFeature : Azure.Provisioning.CloudMachine.CloudMachineFeature + { + public ServiceBusSubscriptionFeature(string name, Azure.CloudMachine.ServiceBusTopicFeature parent) { } + protected override Azure.Provisioning.Primitives.ProvisionableResource EmitCore(Azure.CloudMachine.CloudMachineInfrastructure infrastructure) { throw null; } + } + public partial class ServiceBusTopicFeature : Azure.Provisioning.CloudMachine.CloudMachineFeature + { + public ServiceBusTopicFeature(string name, Azure.CloudMachine.ServiceBusNamespaceFeature parent) { } + protected override Azure.Provisioning.Primitives.ProvisionableResource EmitCore(Azure.CloudMachine.CloudMachineInfrastructure infrastructure) { throw null; } + } + public partial class StorageFeature : Azure.Provisioning.CloudMachine.CloudMachineFeature + { + public StorageFeature(string accountName, Azure.Provisioning.Storage.StorageSkuName sku = Azure.Provisioning.Storage.StorageSkuName.StandardLrs, System.Collections.Generic.IEnumerable? containerNames = null) { } + protected override Azure.Provisioning.Primitives.ProvisionableResource EmitCore(Azure.CloudMachine.CloudMachineInfrastructure infrastructure) { throw null; } + } + public partial class SystemTopicEventSubscriptionFeature : Azure.Provisioning.CloudMachine.CloudMachineFeature + { + public SystemTopicEventSubscriptionFeature(string name, Azure.CloudMachine.EventGridSystemTopicFeature parent, Azure.CloudMachine.ServiceBusTopicFeature destination, Azure.CloudMachine.ServiceBusNamespaceFeature parentNamespace) { } + protected override Azure.Provisioning.Primitives.ProvisionableResource EmitCore(Azure.CloudMachine.CloudMachineInfrastructure infrastructure) { throw null; } + } } namespace Azure.CloudMachine.AppService { @@ -93,6 +123,7 @@ public virtual void AddTo(Azure.CloudMachine.CloudMachineInfrastructure cm) { } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public void Emit(Azure.CloudMachine.CloudMachineInfrastructure cm) { } protected abstract Azure.Provisioning.Primitives.ProvisionableResource EmitCore(Azure.CloudMachine.CloudMachineInfrastructure cm); + protected static T ValidateIsOfType(Azure.Provisioning.CloudMachine.CloudMachineFeature resource) { throw null; } } } namespace System.ClientModel.TypeSpec diff --git a/sdk/provisioning/Azure.Provisioning.CloudMachine/api/Azure.Provisioning.CloudMachine.netstandard2.0.cs b/sdk/provisioning/Azure.Provisioning.CloudMachine/api/Azure.Provisioning.CloudMachine.netstandard2.0.cs index 55b2964a3c0a..dedf17196169 100644 --- a/sdk/provisioning/Azure.Provisioning.CloudMachine/api/Azure.Provisioning.CloudMachine.netstandard2.0.cs +++ b/sdk/provisioning/Azure.Provisioning.CloudMachine/api/Azure.Provisioning.CloudMachine.netstandard2.0.cs @@ -40,11 +40,41 @@ public void AddFeature(Azure.Provisioning.CloudMachine.CloudMachineFeature featu public void AddResource(Azure.Provisioning.Primitives.NamedProvisionableConstruct resource) { } public Azure.Provisioning.ProvisioningPlan Build(Azure.Provisioning.ProvisioningBuildOptions? context = null) { throw null; } } + public partial class EventGridSystemTopicFeature : Azure.Provisioning.CloudMachine.CloudMachineFeature + { + public EventGridSystemTopicFeature(string name, Azure.Provisioning.CloudMachine.CloudMachineFeature source) { } + protected override Azure.Provisioning.Primitives.ProvisionableResource EmitCore(Azure.CloudMachine.CloudMachineInfrastructure infrastructure) { throw null; } + } public partial class FeatureCollection { public FeatureCollection() { } public System.Collections.Generic.IEnumerable FindAll() where T : Azure.Provisioning.CloudMachine.CloudMachineFeature { throw null; } } + public partial class ServiceBusNamespaceFeature : Azure.Provisioning.CloudMachine.CloudMachineFeature + { + public ServiceBusNamespaceFeature(string name, Azure.Provisioning.ServiceBus.ServiceBusSkuName sku = Azure.Provisioning.ServiceBus.ServiceBusSkuName.Standard, Azure.Provisioning.ServiceBus.ServiceBusSkuTier tier = Azure.Provisioning.ServiceBus.ServiceBusSkuTier.Standard) { } + protected override Azure.Provisioning.Primitives.ProvisionableResource EmitCore(Azure.CloudMachine.CloudMachineInfrastructure infrastructure) { throw null; } + } + public partial class ServiceBusSubscriptionFeature : Azure.Provisioning.CloudMachine.CloudMachineFeature + { + public ServiceBusSubscriptionFeature(string name, Azure.CloudMachine.ServiceBusTopicFeature parent) { } + protected override Azure.Provisioning.Primitives.ProvisionableResource EmitCore(Azure.CloudMachine.CloudMachineInfrastructure infrastructure) { throw null; } + } + public partial class ServiceBusTopicFeature : Azure.Provisioning.CloudMachine.CloudMachineFeature + { + public ServiceBusTopicFeature(string name, Azure.CloudMachine.ServiceBusNamespaceFeature parent) { } + protected override Azure.Provisioning.Primitives.ProvisionableResource EmitCore(Azure.CloudMachine.CloudMachineInfrastructure infrastructure) { throw null; } + } + public partial class StorageFeature : Azure.Provisioning.CloudMachine.CloudMachineFeature + { + public StorageFeature(string accountName, Azure.Provisioning.Storage.StorageSkuName sku = Azure.Provisioning.Storage.StorageSkuName.StandardLrs, System.Collections.Generic.IEnumerable? containerNames = null) { } + protected override Azure.Provisioning.Primitives.ProvisionableResource EmitCore(Azure.CloudMachine.CloudMachineInfrastructure infrastructure) { throw null; } + } + public partial class SystemTopicEventSubscriptionFeature : Azure.Provisioning.CloudMachine.CloudMachineFeature + { + public SystemTopicEventSubscriptionFeature(string name, Azure.CloudMachine.EventGridSystemTopicFeature parent, Azure.CloudMachine.ServiceBusTopicFeature destination, Azure.CloudMachine.ServiceBusNamespaceFeature parentNamespace) { } + protected override Azure.Provisioning.Primitives.ProvisionableResource EmitCore(Azure.CloudMachine.CloudMachineInfrastructure infrastructure) { throw null; } + } } namespace Azure.CloudMachine.AppService { @@ -93,6 +123,7 @@ public virtual void AddTo(Azure.CloudMachine.CloudMachineInfrastructure cm) { } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public void Emit(Azure.CloudMachine.CloudMachineInfrastructure cm) { } protected abstract Azure.Provisioning.Primitives.ProvisionableResource EmitCore(Azure.CloudMachine.CloudMachineInfrastructure cm); + protected static T ValidateIsOfType(Azure.Provisioning.CloudMachine.CloudMachineFeature resource) { throw null; } } } namespace System.ClientModel.TypeSpec diff --git a/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/CloudMachineCoreFeature.cs b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/CloudMachineCoreFeature.cs deleted file mode 100644 index 315bf6ac1987..000000000000 --- a/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/CloudMachineCoreFeature.cs +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using Azure.Provisioning; -using Azure.Provisioning.Authorization; -using Azure.Provisioning.CloudMachine; -using Azure.Provisioning.EventGrid; -using Azure.Provisioning.Expressions; -using Azure.Provisioning.Primitives; -using Azure.Provisioning.Resources; -using Azure.Provisioning.ServiceBus; -using Azure.Provisioning.Storage; - -namespace Azure.CloudMachine; - -internal class CloudMachineCoreFeature : CloudMachineFeature -{ - public CloudMachineCoreFeature() - { } - protected override ProvisionableResource EmitCore(CloudMachineInfrastructure infrastructure) - { - ManagedServiceIdentity managedServiceIdentity = new() - { - ManagedServiceIdentityType = ManagedServiceIdentityType.UserAssigned, - UserAssignedIdentities = { { BicepFunction.Interpolate($"{infrastructure.Identity.Id}").Compile().ToString(), new UserAssignedIdentityDetails() } } - }; - - var _storage = - new StorageAccount("cm_storage", StorageAccount.ResourceVersions.V2023_01_01) - { - Kind = StorageKind.StorageV2, - Sku = new StorageSku { Name = StorageSkuName.StandardLrs }, - IsHnsEnabled = true, - AllowBlobPublicAccess = false - }; - _storage.Identity = managedServiceIdentity; - _storage.Name = infrastructure.Id; - - var _blobs = new BlobService("cm_storage_blobs") - { - Parent = _storage, - }; - var _container = new BlobContainer("cm_storage_blobs_container", "2023-01-01") - { - Parent = _blobs, - Name = "default" - }; - - var _serviceBusNamespace = new ServiceBusNamespace("cm_servicebus") - { - Sku = new ServiceBusSku - { - Name = ServiceBusSkuName.Standard, - Tier = ServiceBusSkuTier.Standard - }, - Name = infrastructure.Id, - }; - var _serviceBusNamespaceAuthorizationRule = new ServiceBusNamespaceAuthorizationRule("cm_servicebus_auth_rule", "2021-11-01") - { - Parent = _serviceBusNamespace, - Rights = [ServiceBusAccessRight.Listen, ServiceBusAccessRight.Send, ServiceBusAccessRight.Manage] - }; - var _serviceBusTopic_private = new ServiceBusTopic("cm_servicebus_topic_private", "2021-11-01") - { - Name = "cm_servicebus_topic_private", - Parent = _serviceBusNamespace, - MaxMessageSizeInKilobytes = 256, - DefaultMessageTimeToLive = TimeSpan.FromDays(14), - RequiresDuplicateDetection = false, - EnableBatchedOperations = true, - SupportOrdering = true, - Status = ServiceBusMessagingEntityStatus.Active - }; - var _serviceBusSubscription_private = new ServiceBusSubscription(CloudMachineInfrastructure.SB_PRIVATE_SUB, "2021-11-01") - { - Name = CloudMachineInfrastructure.SB_PRIVATE_SUB, - Parent = _serviceBusTopic_private, - IsClientAffine = false, - LockDuration = TimeSpan.FromSeconds(30), - RequiresSession = false, - DefaultMessageTimeToLive = TimeSpan.FromDays(14), - DeadLetteringOnFilterEvaluationExceptions = true, - DeadLetteringOnMessageExpiration = true, - MaxDeliveryCount = 10, - EnableBatchedOperations = true, - Status = ServiceBusMessagingEntityStatus.Active - }; - var _serviceBusTopic_default = new ServiceBusTopic("cm_servicebus_topic_default", "2021-11-01") - { - Name = "cm_servicebus_default_topic", - Parent = _serviceBusNamespace, - MaxMessageSizeInKilobytes = 256, - DefaultMessageTimeToLive = TimeSpan.FromDays(14), - RequiresDuplicateDetection = false, - EnableBatchedOperations = true, - SupportOrdering = true, - Status = ServiceBusMessagingEntityStatus.Active - }; - var _serviceBusSubscription_default = new ServiceBusSubscription("cm_servicebus_subscription_default", "2021-11-01") - { - Name = "cm_servicebus_subscription_default", - Parent = _serviceBusTopic_default, - IsClientAffine = false, - LockDuration = TimeSpan.FromSeconds(30), - RequiresSession = false, - DefaultMessageTimeToLive = TimeSpan.FromDays(14), - DeadLetteringOnFilterEvaluationExceptions = true, - DeadLetteringOnMessageExpiration = true, - MaxDeliveryCount = 10, - EnableBatchedOperations = true, - Status = ServiceBusMessagingEntityStatus.Active - }; - var _eventGridTopic_blobs = new SystemTopic("cm_eventgrid_topic_blob", "2022-06-15") - { - TopicType = "Microsoft.Storage.StorageAccounts", - Source = _storage.Id, - Identity = new() - { - ManagedServiceIdentityType = ManagedServiceIdentityType.UserAssigned, - UserAssignedIdentities = { { BicepFunction.Interpolate($"{infrastructure.Identity.Id}").Compile().ToString(), new UserAssignedIdentityDetails() } } - }, - Name = infrastructure.Id - }; - var _eventGridSubscription_blobs = new SystemTopicEventSubscription("cm_eventgrid_subscription_blob", "2022-06-15") - { - Name = "cm-eventgrid-subscription-blob", - Parent = _eventGridTopic_blobs, - DeliveryWithResourceIdentity = new DeliveryWithResourceIdentity - { - Identity = new EventSubscriptionIdentity - { - IdentityType = EventSubscriptionIdentityType.UserAssigned, - UserAssignedIdentity = infrastructure.Identity.Id - }, - Destination = new ServiceBusTopicEventSubscriptionDestination - { - ResourceId = _serviceBusTopic_private.Id - } - }, - Filter = new EventSubscriptionFilter - { - IncludedEventTypes = - [ - "Microsoft.Storage.BlobCreated", - "Microsoft.Storage.BlobDeleted", - "Microsoft.Storage.BlobRenamed" - ], - IsAdvancedFilteringOnArraysEnabled = true - }, - EventDeliverySchema = EventDeliverySchema.EventGridSchema, - RetryPolicy = new EventSubscriptionRetryPolicy - { - MaxDeliveryAttempts = 30, - EventTimeToLiveInMinutes = 1440 - } - }; - - infrastructure.AddResource(infrastructure.PrincipalIdParameter); - infrastructure.AddResource(infrastructure.Identity); - infrastructure.AddResource(_storage); - RequiredSystemRoles.Add( - _storage, - [ - (StorageBuiltInRole.GetBuiltInRoleName(StorageBuiltInRole.StorageBlobDataContributor),StorageBuiltInRole.StorageBlobDataContributor.ToString()), - (StorageBuiltInRole.GetBuiltInRoleName(StorageBuiltInRole.StorageTableDataContributor), StorageBuiltInRole.StorageTableDataContributor.ToString()) - ]); - - infrastructure.AddResource(_container); - infrastructure.AddResource(_blobs); - infrastructure.AddResource(_serviceBusNamespace); - - RequiredSystemRoles.Add( - _serviceBusNamespace, - [ - (ServiceBusBuiltInRole.GetBuiltInRoleName(ServiceBusBuiltInRole.AzureServiceBusDataOwner), ServiceBusBuiltInRole.AzureServiceBusDataOwner.ToString()), - ]); - - var role = ServiceBusBuiltInRole.AzureServiceBusDataSender; - RoleAssignment roleAssignment = new RoleAssignment("cm_servicebus_role"); - roleAssignment.Name = BicepFunction.CreateGuid(_serviceBusNamespace.Id, infrastructure.Identity.Id, BicepFunction.GetSubscriptionResourceId("Microsoft.Authorization/roleDefinitions", role.ToString())); - roleAssignment.Scope = new IdentifierExpression(_serviceBusNamespace.BicepIdentifier); - roleAssignment.PrincipalType = RoleManagementPrincipalType.ServicePrincipal; - roleAssignment.RoleDefinitionId = BicepFunction.GetSubscriptionResourceId("Microsoft.Authorization/roleDefinitions", role.ToString()); - roleAssignment.PrincipalId = infrastructure.Identity.PrincipalId; - infrastructure.AddResource(roleAssignment); - - // the role assignment must exist before the system topic event subscription is created. - _eventGridSubscription_blobs.DependsOn.Add(roleAssignment); - - infrastructure.AddResource(_serviceBusNamespaceAuthorizationRule); - infrastructure.AddResource(_serviceBusTopic_private); - infrastructure.AddResource(_serviceBusTopic_default); - infrastructure.AddResource(_serviceBusSubscription_private); - infrastructure.AddResource(_serviceBusSubscription_default); - infrastructure.AddResource(_eventGridSubscription_blobs); - infrastructure.AddResource(_eventGridTopic_blobs); - - // Placeholders for now. - infrastructure.AddResource(new ProvisioningOutput($"storage_name", typeof(string)) { Value = _storage.Name }); - infrastructure.AddResource(new ProvisioningOutput($"servicebus_name", typeof(string)) { Value = _serviceBusNamespace.Name }); - - return _storage; - } -} diff --git a/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/CloudMachineFeature.cs b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/CloudMachineFeature.cs index da68e676e6c7..ac23c3c3d519 100644 --- a/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/CloudMachineFeature.cs +++ b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/CloudMachineFeature.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; using System.Collections.Generic; using System.ComponentModel; using Azure.CloudMachine; @@ -28,4 +29,11 @@ public void Emit(CloudMachineInfrastructure cm) public ProvisionableResource Emitted { get; protected set; } = default!; protected internal Dictionary RequiredSystemRoles { get; } = []; + + protected static T ValidateIsOfType(CloudMachineFeature resource) + { + if (resource.Emitted is T typed) + return typed; + throw new ArgumentException($"Expected resource of type {typeof(T).Name}, but got {resource.GetType().Name}"); + } } diff --git a/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/CloudMachineInfrastructure.cs b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/CloudMachineInfrastructure.cs index 9a2847f25469..0973d0106f44 100644 --- a/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/CloudMachineInfrastructure.cs +++ b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/CloudMachineInfrastructure.cs @@ -9,8 +9,6 @@ using System.Collections.Generic; using Azure.Provisioning; using Azure.Provisioning.CloudMachine; -using Azure.Core; -using System.Runtime.CompilerServices; namespace Azure.CloudMachine; @@ -18,7 +16,7 @@ public class CloudMachineInfrastructure { internal const string SB_PRIVATE_TOPIC = "cm_servicebus_topic_private"; internal const string SB_PRIVATE_SUB = "cm_servicebus_subscription_private"; - private readonly string _cmid; + private readonly string _cmId; private Infrastructure _infrastructure = new Infrastructure("cm"); private List _resources = new(); @@ -26,7 +24,7 @@ public class CloudMachineInfrastructure internal List Endpoints { get; } = new(); public UserAssignedIdentity Identity { get; private set; } - public string Id => _cmid; + public string Id => _cmId; /// /// The common principalId parameter. @@ -45,13 +43,27 @@ public class CloudMachineInfrastructure public CloudMachineInfrastructure(string cmId) { - _cmid = cmId; + _cmId = cmId; // setup CM identity Identity = new UserAssignedIdentity("cm_identity"); - Identity.Name = _cmid; + Identity.Name = _cmId; _infrastructure.Add(new ProvisioningOutput($"cm_managed_identity_id", typeof(string)) { Value = Identity.Id }); - Features.Add(new CloudMachineCoreFeature()); + + // Add core features + var storage = new StorageFeature(_cmId); + Features.Add(storage); + var sbNamespace = new ServiceBusNamespaceFeature(_cmId); + Features.Add(sbNamespace); + var sbTopic_private = new ServiceBusTopicFeature("cm_servicebus_topic_private", sbNamespace); + Features.Add(sbTopic_private); + var sbTopic_default = new ServiceBusTopicFeature("cm_servicebus_default_topic", sbNamespace); + Features.Add(sbTopic_default); + Features.Add(new ServiceBusSubscriptionFeature("cm_servicebus_subscription_private", sbTopic_private)); + Features.Add(new ServiceBusSubscriptionFeature("cm_servicebus_subscription_default", sbTopic_default)); + var systemTopic = new EventGridSystemTopicFeature(_cmId, storage); + Features.Add(systemTopic); + Features.Add(new SystemTopicEventSubscriptionFeature("cm_eventgrid_subscription_blob", systemTopic, sbTopic_private, sbNamespace)); } public void AddResource(NamedProvisionableConstruct resource) @@ -90,6 +102,13 @@ public ProvisioningPlan Build(ProvisioningBuildOptions? context = null) Value = BicepFunction.GetResourceGroup().Location }); + _infrastructure.Add(new ProvisioningParameter("principalId", typeof(string)) + { + Description = "The objectId of the current user principal.", + }); + + _infrastructure.Add(Identity); + // Add any add-on resources to the infrastructure. foreach (Provisionable resource in _resources) { diff --git a/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/EventGridSystemTopicFeature.cs b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/EventGridSystemTopicFeature.cs new file mode 100644 index 000000000000..d2f21333eee4 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/EventGridSystemTopicFeature.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Provisioning.CloudMachine; +using Azure.Provisioning.EventGrid; +using Azure.Provisioning.Expressions; +using Azure.Provisioning.Primitives; +using Azure.Provisioning.Resources; +using Azure.Provisioning.Storage; + +namespace Azure.CloudMachine; + +public class EventGridSystemTopicFeature(string name, CloudMachineFeature source) : CloudMachineFeature +{ + protected override ProvisionableResource EmitCore(CloudMachineInfrastructure infrastructure) + { + var topic = new SystemTopic("cm_eventgrid_topic", "2022-06-15") + { + TopicType = "Microsoft.Storage.StorageAccounts", + Source = ValidateIsOfType(source).Id, + Identity = new() + { + ManagedServiceIdentityType = ManagedServiceIdentityType.UserAssigned, + UserAssignedIdentities = { { BicepFunction.Interpolate($"{infrastructure.Identity.Id}").Compile().ToString(), new UserAssignedIdentityDetails() } } + }, + Name = name + }; + + infrastructure.AddResource(topic); + + Emitted = topic; + return topic; + } +} diff --git a/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/ServiceBusNamespaceFeature.cs b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/ServiceBusNamespaceFeature.cs new file mode 100644 index 000000000000..441fd1be6902 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/ServiceBusNamespaceFeature.cs @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Provisioning.Authorization; +using Azure.Provisioning.CloudMachine; +using Azure.Provisioning.Expressions; +using Azure.Provisioning.Primitives; +using Azure.Provisioning.ServiceBus; + +namespace Azure.CloudMachine; + +public class ServiceBusNamespaceFeature(string name, ServiceBusSkuName sku = ServiceBusSkuName.Standard, ServiceBusSkuTier tier = ServiceBusSkuTier.Standard) : CloudMachineFeature +{ + protected override ProvisionableResource EmitCore(CloudMachineInfrastructure infrastructure) + { + var _serviceBusNamespace = new ServiceBusNamespace("cm_servicebus") + { + Sku = new ServiceBusSku + { + Name = sku, + Tier = tier + }, + Name = name, + }; + infrastructure.AddResource(_serviceBusNamespace); + infrastructure.AddResource( + new ServiceBusNamespaceAuthorizationRule("cm_servicebus_auth_rule", "2021-11-01") + { + Parent = _serviceBusNamespace, + Rights = [ServiceBusAccessRight.Listen, ServiceBusAccessRight.Send, ServiceBusAccessRight.Manage] + } + ); + + RequiredSystemRoles.Add( + _serviceBusNamespace, + [ + (ServiceBusBuiltInRole.GetBuiltInRoleName(ServiceBusBuiltInRole.AzureServiceBusDataOwner), ServiceBusBuiltInRole.AzureServiceBusDataOwner.ToString()), + ]); + + Emitted = _serviceBusNamespace; + return _serviceBusNamespace; + } +} diff --git a/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/ServiceBusSubscriptionFeature.cs b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/ServiceBusSubscriptionFeature.cs new file mode 100644 index 000000000000..b60042fe6324 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/ServiceBusSubscriptionFeature.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Azure.Provisioning.CloudMachine; +using Azure.Provisioning.Primitives; +using Azure.Provisioning.ServiceBus; + +namespace Azure.CloudMachine; + +public class ServiceBusSubscriptionFeature(string name, ServiceBusTopicFeature parent) : CloudMachineFeature +{ + protected override ProvisionableResource EmitCore(CloudMachineInfrastructure infrastructure) + { + var subscription = new ServiceBusSubscription(name, "2021-11-01") + { + Name = name, + Parent = ValidateIsOfType(parent), + IsClientAffine = false, + LockDuration = TimeSpan.FromSeconds(30), + RequiresSession = false, + DefaultMessageTimeToLive = TimeSpan.FromDays(14), + DeadLetteringOnFilterEvaluationExceptions = true, + DeadLetteringOnMessageExpiration = true, + MaxDeliveryCount = 10, + EnableBatchedOperations = true, + Status = ServiceBusMessagingEntityStatus.Active + }; + + infrastructure.AddResource(subscription); + Emitted = subscription; + return subscription; + } +} diff --git a/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/ServiceBusTopicFeature.cs b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/ServiceBusTopicFeature.cs new file mode 100644 index 000000000000..707b316d9389 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/ServiceBusTopicFeature.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Azure.Provisioning.CloudMachine; +using Azure.Provisioning.Primitives; +using Azure.Provisioning.ServiceBus; + +namespace Azure.CloudMachine; + +public class ServiceBusTopicFeature(string name, ServiceBusNamespaceFeature parent) : CloudMachineFeature +{ + protected override ProvisionableResource EmitCore(CloudMachineInfrastructure infrastructure) + { + var topic = new ServiceBusTopic(name, "2021-11-01") + { + Name = name, + Parent = ValidateIsOfType(parent), + MaxMessageSizeInKilobytes = 256, + DefaultMessageTimeToLive = TimeSpan.FromDays(14), + RequiresDuplicateDetection = false, + EnableBatchedOperations = true, + SupportOrdering = true, + Status = ServiceBusMessagingEntityStatus.Active + }; + + infrastructure.AddResource(topic); + Emitted = topic; + return topic; + } +} diff --git a/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/StorageFeature.cs b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/StorageFeature.cs new file mode 100644 index 000000000000..b7f67141bc1f --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/StorageFeature.cs @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using System.Linq; +using Azure.Provisioning; +using Azure.Provisioning.CloudMachine; +using Azure.Provisioning.Expressions; +using Azure.Provisioning.Primitives; +using Azure.Provisioning.Resources; +using Azure.Provisioning.Storage; + +namespace Azure.CloudMachine; + +public class StorageFeature : CloudMachineFeature +{ + private List _containerNames; + private StorageSkuName _skuName; + private string _name; + + public StorageFeature(string accountName, StorageSkuName sku = StorageSkuName.StandardLrs, IEnumerable? containerNames = null) + { + _skuName = sku; + _name = accountName; + if (containerNames != null) + _containerNames = containerNames.ToList(); + else + _containerNames = ["default"]; + } + + protected override ProvisionableResource EmitCore(CloudMachineInfrastructure infrastructure) + { + var _storage = + new StorageAccount("cm_storage", StorageAccount.ResourceVersions.V2023_01_01) + { + Name = _name, + Kind = StorageKind.StorageV2, + Sku = new StorageSku { Name = _skuName }, + IsHnsEnabled = true, + AllowBlobPublicAccess = false, + Identity = new() + { + ManagedServiceIdentityType = ManagedServiceIdentityType.UserAssigned, + UserAssignedIdentities = { { BicepFunction.Interpolate($"{infrastructure.Identity.Id}").Compile().ToString(), new UserAssignedIdentityDetails() } } + } + }; + infrastructure.AddResource(_storage); + + var _blobs = new BlobService("cm_storage_blobs") + { + Parent = _storage, + }; + infrastructure.AddResource(_blobs); + + foreach (var containerName in _containerNames) + { + infrastructure.AddResource( + new BlobContainer("cm_storage_blobs_container_" + containerName, "2023-01-01") + { + Parent = _blobs, + Name = containerName + } + ); + } + + RequiredSystemRoles.Add( + _storage, + [ + (StorageBuiltInRole.GetBuiltInRoleName(StorageBuiltInRole.StorageBlobDataContributor),StorageBuiltInRole.StorageBlobDataContributor.ToString()), + (StorageBuiltInRole.GetBuiltInRoleName(StorageBuiltInRole.StorageTableDataContributor), StorageBuiltInRole.StorageTableDataContributor.ToString()) + ]); + + // Placeholders for now. + infrastructure.AddResource(new ProvisioningOutput($"storage_name", typeof(string)) { Value = _storage.Name }); + + Emitted = _storage; + return _storage; + } +} diff --git a/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/SystemTopicEventSubscriptionFeature.cs b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/SystemTopicEventSubscriptionFeature.cs new file mode 100644 index 000000000000..85faafb2435d --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/SystemTopicEventSubscriptionFeature.cs @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Provisioning.Authorization; +using Azure.Provisioning.CloudMachine; +using Azure.Provisioning.EventGrid; +using Azure.Provisioning.Expressions; +using Azure.Provisioning.Primitives; +using Azure.Provisioning.ServiceBus; + +namespace Azure.CloudMachine; + +public class SystemTopicEventSubscriptionFeature(string name, EventGridSystemTopicFeature parent, ServiceBusTopicFeature destination, ServiceBusNamespaceFeature parentNamespace) : CloudMachineFeature +{ + protected override ProvisionableResource EmitCore(CloudMachineInfrastructure infrastructure) + { + var serviceBusNamespace = ValidateIsOfType(parentNamespace); + + var role = ServiceBusBuiltInRole.AzureServiceBusDataSender; + var roleAssignment = new RoleAssignment($"cm_servicebus_{ValidateIsOfType(parent).Name.Value}_role") + { + Name = BicepFunction.CreateGuid(serviceBusNamespace.Id, infrastructure.Identity.Id, BicepFunction.GetSubscriptionResourceId("Microsoft.Authorization/roleDefinitions", role.ToString())), + Scope = new IdentifierExpression(serviceBusNamespace.BicepIdentifier), + PrincipalType = RoleManagementPrincipalType.ServicePrincipal, + RoleDefinitionId = BicepFunction.GetSubscriptionResourceId("Microsoft.Authorization/roleDefinitions", role.ToString()), + PrincipalId = infrastructure.Identity.PrincipalId, + }; + + var systemTopic = ValidateIsOfType(parent); + var subscription = new SystemTopicEventSubscription("cm_eventgrid_subscription_blob", "2022-06-15") + { + Name = name, + Parent = systemTopic, + DeliveryWithResourceIdentity = new DeliveryWithResourceIdentity + { + Identity = new EventSubscriptionIdentity + { + IdentityType = EventSubscriptionIdentityType.UserAssigned, + UserAssignedIdentity = infrastructure.Identity.Id + }, + Destination = new ServiceBusTopicEventSubscriptionDestination + { + ResourceId = ValidateIsOfType(destination).Id + } + }, + Filter = new EventSubscriptionFilter + { + IncludedEventTypes = + [ + "Microsoft.Storage.BlobCreated", + "Microsoft.Storage.BlobDeleted", + "Microsoft.Storage.BlobRenamed" + ], + IsAdvancedFilteringOnArraysEnabled = true + }, + EventDeliverySchema = EventDeliverySchema.EventGridSchema, + RetryPolicy = new EventSubscriptionRetryPolicy + { + MaxDeliveryAttempts = 30, + EventTimeToLiveInMinutes = 1440 + } + }; + subscription.DependsOn.Add(roleAssignment); + + infrastructure.AddResource(subscription); + infrastructure.AddResource(roleAssignment); + + Emitted = subscription; + return subscription; + } +} diff --git a/sdk/provisioning/Azure.Provisioning.CloudMachine/tests/CloudMachineTests.cs b/sdk/provisioning/Azure.Provisioning.CloudMachine/tests/CloudMachineTests.cs index 7c6a99f3254f..be895b522e5c 100644 --- a/sdk/provisioning/Azure.Provisioning.CloudMachine/tests/CloudMachineTests.cs +++ b/sdk/provisioning/Azure.Provisioning.CloudMachine/tests/CloudMachineTests.cs @@ -18,11 +18,19 @@ public class CloudMachineTests [Test] public void GenerateBicep() { + CloudMachineCommands.Execute(["-bicep"], (CloudMachineInfrastructure infrastructure) => + { + infrastructure.AddFeature(new KeyVaultFeature()); + infrastructure.AddFeature(new OpenAIModel("gpt-35-turbo", "0125")); + infrastructure.AddFeature(new OpenAIModel("text-embedding-ada-002", "2", AIModelKind.Embedding)); + infrastructure.AddFeature(new AppServiceFeature()); + }, exitProcessIfHandled: false); + CloudMachineInfrastructure infra = new("cm0c420d2f21084cd"); infra.AddFeature(new KeyVaultFeature()); - infra.AddFeature(new OpenAIModel("gpt-35-turbo", "0125")); - infra.AddFeature(new OpenAIModel("text-embedding-ada-002", "2", AIModelKind.Embedding)); - infra.AddFeature(new AppServiceFeature()); + infra.AddFeature(new OpenAIModel("gpt-35-turbo", "0125")); + infra.AddFeature(new OpenAIModel("text-embedding-ada-002", "2", AIModelKind.Embedding)); + infra.AddFeature(new AppServiceFeature()); string actualBicep = infra!.Build().Compile().FirstOrDefault().Value; string expectedBicep = File.ReadAllText(Path.Combine(TestContext.CurrentContext.TestDirectory, "Data", "GenerateBicep.bicep")).Replace("\r\n", Environment.NewLine); diff --git a/sdk/provisioning/Azure.Provisioning.CloudMachine/tests/Data/GenerateBicep.bicep b/sdk/provisioning/Azure.Provisioning.CloudMachine/tests/Data/GenerateBicep.bicep index 9cbe83a6469c..1bbb649a44b4 100644 --- a/sdk/provisioning/Azure.Provisioning.CloudMachine/tests/Data/GenerateBicep.bicep +++ b/sdk/provisioning/Azure.Provisioning.CloudMachine/tests/Data/GenerateBicep.bicep @@ -1,6 +1,7 @@ @description('The location for the resource(s) to be deployed.') param location string = resourceGroup().location +@description('The objectId of the current user principal.') param principalId string resource cm_identity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { @@ -67,14 +68,14 @@ resource cm_storage_cm_identity_StorageTableDataContributor 'Microsoft.Authoriza scope: cm_storage } -resource cm_storage_blobs_container 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = { +resource cm_storage_blobs 'Microsoft.Storage/storageAccounts/blobServices@2024-01-01' = { name: 'default' - parent: cm_storage_blobs + parent: cm_storage } -resource cm_storage_blobs 'Microsoft.Storage/storageAccounts/blobServices@2024-01-01' = { +resource cm_storage_blobs_container_default 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = { name: 'default' - parent: cm_storage + parent: cm_storage_blobs } resource cm_servicebus 'Microsoft.ServiceBus/namespaces@2024-01-01' = { @@ -106,16 +107,6 @@ resource cm_servicebus_cm_identity_AzureServiceBusDataOwner 'Microsoft.Authoriza scope: cm_servicebus } -resource cm_servicebus_role 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(cm_servicebus.id, cm_identity.id, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '69a216fc-b8fb-44d8-bc22-1f3c2cd27a39')) - properties: { - principalId: cm_identity.properties.principalId - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '69a216fc-b8fb-44d8-bc22-1f3c2cd27a39') - principalType: 'ServicePrincipal' - } - scope: cm_servicebus -} - resource cm_servicebus_auth_rule 'Microsoft.ServiceBus/namespaces/AuthorizationRules@2021-11-01' = { name: take('cm_servicebus_auth_rule-${uniqueString(resourceGroup().id)}', 50) properties: { @@ -141,7 +132,7 @@ resource cm_servicebus_topic_private 'Microsoft.ServiceBus/namespaces/topics@202 parent: cm_servicebus } -resource cm_servicebus_topic_default 'Microsoft.ServiceBus/namespaces/topics@2021-11-01' = { +resource cm_servicebus_default_topic 'Microsoft.ServiceBus/namespaces/topics@2021-11-01' = { name: 'cm_servicebus_default_topic' properties: { defaultMessageTimeToLive: 'P14D' @@ -183,11 +174,26 @@ resource cm_servicebus_subscription_default 'Microsoft.ServiceBus/namespaces/top requiresSession: false status: 'Active' } - parent: cm_servicebus_topic_default + parent: cm_servicebus_default_topic +} + +resource cm_eventgrid_topic 'Microsoft.EventGrid/systemTopics@2022-06-15' = { + name: 'cm0c420d2f21084cd' + location: location + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${cm_identity.id}': { } + } + } + properties: { + source: cm_storage.id + topicType: 'Microsoft.Storage.StorageAccounts' + } } resource cm_eventgrid_subscription_blob 'Microsoft.EventGrid/systemTopics/eventSubscriptions@2022-06-15' = { - name: 'cm-eventgrid-subscription-blob' + name: 'cm_eventgrid_subscription_blob' properties: { deliveryWithResourceIdentity: { identity: { @@ -215,25 +221,20 @@ resource cm_eventgrid_subscription_blob 'Microsoft.EventGrid/systemTopics/eventS eventTimeToLiveInMinutes: 1440 } } - parent: cm_eventgrid_topic_blob + parent: cm_eventgrid_topic dependsOn: [ - cm_servicebus_role + cm_servicebus_cm0c420d2f21084cd_role ] } -resource cm_eventgrid_topic_blob 'Microsoft.EventGrid/systemTopics@2022-06-15' = { - name: 'cm0c420d2f21084cd' - location: location - identity: { - type: 'UserAssigned' - userAssignedIdentities: { - '${cm_identity.id}': { } - } - } +resource cm_servicebus_cm0c420d2f21084cd_role 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(cm_servicebus.id, cm_identity.id, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '69a216fc-b8fb-44d8-bc22-1f3c2cd27a39')) properties: { - source: cm_storage.id - topicType: 'Microsoft.Storage.StorageAccounts' + principalId: cm_identity.properties.principalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '69a216fc-b8fb-44d8-bc22-1f3c2cd27a39') + principalType: 'ServicePrincipal' } + scope: cm_servicebus } resource cm_kv 'Microsoft.KeyVault/vaults@2023-07-01' = { @@ -396,6 +397,4 @@ resource cm_website 'Microsoft.Web/sites@2024-04-01' = { output cm_managed_identity_id string = cm_identity.id -output storage_name string = cm_storage.name - -output servicebus_name string = cm_servicebus.name \ No newline at end of file +output storage_name string = cm_storage.name \ No newline at end of file