diff --git a/sdk/provisioning/Azure.Provisioning.CloudMachine/CHANGELOG.md b/sdk/provisioning/Azure.Provisioning.CloudMachine/CHANGELOG.md new file mode 100644 index 0000000000000..13dd08af78abe --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.CloudMachine/CHANGELOG.md @@ -0,0 +1,11 @@ +# Release History + +## 1.0.0-beta.1 (Unreleased) + +### Features Added + +### Breaking Changes + +### Bugs Fixed + +### Other Changes diff --git a/sdk/provisioning/Azure.Provisioning.CloudMachine/README.md b/sdk/provisioning/Azure.Provisioning.CloudMachine/README.md new file mode 100644 index 0000000000000..f39ffc5c26e7c --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.CloudMachine/README.md @@ -0,0 +1,57 @@ +# Azure Provisioning client library for .NET + +Azure.Provisioning.CloudMachine simplifies declarative resource provisioning in .NET for CloudMachine resources. + +## Getting started + +### Install the package + +Install the client library for .NET with [NuGet](https://www.nuget.org/ ): + +```dotnetcli +dotnet add package Azure.Provisioning.CloudMachine +``` + +### Prerequisites + +> You must have an [Azure subscription](https://azure.microsoft.com/free/dotnet/). + +### Authenticate the Client + +## Key concepts + +This library allows you to specify your infrastructure in a declarative style using dotnet. You can then use azd to deploy your infrastructure to Azure directly without needing to write or maintain bicep or arm templates. + +## Examples + +## Troubleshooting + +- File an issue via [GitHub Issues](https://github.com/Azure/azure-sdk-for-net/issues). +- Check [previous questions](https://stackoverflow.com/questions/tagged/azure+.net) or ask new ones on Stack Overflow using Azure and .NET tags. + +## Next steps + +## Contributing + +For details on contributing to this repository, see the [contributing +guide][cg]. + +This project welcomes contributions and suggestions. Most contributions +require you to agree to a Contributor License Agreement (CLA) declaring +that you have the right to, and actually do, grant us the rights to use +your contribution. For details, visit . + +When you submit a pull request, a CLA-bot will automatically determine +whether you need to provide a CLA and decorate the PR appropriately +(for example, label, comment). Follow the instructions provided by the +bot. You'll only need to do this action once across all repositories +using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct][coc]. For +more information, see the [Code of Conduct FAQ][coc_faq] or contact + with any other questions or comments. + + +[cg]: https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/resourcemanager/Azure.ResourceManager/docs/CONTRIBUTING.md +[coc]: https://opensource.microsoft.com/codeofconduct/ +[coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/ 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 new file mode 100644 index 0000000000000..6663393809637 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.CloudMachine/api/Azure.Provisioning.CloudMachine.netstandard2.0.cs @@ -0,0 +1,11 @@ +namespace Azure.Provisioning.CloudMachine +{ + public partial class CloudMachineInfrastructure : Azure.Provisioning.Infrastructure + { + public CloudMachineInfrastructure(string? name = "cm") : base (default(string)) { } + public Azure.Provisioning.BicepParameter PrincipalIdParameter { get { throw null; } } + public Azure.Provisioning.BicepParameter PrincipalNameParameter { get { throw null; } } + public Azure.Provisioning.BicepParameter PrincipalTypeParameter { get { throw null; } } + public override Azure.Provisioning.ProvisioningPlan Build(Azure.Provisioning.ProvisioningContext? context = null) { throw null; } + } +} diff --git a/sdk/provisioning/Azure.Provisioning.CloudMachine/src/Azure.Provisioning.CloudMachine.csproj b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/Azure.Provisioning.CloudMachine.csproj new file mode 100644 index 0000000000000..56ff43800adc3 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/Azure.Provisioning.CloudMachine.csproj @@ -0,0 +1,19 @@ + + + + Azure.Provisioning.CloudMachine simplifies declarative resource provisioning in .NET. + 1.0.0-beta.1 + $(RequiredTargetFrameworks) + 12 + + + CS1591 + + + + + + + + + diff --git a/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CloudMachineInfrastructure.cs b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CloudMachineInfrastructure.cs new file mode 100644 index 0000000000000..4f586d931fce5 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/CloudMachineInfrastructure.cs @@ -0,0 +1,215 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Provisioning.Authorization; +using Azure.Provisioning.EventGrid; +using Azure.Provisioning.Expressions; +using Azure.Provisioning.Resources; +using Azure.Provisioning.Roles; +using Azure.Provisioning.ServiceBus; +using Azure.Provisioning.Storage; + +namespace Azure.Provisioning.CloudMachine; + +public class CloudMachineInfrastructure : Infrastructure +{ + private readonly string _name; + private UserAssignedIdentity _identity; + private StorageAccount _storage; + private BlobService _blobs; + private BlobContainer _container; + private ServiceBusNamespace _serviceBusNamespace; + private ServiceBusNamespaceAuthorizationRule _serviceBusNamespaceAuthorizationRule; + private ServiceBusTopic _serviceBusTopic_main; + private ServiceBusTopic _serviceBusTopic_app; + private ServiceBusSubscription _serviceBusSubscription_main; + private ServiceBusSubscription _serviceBusSubscription_app; + private SystemTopic _eventGridTopic_Blobs; + private SystemTopicEventSubscription _systemTopicEventSubscription; + + /// + /// The common principalId parameter. + /// + public BicepParameter PrincipalIdParameter => new BicepParameter("principalId", typeof(string)); + + /// + /// The common principalType parameter. + /// + public BicepParameter PrincipalTypeParameter => new BicepParameter("principalType", typeof(string)); + + /// + /// The common principalName parameter. + /// + public BicepParameter PrincipalNameParameter => new BicepParameter("principalName", typeof(string)); + + public CloudMachineInfrastructure(string name = "cm") : base(name!) + { + _name = name ?? "cm"; + _identity = new($"{_name}_identity"); + ManagedServiceIdentity managedServiceIdentity = new() + { + ManagedServiceIdentityType = ManagedServiceIdentityType.UserAssigned, + UserAssignedIdentities = { { BicepFunction.Interpolate($"{_identity.Id}").Compile().ToString(), new UserAssignedIdentityDetails() } } + }; + + _storage = StorageResources.CreateAccount($"{_name}_sa"); + _storage.Identity = managedServiceIdentity; + + _blobs = new($"{_name}_blobs") + { + Parent = _storage, + }; + _container = new BlobContainer($"{_name}_container", "2023-01-01") + { + Parent = _blobs, + Name = "default" + }; + + _serviceBusNamespace = new($"{_name}_sb") + { + Sku = new ServiceBusSku + { + Name = ServiceBusSkuName.Standard, + Tier = ServiceBusSkuTier.Standard + }, + }; + _serviceBusNamespaceAuthorizationRule = new($"{_name}_sb_auth_rule", "2021-11-01") + { + Parent = _serviceBusNamespace, + Rights = [ServiceBusAccessRight.Listen, ServiceBusAccessRight.Send, ServiceBusAccessRight.Manage] + }; + _serviceBusTopic_main = new($"{_name}_sb_topic_main", "2021-11-01") + { + Parent = _serviceBusNamespace, + MaxMessageSizeInKilobytes = 256, + DefaultMessageTimeToLive = new StringLiteral("P14D"), + RequiresDuplicateDetection = false, + EnableBatchedOperations = true, + SupportOrdering = true, + Status = ServiceBusMessagingEntityStatus.Active + }; + _serviceBusSubscription_main = new($"{_name}_sb_sub_main", "2021-11-01") + { + Parent = _serviceBusTopic_main, + IsClientAffine = false, + LockDuration = new StringLiteral("PT30S"), + RequiresSession = false, + DefaultMessageTimeToLive = new StringLiteral("P14D"), + DeadLetteringOnFilterEvaluationExceptions = true, + DeadLetteringOnMessageExpiration = true, + MaxDeliveryCount = 10, + EnableBatchedOperations = true, + Status = ServiceBusMessagingEntityStatus.Active + }; + _serviceBusTopic_app = new($"{_name}_sb_topic_app", "2021-11-01") + { + Parent = _serviceBusNamespace, + // Name = "default", + MaxMessageSizeInKilobytes = 256, + DefaultMessageTimeToLive = new StringLiteral("P14D"), + RequiresDuplicateDetection = false, + EnableBatchedOperations = true, + SupportOrdering = true, + Status = ServiceBusMessagingEntityStatus.Active + }; + _serviceBusSubscription_app = new($"{_name}_sb_sub_app", "2021-11-01") + { + Parent = _serviceBusTopic_app, + IsClientAffine = false, + LockDuration = new StringLiteral("PT30S"), + RequiresSession = false, + DefaultMessageTimeToLive = new StringLiteral("P14D"), + DeadLetteringOnFilterEvaluationExceptions = true, + DeadLetteringOnMessageExpiration = true, + MaxDeliveryCount = 10, + EnableBatchedOperations = true, + Status = ServiceBusMessagingEntityStatus.Active + }; + _eventGridTopic_Blobs = new($"{_name}_eg_blob", "2022-06-15") + { + TopicType = "Microsoft.Storage.StorageAccounts", + Source = _storage.Id, + Identity = managedServiceIdentity + }; + _systemTopicEventSubscription = new($"{_name}_eg_blob_sub", "2022-06-15") + { + Parent = _eventGridTopic_Blobs, + DeliveryWithResourceIdentity = new DeliveryWithResourceIdentity + { + Identity = new EventSubscriptionIdentity + { + IdentityType = EventSubscriptionIdentityType.UserAssigned, + UserAssignedIdentity = _identity.Id + }, + Destination = new EventHubEventSubscriptionDestination + { + ResourceId = _serviceBusTopic_main.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 + } + }; + } + + public override ProvisioningPlan Build(ProvisioningContext? context = null) + { + // Always add a default location parameter. + // azd assumes there will be a location parameter for every module. + // The Infrastructure location resolver will resolve unset Location properties to this parameter. + Add(new BicepParameter("location", typeof(string)) + { + Description = "The location for the resource(s) to be deployed.", + Value = BicepFunction.GetResourceGroup().Location + }); + + Add(PrincipalIdParameter); + Add(PrincipalTypeParameter); + Add(PrincipalNameParameter); + + Add(_identity); + Add(_storage); + Add(_storage.AssignRole(StorageBuiltInRole.StorageBlobDataContributor, RoleManagementPrincipalType.User, PrincipalIdParameter)); + Add(_storage.AssignRole(StorageBuiltInRole.StorageTableDataContributor, RoleManagementPrincipalType.User, PrincipalIdParameter)); + Add(_container); + Add(_blobs); + Add(_serviceBusNamespace); + Add(_serviceBusNamespace.AssignRole(ServiceBusBuiltInRole.AzureServiceBusDataOwner, RoleManagementPrincipalType.User, PrincipalIdParameter)); + Add(_serviceBusNamespaceAuthorizationRule); + Add(_serviceBusTopic_main); + Add(_serviceBusTopic_app); + Add(_serviceBusSubscription_main); + Add(_serviceBusSubscription_app); + + // This is necessary until SystemTopic adds an AssignRole method. + var role = ServiceBusBuiltInRole.AzureServiceBusDataOwner; + RoleAssignment roleAssignment = new RoleAssignment(_eventGridTopic_Blobs.ResourceName + "_" + _identity.ResourceName + "_" + ServiceBusBuiltInRole.GetBuiltInRoleName(role)); + roleAssignment.Name = BicepFunction.CreateGuid(_eventGridTopic_Blobs.Id, _identity.Id, BicepFunction.GetSubscriptionResourceId("Microsoft.Authorization/roleDefinitions", role.ToString())); + roleAssignment.Scope = new IdentifierExpression(_eventGridTopic_Blobs.ResourceName); + roleAssignment.PrincipalType = RoleManagementPrincipalType.ServicePrincipal; + roleAssignment.RoleDefinitionId = BicepFunction.GetSubscriptionResourceId("Microsoft.Authorization/roleDefinitions", role.ToString()); + roleAssignment.PrincipalId = _identity.PrincipalId; + Add(roleAssignment); + Add(_systemTopicEventSubscription); + Add(_eventGridTopic_Blobs); + + // Placeholders for now. + Add(new BicepOutput($"storage_name", typeof(string)) { Value = _storage.Name }); + Add(new BicepOutput($"servicebus_name", typeof(string)) { Value = _serviceBusNamespace.Name }); + + return base.Build(context); + } +} diff --git a/sdk/provisioning/Azure.Provisioning.CloudMachine/src/Properties/AssemblyInfo.cs b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000000..15a940a47a165 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.CloudMachine/src/Properties/AssemblyInfo.cs @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Diagnostics.CodeAnalysis; + +[assembly: Experimental("AZPROVISION001")] diff --git a/sdk/provisioning/Azure.Provisioning.CloudMachine/tests/Azure.Provisioning.CloudMachine.Tests.csproj b/sdk/provisioning/Azure.Provisioning.CloudMachine/tests/Azure.Provisioning.CloudMachine.Tests.csproj new file mode 100644 index 0000000000000..67db81d05c870 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.CloudMachine/tests/Azure.Provisioning.CloudMachine.Tests.csproj @@ -0,0 +1,9 @@ + + + 12 + + + + + + diff --git a/sdk/provisioning/Azure.Provisioning.sln b/sdk/provisioning/Azure.Provisioning.sln index 4bc1e399e99af..9c190c0c12290 100644 --- a/sdk/provisioning/Azure.Provisioning.sln +++ b/sdk/provisioning/Azure.Provisioning.sln @@ -106,6 +106,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Provisioning.WebPubSu EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Provisioning.WebPubSub.Tests", "Azure.Provisioning.WebPubSub\tests\Azure.Provisioning.WebPubSub.Tests.csproj", "{015670AB-881C-464F-8545-E686C9A92C4F}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Azure.Provisioning.CloudMachine", "Azure.Provisioning.CloudMachine", "{DB2FC0CB-7103-4D3C-A737-8C6AB61168F8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Provisioning.CloudMachine", "Azure.Provisioning.CloudMachine\src\Azure.Provisioning.CloudMachine.csproj", "{F54CA64F-3BB8-49D5-AE3B-3408AE324632}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Provisioning.CloudMachine.Tests", "Azure.Provisioning.CloudMachine\tests\Azure.Provisioning.CloudMachine.Tests.csproj", "{94642992-7CC0-4649-B58F-8E5E3F134C8A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -308,6 +314,14 @@ Global {015670AB-881C-464F-8545-E686C9A92C4F}.Debug|Any CPU.Build.0 = Debug|Any CPU {015670AB-881C-464F-8545-E686C9A92C4F}.Release|Any CPU.ActiveCfg = Release|Any CPU {015670AB-881C-464F-8545-E686C9A92C4F}.Release|Any CPU.Build.0 = Release|Any CPU + {F54CA64F-3BB8-49D5-AE3B-3408AE324632}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F54CA64F-3BB8-49D5-AE3B-3408AE324632}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F54CA64F-3BB8-49D5-AE3B-3408AE324632}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F54CA64F-3BB8-49D5-AE3B-3408AE324632}.Release|Any CPU.Build.0 = Release|Any CPU + {94642992-7CC0-4649-B58F-8E5E3F134C8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {94642992-7CC0-4649-B58F-8E5E3F134C8A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {94642992-7CC0-4649-B58F-8E5E3F134C8A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {94642992-7CC0-4649-B58F-8E5E3F134C8A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -315,4 +329,8 @@ Global GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7CB2D417-323C-4A66-9355-26459881303F} EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {F54CA64F-3BB8-49D5-AE3B-3408AE324632} = {DB2FC0CB-7103-4D3C-A737-8C6AB61168F8} + {94642992-7CC0-4649-B58F-8E5E3F134C8A} = {DB2FC0CB-7103-4D3C-A737-8C6AB61168F8} + EndGlobalSection EndGlobal diff --git a/sdk/provisioning/ci.compute.yml b/sdk/provisioning/ci.compute.yml index 5f8eb541aa1f4..6b3c935bbdd4a 100644 --- a/sdk/provisioning/ci.compute.yml +++ b/sdk/provisioning/ci.compute.yml @@ -13,6 +13,7 @@ trigger: - sdk/provisioning/Azure.Provisioning.AppContainers - sdk/provisioning/Azure.Provisioning.ApplicationInsights - sdk/provisioning/Azure.Provisioning.AppService + - sdk/provisioning/Azure.Provisioning.CloudMachine - sdk/provisioning/Azure.Provisioning.Communication - sdk/provisioning/Azure.Provisioning.ContainerRegistry - sdk/provisioning/Azure.Provisioning.ContainerService @@ -37,6 +38,7 @@ pr: - sdk/provisioning/Azure.Provisioning.AppContainers - sdk/provisioning/Azure.Provisioning.ApplicationInsights - sdk/provisioning/Azure.Provisioning.AppService + - sdk/provisioning/Azure.Provisioning.CloudMachine - sdk/provisioning/Azure.Provisioning.Communication - sdk/provisioning/Azure.Provisioning.ContainerRegistry - sdk/provisioning/Azure.Provisioning.ContainerService @@ -62,6 +64,8 @@ extends: safeName: AzureProvisioningApplicationInsights - name: Azure.Provisioning.AppService safeName: AzureProvisioningAppService + - name: Azure.Provisioning.CloudMachine + safeName: AzureProvisioningCloudMachine - name: Azure.Provisioning.Communication safeName: AzureProvisioningCommunication - name: Azure.Provisioning.ContainerRegistry diff --git a/sdk/provisioning/service.projects b/sdk/provisioning/service.projects index 3fd8eefd48817..85c4b3ac4073a 100644 --- a/sdk/provisioning/service.projects +++ b/sdk/provisioning/service.projects @@ -17,6 +17,7 @@ +