From b6b8efd54f1c1ba6551294f4850d68843f00f3cd Mon Sep 17 00:00:00 2001 From: Mark Cowlishaw Date: Sat, 21 Jun 2025 16:33:57 -0700 Subject: [PATCH 01/16] Initial parameter types --- .../lib/Legacy/arm.legacy.tsp | 3 +++ .../lib/Legacy/extension.tsp | 0 .../lib/arm.tsp | 1 + .../lib/common-types/internal.tsp | 3 +++ .../lib/decorators.tsp | 2 +- .../lib/extension/extension.tsp | 7 +++++ .../lib/extension/models.tsp | 26 +++++++++++++++++++ .../lib/extension/operations.tsp | 5 ++++ .../lib/extension/parameters.tsp | 5 ++++ .../lib/extension/private.decorators.tsp | 13 ++++++++++ 10 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 packages/typespec-azure-resource-manager/lib/Legacy/extension.tsp create mode 100644 packages/typespec-azure-resource-manager/lib/extension/extension.tsp create mode 100644 packages/typespec-azure-resource-manager/lib/extension/models.tsp create mode 100644 packages/typespec-azure-resource-manager/lib/extension/operations.tsp create mode 100644 packages/typespec-azure-resource-manager/lib/extension/parameters.tsp create mode 100644 packages/typespec-azure-resource-manager/lib/extension/private.decorators.tsp diff --git a/packages/typespec-azure-resource-manager/lib/Legacy/arm.legacy.tsp b/packages/typespec-azure-resource-manager/lib/Legacy/arm.legacy.tsp index d9a1926a53..8858580c10 100644 --- a/packages/typespec-azure-resource-manager/lib/Legacy/arm.legacy.tsp +++ b/packages/typespec-azure-resource-manager/lib/Legacy/arm.legacy.tsp @@ -2,3 +2,6 @@ import "./managed-identity.tsp"; import "./decorator.tsp"; import "./operations.tsp"; import "./interfaces.tsp"; +import "./extension.tsp"; + +namespace Azure.ResourceManager.Legacy; diff --git a/packages/typespec-azure-resource-manager/lib/Legacy/extension.tsp b/packages/typespec-azure-resource-manager/lib/Legacy/extension.tsp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/typespec-azure-resource-manager/lib/arm.tsp b/packages/typespec-azure-resource-manager/lib/arm.tsp index 89af7ed2dd..443205d238 100644 --- a/packages/typespec-azure-resource-manager/lib/arm.tsp +++ b/packages/typespec-azure-resource-manager/lib/arm.tsp @@ -8,6 +8,7 @@ import "@azure-tools/typespec-azure-core"; import "./foundations/arm.foundations.tsp"; import "./Legacy/arm.legacy.tsp"; import "./common-types/common-types.tsp"; +import "./extension/extension.tsp"; import "./backcompat.tsp"; import "./private.decorators.tsp"; import "./models.tsp"; diff --git a/packages/typespec-azure-resource-manager/lib/common-types/internal.tsp b/packages/typespec-azure-resource-manager/lib/common-types/internal.tsp index c1334a48a3..f2d0c3acf4 100644 --- a/packages/typespec-azure-resource-manager/lib/common-types/internal.tsp +++ b/packages/typespec-azure-resource-manager/lib/common-types/internal.tsp @@ -18,6 +18,9 @@ enum ResourceHome { @doc("The resource is bound to an extension") Extension, + + @doc("The resource is built in") + BuiltIn, } /** Alias of keyEncryptionKeyIdentity for back compatibility. Please change to keyEncryptionKeyIdentity. */ diff --git a/packages/typespec-azure-resource-manager/lib/decorators.tsp b/packages/typespec-azure-resource-manager/lib/decorators.tsp index 7e50611a59..f2ec50846a 100644 --- a/packages/typespec-azure-resource-manager/lib/decorators.tsp +++ b/packages/typespec-azure-resource-manager/lib/decorators.tsp @@ -180,7 +180,7 @@ extern dec armCommonTypesVersion( * * @param propertiesType: The type of the resource properties. */ -extern dec armVirtualResource(target: Model); +extern dec armVirtualResource(target: Model, provider?: valueof string); /** * This decorator sets the base type of the given resource. diff --git a/packages/typespec-azure-resource-manager/lib/extension/extension.tsp b/packages/typespec-azure-resource-manager/lib/extension/extension.tsp new file mode 100644 index 0000000000..6610b4149c --- /dev/null +++ b/packages/typespec-azure-resource-manager/lib/extension/extension.tsp @@ -0,0 +1,7 @@ +import "@azure-tools/typespec-azure-core"; +import "./models.tsp"; +import "./operations.tsp"; +import "./parameters.tsp"; +import "./private.decorators.tsp"; + +namespace Azure.resourceManager.Extension; diff --git a/packages/typespec-azure-resource-manager/lib/extension/models.tsp b/packages/typespec-azure-resource-manager/lib/extension/models.tsp new file mode 100644 index 0000000000..176ccbfb6d --- /dev/null +++ b/packages/typespec-azure-resource-manager/lib/extension/models.tsp @@ -0,0 +1,26 @@ +using Http; +using Rest; +using Azure.Core; +using Azure.ResourceManager.Private; + +namespace Azure.ResourceManager.Extension; + +/** Represents an extension resource group */ +@parentResource(Subscription) +@Private.builtInResource +model ResourceGroup is CommonTypes.ResourceGroupNameParameter; + +@Private.builtInResource +model Subscription is CommonTypes.SubscriptionIdParameter; + +/** Represents a management group */ +@tenantResource +@armVirtualResource("Microsoft.Management") +model ManagementGroup { + @path + @minLength(1) + @segment("managementGroups") + @key + @doc("The management group ID.") + managementGroupName: string; +} diff --git a/packages/typespec-azure-resource-manager/lib/extension/operations.tsp b/packages/typespec-azure-resource-manager/lib/extension/operations.tsp new file mode 100644 index 0000000000..45a3c19e4f --- /dev/null +++ b/packages/typespec-azure-resource-manager/lib/extension/operations.tsp @@ -0,0 +1,5 @@ +using Http; +using Rest; +using Azure.Core; + +namespace Azure.ResourceManager.Extension; diff --git a/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp b/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp new file mode 100644 index 0000000000..45a3c19e4f --- /dev/null +++ b/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp @@ -0,0 +1,5 @@ +using Http; +using Rest; +using Azure.Core; + +namespace Azure.ResourceManager.Extension; diff --git a/packages/typespec-azure-resource-manager/lib/extension/private.decorators.tsp b/packages/typespec-azure-resource-manager/lib/extension/private.decorators.tsp new file mode 100644 index 0000000000..12c17e9f2e --- /dev/null +++ b/packages/typespec-azure-resource-manager/lib/extension/private.decorators.tsp @@ -0,0 +1,13 @@ +using Http; +using Rest; +using Azure.Core; +using Reflection; + +namespace Azure.ResourceManager.Extension.Private; + +/** + * `@builtInResource` marks a model as built-in to Azure ResourceManager + * + * @param target - The model that is marked as built-in. + */ +extern dec builtInResource(target: Model); From 43683a99e0003bc88cfde0b953fcf4e8f624d1fc Mon Sep 17 00:00:00 2001 From: Mark Cowlishaw Date: Sun, 22 Jun 2025 20:03:29 -0700 Subject: [PATCH 02/16] Add implementation of standard async operations --- ...Azure.ResourceManager.Extension.Private.ts | 12 + .../generated-defs/Azure.ResourceManager.ts | 44 +- .../lib/common-types/common-types.tsp | 1 + .../commontypes.extension.models.tsp} | 13 +- .../lib/extension/extension.tsp | 1 - .../lib/extension/operations.tsp | 506 +++++++++++++++++- .../lib/extension/parameters.tsp | 67 +++ .../src/private.decorators.ts | 24 +- .../src/resource.ts | 36 +- 9 files changed, 671 insertions(+), 33 deletions(-) create mode 100644 packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.Extension.Private.ts rename packages/typespec-azure-resource-manager/lib/{extension/models.tsp => common-types/commontypes.extension.models.tsp} (57%) diff --git a/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.Extension.Private.ts b/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.Extension.Private.ts new file mode 100644 index 0000000000..efb9bccd24 --- /dev/null +++ b/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.Extension.Private.ts @@ -0,0 +1,12 @@ +import type { DecoratorContext, Model } from "@typespec/compiler"; + +/** + * `@builtInResource` marks a model as built-in to Azure ResourceManager + * + * @param target The model that is marked as built-in. + */ +export type BuiltInResourceDecorator = (context: DecoratorContext, target: Model) => void; + +export type AzureResourceManagerExtensionPrivateDecorators = { + builtInResource: BuiltInResourceDecorator; +}; diff --git a/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.ts b/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.ts index b00ea3befb..793d783ac6 100644 --- a/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.ts +++ b/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.ts @@ -26,6 +26,28 @@ export type ArmResourceCollectionActionDecorator = ( */ export type ArmProviderNameValueDecorator = (context: DecoratorContext, target: Operation) => void; +/** + * `@tenantResource` marks an Azure Resource Manager resource model as a Tenant resource/Root resource/Top-Level resource. + * + * Tenant resources have REST API paths like: + * `/provider/Microsoft.Contoso/FooResources` + * + * See more details on [different Azure Resource Manager resource type here.](https://azure.github.io/typespec-azure/docs/howtos/ARM/resource-type) + */ +export type TenantResourceDecorator = (context: DecoratorContext, target: Model) => void; + +/** + * This decorator is used on Azure Resource Manager resources that are not based on + * Azure.ResourceManager common types. + * + * @param propertiesType : The type of the resource properties. + */ +export type ArmVirtualResourceDecorator = ( + context: DecoratorContext, + target: Model, + provider?: string, +) => void; + /** * `@armProviderNamespace` sets the Azure Resource Manager provider name. It will default to use the * Namespace element value unless an override value is specified. @@ -88,16 +110,6 @@ export type SingletonDecorator = ( keyValue?: string | "default", ) => void; -/** - * `@tenantResource` marks an Azure Resource Manager resource model as a Tenant resource/Root resource/Top-Level resource. - * - * Tenant resources have REST API paths like: - * `/provider/Microsoft.Contoso/FooResources` - * - * See more details on [different Azure Resource Manager resource type here.](https://azure.github.io/typespec-azure/docs/howtos/ARM/resource-type) - */ -export type TenantResourceDecorator = (context: DecoratorContext, target: Model) => void; - /** * `@subscriptionResource` marks an Azure Resource Manager resource model as a subscription resource. * @@ -242,14 +254,6 @@ export type ArmCommonTypesVersionDecorator = ( version: string | EnumValue, ) => void; -/** - * This decorator is used on Azure Resource Manager resources that are not based on - * Azure.ResourceManager common types. - * - * @param propertiesType : The type of the resource properties. - */ -export type ArmVirtualResourceDecorator = (context: DecoratorContext, target: Model) => void; - /** * This decorator sets the base type of the given resource. * @@ -283,11 +287,12 @@ export type IdentifiersDecorator = ( export type AzureResourceManagerDecorators = { armResourceCollectionAction: ArmResourceCollectionActionDecorator; armProviderNameValue: ArmProviderNameValueDecorator; + tenantResource: TenantResourceDecorator; + armVirtualResource: ArmVirtualResourceDecorator; armProviderNamespace: ArmProviderNamespaceDecorator; useLibraryNamespace: UseLibraryNamespaceDecorator; armLibraryNamespace: ArmLibraryNamespaceDecorator; singleton: SingletonDecorator; - tenantResource: TenantResourceDecorator; subscriptionResource: SubscriptionResourceDecorator; locationResource: LocationResourceDecorator; resourceGroupResource: ResourceGroupResourceDecorator; @@ -300,7 +305,6 @@ export type AzureResourceManagerDecorators = { armResourceList: ArmResourceListDecorator; armResourceOperations: ArmResourceOperationsDecorator; armCommonTypesVersion: ArmCommonTypesVersionDecorator; - armVirtualResource: ArmVirtualResourceDecorator; resourceBaseType: ResourceBaseTypeDecorator; identifiers: IdentifiersDecorator; }; diff --git a/packages/typespec-azure-resource-manager/lib/common-types/common-types.tsp b/packages/typespec-azure-resource-manager/lib/common-types/common-types.tsp index f1f2af0394..c344f7181a 100644 --- a/packages/typespec-azure-resource-manager/lib/common-types/common-types.tsp +++ b/packages/typespec-azure-resource-manager/lib/common-types/common-types.tsp @@ -9,6 +9,7 @@ import "./customer-managed-keys-ref.tsp"; import "./extended-location-ref.tsp"; import "./internal.tsp"; import "./commontypes.private.decorators.tsp"; +import "./commontypes.extension.models.tsp"; import "./versions.tsp"; import "./mobo-ref.tsp"; import "./network-security-perimeter-ref.tsp"; diff --git a/packages/typespec-azure-resource-manager/lib/extension/models.tsp b/packages/typespec-azure-resource-manager/lib/common-types/commontypes.extension.models.tsp similarity index 57% rename from packages/typespec-azure-resource-manager/lib/extension/models.tsp rename to packages/typespec-azure-resource-manager/lib/common-types/commontypes.extension.models.tsp index 176ccbfb6d..64ea0c3650 100644 --- a/packages/typespec-azure-resource-manager/lib/extension/models.tsp +++ b/packages/typespec-azure-resource-manager/lib/common-types/commontypes.extension.models.tsp @@ -2,16 +2,17 @@ using Http; using Rest; using Azure.Core; using Azure.ResourceManager.Private; +using Azure.ResourceManager.Extension.Private; -namespace Azure.ResourceManager.Extension; +namespace Azure.ResourceManager.CommonTypes.Extension; /** Represents an extension resource group */ -@parentResource(Subscription) -@Private.builtInResource -model ResourceGroup is CommonTypes.ResourceGroupNameParameter; +@parentResource(SubscriptionTarget) +@builtInResource +model ResourceGroupTarget is ResourceGroupParameter; -@Private.builtInResource -model Subscription is CommonTypes.SubscriptionIdParameter; +@builtInResource +model SubscriptionTarget is SubscriptionIdParameter; /** Represents a management group */ @tenantResource diff --git a/packages/typespec-azure-resource-manager/lib/extension/extension.tsp b/packages/typespec-azure-resource-manager/lib/extension/extension.tsp index 6610b4149c..89caf0231e 100644 --- a/packages/typespec-azure-resource-manager/lib/extension/extension.tsp +++ b/packages/typespec-azure-resource-manager/lib/extension/extension.tsp @@ -1,5 +1,4 @@ import "@azure-tools/typespec-azure-core"; -import "./models.tsp"; import "./operations.tsp"; import "./parameters.tsp"; import "./private.decorators.tsp"; diff --git a/packages/typespec-azure-resource-manager/lib/extension/operations.tsp b/packages/typespec-azure-resource-manager/lib/extension/operations.tsp index 45a3c19e4f..b578bdf306 100644 --- a/packages/typespec-azure-resource-manager/lib/extension/operations.tsp +++ b/packages/typespec-azure-resource-manager/lib/extension/operations.tsp @@ -1,5 +1,507 @@ +namespace Azure.ResourceManager.Extension; + using Http; using Rest; -using Azure.Core; +using Azure.ResourceManager.Foundations; +using Azure.ResourceManager.Private; -namespace Azure.ResourceManager.Extension; +// OPERATION TEMPLATES + +/** + * List an extension resource at the given target scope + * @template TargetResource The target to list at, e.g. Extension.Subscription or Extension>ManagementGroup or Extension.ResourceGroup + * @template ExtensionResource the resource being listed + * @template Parameters Optional. Additional parameters after the path parameters + * @template Response Optional. The success response for the list operation + * @template Error Optional. The error response, if non-standard. + */ +@autoRoute +@doc("List {name} resources by subscription ID", ExtensionResource) +@listsResource(ExtensionResource) +@segmentOf(ExtensionResource) +@armResourceList(ExtensionResource) +@get +@enforceConstraint(TargetResource, Foundations.Resource) +@enforceConstraint(ExtensionResource, Foundations.Resource) +op ListByTarget< + TargetResource extends Foundations.SimpleResource, + ExtensionResource extends Foundations.SimpleResource, + Parameters extends {} = {}, + Response extends {} = ArmResponse>, + Error extends {} = ErrorResponse +> is ArmReadOperation< + ExtensionParentParameters & Parameters, + Response, + Error +>; + +/** + * A resource GET operation + * @template TargetResource The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup + * @template ExtensionResource the resource being rea + * @template Parameters Optional. Additional parameters after the path parameters + * @template Response Optional. The success response for the read operation + * @template Error Optional. The error response, if non-standard. + */ +@autoRoute +@doc("Get a {name}", ExtensionResource) +@get +@enforceConstraint(TargetResource, Foundations.Resource) +@enforceConstraint(ExtensionResource, Foundations.Resource) +@armResourceRead(ExtensionResource) +op Read< + TargetResource extends SimpleResource, + ExtensionResource extends SimpleResource, + Parameters extends {} = {}, + Response extends {} = ArmResponse, + Error extends {} = ErrorResponse +> is ArmReadOperation< + ExtensionInstanceParameters & Parameters, + Response, + Error +>; + +/** + * Check a resource's existence via HEAD operation + * @template TargetResource The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup + * @template ExtensionResource the extension resource being checked + * @template Parameters Optional. Additional parameters after the path parameters + * @template Response Optional. The success response for the read operation + * @template Error Optional. The error response, if non-standard. + */ +@autoRoute +@doc("Check for the existence of a {name}", ExtensionResource) +@enforceConstraint(TargetResource, Foundations.Resource) +@enforceConstraint(ExtensionResource, Foundations.Resource) +@head +op CheckExistence< + TargetResource extends SimpleResource, + ExtensionResource extends SimpleResource, + Parameters extends {} = {}, + Response extends {} = ArmResourceExistsResponse | ArmResourceNotFoundResponse, + Error extends {} = ErrorResponse +> is ArmReadOperation< + ExtensionInstanceParameters & Parameters, + Response, + Error +>; + +/** + * A long-running resource CreateOrUpdate (PUT) + * @template TargetResource the target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup + * @template ExtensionResource the resource being created or updated + * @template LroHeaders Optional. Allows overriding the lro headers returned on resource create + * @template Parameters Optional. Additional parameters after the path parameters + * @template Response Optional. The success response for the createOrUpdate operation + * @template Error Optional. The error response, if non-standard. + */ +@autoRoute +@doc("Create a {name}", ExtensionResource) +@armResourceCreateOrUpdate(ExtensionResource) +@enforceConstraint(TargetResource, Foundations.Resource) +@enforceConstraint(ExtensionResource, Foundations.Resource) +@Azure.Core.Foundations.Private.defaultFinalStateVia(#["location", "azure-async-operation"]) +@put +op CreateOrUpdateAsync< + TargetResource extends Foundations.SimpleResource, + ExtensionResource extends Foundations.SimpleResource, + LroHeaders extends TypeSpec.Reflection.Model = ArmAsyncOperationHeader & + Azure.Core.Foundations.RetryAfterHeader, + Parameters extends {} = {}, + Response extends {} = ArmResourceUpdatedResponse | ArmResourceCreatedResponse< + ExtensionResource, + LroHeaders + >, + Error extends {} = ErrorResponse +> is ArmCreateOperation< + ExtensionInstanceParameters & Parameters, + ExtensionResource, + Response, + Error +>; + +/** + * Synchronous PUT operation for Azure Resource Manager resources + * @template TargetResource the target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup + * @template ExtensionResource the resource being created or replaced + * @template Parameters Optional. Additional parameters after the path parameters + * @template Response Optional. The success response for the createOrUpdate operation + * @template Error Optional. The error response, if non-standard. + */ +@autoRoute +@doc("Create a {name}", ExtensionResource) +@armResourceCreateOrUpdate(ExtensionResource) +@enforceConstraint(TargetResource, Foundations.Resource) +@enforceConstraint(ExtensionResource, Foundations.Resource) +@put +op CreateOrReplaceSync< + TargetResource extends Foundations.SimpleResource, + ExtensionResource extends Foundations.SimpleResource, + Parameters extends {} = {}, + Response extends {} = ArmResourceUpdatedResponse | ArmResourceCreatedSyncResponse, + Error extends {} = ErrorResponse +> is ArmCreateOperation< + ExtensionInstanceParameters & Parameters, + ExtensionResource, + Response, + Error +>; + +/** + * @dev A long-running resource CreateOrUpdate (PUT) + * @template TargetResource the target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup + * @template ExtensionResource the resource being created or replaced + * @template LroHeaders Optional. Allows overriding the lro headers returned on resource create + * @template Parameters Optional. Additional parameters after the path parameters + * @template Response Optional. The success response for the createOrReplace operation + * @template Error Optional. The error response, if non-standard. + */ +@enforceConstraint(TargetResource, Foundations.Resource) +@enforceConstraint(ExtensionResource, Foundations.Resource) +op CreateOrReplaceAsync< + TargetResource extends Foundations.SimpleResource, + ExtensionResource extends Foundations.SimpleResource, + LroHeaders extends TypeSpec.Reflection.Model = ArmAsyncOperationHeader & + Azure.Core.Foundations.RetryAfterHeader, + Parameters extends {} = {}, + Response extends {} = ArmResourceUpdatedResponse | ArmResourceCreatedResponse< + ExtensionResource, + LroHeaders + >, + Error extends {} = ErrorResponse +> is CreateOrUpdateAsync< + TargetResource, + ExtensionResource, + LroHeaders, + Parameters, + Response, + Error +>; + +/** + * A long-running resource update using a custom PATCH payload (Asynchronous) + * @template TargetResource the target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup + * @template ExtensionResource the resource being patched + * @template PatchModel The input model for the PATCH request + * @template LroHeaders Optional. Allows overriding the lro headers returned in the Accepted response + * @template Parameters Optional. Additional parameters after the path parameters + * @template Response Optional. The success response for the patch operation + * @template Error Optional. The error response, if non-standard. + */ +@autoRoute +@doc("Update a {name}", ExtensionResource) +@armResourceUpdate(ExtensionResource) +@enforceConstraint(TargetResource, Foundations.Resource) +@enforceConstraint(ExtensionResource, Foundations.Resource) +@patch(#{ implicitOptionality: true }) +op CustomPatchAsync< + TargetResource extends Foundations.SimpleResource, + ExtensionResource extends Foundations.SimpleResource, + PatchModel extends TypeSpec.Reflection.Model = TagsUpdateModel, + LroHeaders extends TypeSpec.Reflection.Model = ArmLroLocationHeader< + Azure.Core.StatusMonitorPollingOptions, + ExtensionResource, + string + > & + Azure.Core.Foundations.RetryAfterHeader, + Parameters extends {} = {}, + Response extends {} = ArmResponse | ArmAcceptedLroResponse< + "Resource update request accepted.", + LroHeaders + >, + Error extends {} = ErrorResponse +> is ArmUpdateOperation< + ExtensionInstanceParameters & Parameters, + PatchModel, + Response, + Error +>; + +/** + * A resource update using a custom PATCH payload (synchronous) + * @template TargetResource the target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup + * @template ExtensionResource the resource being patched + * @template PatchModel The input model for the PATCH request + * @template Parameters Optional. Additional parameters after the path parameters + * @template Response Optional. The success response for the patch operation + * @template Error Optional. The error response, if non-standard. + */ +@autoRoute +@doc("Update a {name}", ExtensionResource) +@armResourceUpdate(ExtensionResource) +@enforceConstraint(TargetResource, Foundations.Resource) +@enforceConstraint(ExtensionResource, Foundations.Resource) +@patch(#{ implicitOptionality: true }) +op CustomPatchSync< + TargetResource extends Foundations.SimpleResource, + ExtensionResource extends Foundations.SimpleResource, + PatchModel extends TypeSpec.Reflection.Model = TagsUpdateModel, + Parameters extends {} = {}, + Response extends {} = ArmResponse, + Error extends {} = ErrorResponse +> is ArmUpdateOperation< + ExtensionInstanceParameters & Parameters, + PatchModel, + Response, + Error +>; + +/** + * @dev Delete a resource asynchronously + * @template TargetResource The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup + * @template ExtensionResource The resource being deleted + * @template Response The response type for the operation + * @template Parameters Optional. Additional parameters after the path parameters + * @template Error Optional. The error response, if non-standard. + */ +@autoRoute +@doc("Delete a {name}", ExtensionResource) +@armResourceDelete(ExtensionResource) +@enforceConstraint(TargetResource, Foundations.Resource) +@enforceConstraint(ExtensionResource, Foundations.Resource) +@delete +op DeleteAsyncBase< + TargetResource extends Foundations.SimpleResource, + ExtensionResource extends Foundations.SimpleResource, + Response, + Parameters extends {} = {}, + Error extends {} = ErrorResponse +>( + ...ExtensionInstanceParameters, + ...Parameters, +): Response | Error; + +/** + * @dev Delete a resource asynchronously. + * @template TargetResource The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup + * @template ExtensionResource The resource being deleted + * @template LroHeaders Optional. Allows overriding the headers in the Accepted response + * @template Parameters Optional. Additional parameters after the path parameters + * @template Response Optional. The success response(s) for the delete operation + * @template Error Optional. The error response, if non-standard. + */ +#deprecated "Use 'DeleteWithoutOkAsync' instead" +@enforceConstraint(TargetResource, Foundations.Resource) +@enforceConstraint(ExtensionResource, Foundations.Resource) +op DeleteAsync< + TargetResource extends Foundations.SimpleResource, + ExtensionResource extends Foundations.SimpleResource, + LroHeaders extends TypeSpec.Reflection.Model = ArmLroLocationHeader & + Azure.Core.Foundations.RetryAfterHeader, + Parameters extends {} = {}, + Response extends {} = ArmDeletedResponse | ArmDeleteAcceptedLroResponse | ArmDeletedNoContentResponse, + Error extends {} = ErrorResponse +> is DeleteAsyncBase; + +/** + * @dev Delete a resource asynchronously + * @template TargetResource The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup + * @template ExtensionResource The resource being deleted + * @template LroHeaders Optional. Allows overriding the headers returned in the Accepted response + * @template Parameters Optional. Additional parameters after the path parameters + * @template Response Optional. The success response(s) for the delete operation + * @template Error Optional. The error response, if non-standard. + */ +@enforceConstraint(TargetResource, Foundations.Resource) +@enforceConstraint(ExtensionResource, Foundations.Resource) +op ArmResourceDeleteWithoutOkAsync< + TargetResource extends Foundations.SimpleResource, + ExtensionResource extends Foundations.SimpleResource, + LroHeaders extends TypeSpec.Reflection.Model = ArmLroLocationHeader & + Azure.Core.Foundations.RetryAfterHeader, + Parameters extends {} = {}, + Response extends {} = ArmDeleteAcceptedLroResponse | ArmDeletedNoContentResponse, + Error extends {} = ErrorResponse +> is DeleteAsyncBase; + +/** + * Delete a resource synchronously + * @template TargetResource The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup + * @template ExtensionResource The resource being deleted + * @template Parameters Optional. Additional parameters after the path parameters + * @template Response Optional. The success response(s) for the delete operation + * @template Error Optional. The error response, if non-standard. + */ +@autoRoute +@doc("Delete a {name}", ExtensionResource) +@armResourceDelete(ExtensionResource) +@enforceConstraint(TargetResource, Foundations.Resource) +@enforceConstraint(ExtensionResource, Foundations.Resource) +@delete +op DeleteSync< + TargetResource extends Foundations.SimpleResource, + ExtensionResource extends Foundations.SimpleResource, + Parameters extends {} = {}, + Response extends {} = ArmDeletedResponse | ArmDeletedNoContentResponse, + Error = ErrorResponse +>( + ...ExtensionInstanceParameters, + ...Parameters, +): Response | Error; + +/** + * A long-running resource action. + * @template TargetResource The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup + * @template ExtensionResource The resource being acted upon + * @template Request The request model for the action + * @template Response The response type for the action + * @template Parameters Optional. Additional parameters after the path parameters + * @template Error Optional. The error response, if non-standard. + * @template OptionalRequestBody Optional. Indicates whether the request body is optional. + */ +@autoRoute +@armResourceAction(ExtensionResource) +@enforceConstraint(TargetResource, Foundations.Resource) +@enforceConstraint(ExtensionResource, Foundations.Resource) +@post +op ActionAsyncBase< + TargetResource extends Foundations.SimpleResource, + ExtensionResource extends Foundations.SimpleResource, + Request extends TypeSpec.Reflection.Model | void, + Response extends TypeSpec.Reflection.Model | void, + Parameters extends {} = {}, + Error extends {} = ErrorResponse, + OptionalRequestBody extends valueof boolean = false +>( + ...ExtensionInstanceParameters, + ...Parameters, + + @doc("The content of the action request") + @armBodyRoot(OptionalRequestBody) + body: Request, +): Response | Error; + +/** + * @dev A long-running resource action. + * @template TargetResource The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup + * @template ExtensionResource The resource being acted upon + * @template Request The request model for the action + * @template Response The response model for the action + * @template LroHeaders Optional. Allows overriding the headers returned in the Accepted response + * @template Parameters Optional. Additional parameters after the path parameters + * @template Error Optional. The error response, if non-standard. + * @template OptionalRequestBody Optional. Indicates whether the body parameter is optional. + */ +@returnsDoc("Azure operation completed successfully.") +@enforceConstraint(ExtensionResource, Foundations.Resource) +op ActionAsync< + TargetResource extends Foundations.SimpleResource, + ExtensionResource extends Foundations.SimpleResource, + Request extends TypeSpec.Reflection.Model | void, + Response extends TypeSpec.Reflection.Model | void, + LroHeaders extends TypeSpec.Reflection.Model = ArmLroLocationHeader< + Azure.Core.StatusMonitorPollingOptions, + Response, + string + > & + Azure.Core.Foundations.RetryAfterHeader, + Parameters extends {} = {}, + Error extends {} = ErrorResponse, + OptionalRequestBody extends valueof boolean = false +> is ActionAsyncBase< + TargetResource, + ExtensionResource, + Request, + ArmAcceptedLroResponse<"Resource operation accepted.", LroHeaders> | Response, + Parameters, + Error, + OptionalRequestBody +>; + +/** + * A synchronous resource action. + * @template TargetResource The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup + * @template ExtensionResource The resource being acted upon + * @template Request The request model for the action + * @template Response The response model for the action + * @template Parameters Optional. Additional parameters after the path parameters + * @template Error Optional. The error response, if non-standard. + * @template OptionalRequestBody Optional. Indicates whether the body parameter is optional. + */ +@autoRoute +@armResourceAction(ExtensionResource) +@enforceConstraint(TargetResource, Foundations.Resource) +@enforceConstraint(ExtensionResource, Foundations.Resource) +@post +@returnsDoc("Azure operation completed successfully.") +op ActionSync< + TargetResource extends Foundations.SimpleResource, + ExtensionResource extends Foundations.SimpleResource, + Request extends TypeSpec.Reflection.Model | void, + Response extends TypeSpec.Reflection.Model | void, + Parameters extends {} = {}, + Error extends {} = ErrorResponse, + OptionalRequestBody extends valueof boolean = false +>( + ...ExtensionInstanceParameters, + ...Parameters, + + @doc("The content of the action request") + @armBodyRoot(OptionalRequestBody) + body: Request, +): Response | Error; + +/** + * @dev A long-running resource action that returns no content. + * @template TargetResource The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup + * @template ExtensionResource The resource being acted upon + * @template Request The request model for the action + * @template LroHeaders Optional. Allows overriding the headers returned in the Accepted response + * @template Parameters Optional. Additional parameters after the path parameters + * @template Error Optional. The error response, if non-standard. + * @template OptionalRequestBody Optional. Indicates whether the body parameter is optional. + */ +@enforceConstraint(TargetResource, Foundations.Resource) +@enforceConstraint(ExtensionResource, Foundations.Resource) +op ActionNoResponseContentAsync< + TargetResource extends Foundations.SimpleResource, + ExtensionResource extends Foundations.SimpleResource, + Request extends TypeSpec.Reflection.Model | void, + LroHeaders extends TypeSpec.Reflection.Model = ArmLroLocationHeader< + Azure.Core.StatusMonitorPollingOptions, + void, + string + > & + Azure.Core.Foundations.RetryAfterHeader, + Parameters extends {} = {}, + Error extends {} = ErrorResponse, + OptionalRequestBody extends valueof boolean = false +> is ActionAsyncBase< + TargetResource, + ExtensionResource, + Request, + ArmAcceptedLroResponse<"Resource operation accepted.", LroHeaders>, + Parameters, + Error, + OptionalRequestBody +>; + +/** + * A synchronous resource action that returns no content. + * @template TargetResource The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup + * @template ExtensionResource The resource being acted upon + * @template Request The request model for the action + * @template Parameters Optional. Additional parameters after the path parameters + * @template Error Optional. The error response, if non-standard. + * @template OptionalRequestBody Optional. Indicates whether the request body is optional. + */ +@autoRoute +@armResourceAction(ExtensionResource) +@enforceConstraint(TargetResource, Foundations.Resource) +@enforceConstraint(ExtensionResource, Foundations.Resource) +@post +op ActionNoContentSync< + TargetResource extends Foundations.SimpleResource, + ExtensionResource extends Foundations.SimpleResource, + Request extends TypeSpec.Reflection.Model | void, + Parameters extends {} = {}, + Error extends {} = ErrorResponse, + OptionalRequestBody extends valueof boolean = false +>( + ...ExtensionInstanceParameters, + ...Parameters, + + @doc("The content of the action request") + @armBodyRoot(OptionalRequestBody) + body: Request, +): ArmNoContentResponse<"Action completed successfully."> | Error; diff --git a/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp b/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp index 45a3c19e4f..4d830e6433 100644 --- a/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp +++ b/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp @@ -1,5 +1,72 @@ using Http; using Rest; using Azure.Core; +using Azure.ResourceManager; +using Azure.ResourceManager.Private; +using Azure.ResourceManager.Foundations; +using Azure.ResourceManager.Extension.Private; namespace Azure.ResourceManager.Extension; + +/** + * The default scope parameter type. + * + * @example + * ```typespec + * model Employee { + * ...ResourceUriParameter; + * } + * ``` + */ +@doc("The default resourceUri parameter type.") +@builtInResource +model ScopeParameter { + @path(#{ allowReserved: true }) + @doc("The fully qualified Azure Resource manager identifier of the resource.") + scope: Type; +} +/** + * Base parameters for a resource. + * @template Resource The type of the resource. + */ +@resourceBaseParametersOf(Resource) +model TargetBaseParameters { + ...ApiVersionParameter; + + // unless tenant or extension + ...CommonTypes.SubscriptionIdParameter; + + // unless tenant, subscription, location, or extension + ...CommonTypes.ResourceGroupNameParameter; +} + +model TargetParameters { + ...TargetBaseParameters; + ...ProviderNamespace; + ...KeysOf; +} + +model ExtensionProviderNamespace { + @path + @segment("providers") + @key + @assignProviderNameValue(ExtensionResource) + @doc("The provider namespace for the resource.") + extensionProvider: "Microsoft.ThisWillBeReplaced"; +} + +model ExtensionInstanceParameters { + ...TargetParameters; + ...ExtensionProviderNamespace; + ...KeysOf; +} + +model ExtensionParentParameters { + ...TargetParameters; + ...ExtensionProviderNamespace; + ...ParentKeysOf; +} + +alias ManagementGroupResource = CommonTypes.Extension.ManagementGroup; +alias Subscription = CommonTypes.Extension.SubscriptionTarget; +alias ResourceGroup = CommonTypes.Extension.ResourceGroupTarget; diff --git a/packages/typespec-azure-resource-manager/src/private.decorators.ts b/packages/typespec-azure-resource-manager/src/private.decorators.ts index ca94406371..a944dfc779 100644 --- a/packages/typespec-azure-resource-manager/src/private.decorators.ts +++ b/packages/typespec-azure-resource-manager/src/private.decorators.ts @@ -21,6 +21,10 @@ import { $bodyRoot, getHttpOperation } from "@typespec/http"; import { $segment, getSegment } from "@typespec/rest"; import { camelCase } from "change-case"; import pluralize from "pluralize"; +import { + AzureResourceManagerExtensionPrivateDecorators, + BuiltInResourceDecorator, +} from "../generated-defs/Azure.ResourceManager.Extension.Private.js"; import { ArmBodyRootDecorator, ArmRenameListByOperationDecorator, @@ -44,16 +48,27 @@ import { ArmResourceDetails, ResourceBaseType, getArmResourceKind, + getArmVirtualResourceDetails, getResourceBaseType, isArmVirtualResource, isCustomAzureResource, resolveResourceBaseType, + setResourceBaseType, } from "./resource.js"; import { ArmStateKeys } from "./state.js"; export const namespace = "Azure.ResourceManager.Private"; /** @internal */ + +const $builtInResource: BuiltInResourceDecorator = ( + context: DecoratorContext, + resourceType: Model, +) => { + const { program } = context; + + setResourceBaseType(program, resourceType, ResourceBaseType.BuiltIn); +}; const $omitIfEmpty: OmitIfEmptyDecorator = ( context: DecoratorContext, entity: Model, @@ -332,7 +347,8 @@ export function registerArmResource(context: DecoratorContext, resourceType: Mod // Locate the ARM namespace in the namespace hierarchy const armProviderNamespace = getArmProviderNamespace(program, resourceType.namespace); const armLibraryNamespace = isArmLibraryNamespace(program, resourceType.namespace); - if (!armProviderNamespace && !armLibraryNamespace) { + const armExternalNamespace = getArmVirtualResourceDetails(program, resourceType)?.provider; + if (!armProviderNamespace && !armLibraryNamespace && armExternalNamespace === undefined) { reportDiagnostic(program, { code: "arm-resource-missing-arm-namespace", target: resourceType }); return; } @@ -373,6 +389,7 @@ export function registerArmResource(context: DecoratorContext, resourceType: Mod let kind = getArmResourceKind(resourceType); if (isArmVirtualResource(program, resourceType)) kind = "Virtual"; if (isCustomAzureResource(program, resourceType)) kind = "Custom"; + if (!kind) { reportDiagnostic(program, { code: "arm-resource-invalid-base-type", @@ -388,7 +405,7 @@ export function registerArmResource(context: DecoratorContext, resourceType: Mod typespecType: resourceType, collectionName, keyName, - armProviderNamespace: armProviderNamespace ?? "", + armProviderNamespace: armProviderNamespace ?? armExternalNamespace ?? "", operations: { lifecycle: {}, lists: {}, @@ -509,4 +526,7 @@ export const $decorators = { armResourcePropertiesOptionality: $armResourcePropertiesOptionality, armBodyRoot: $armBodyRoot, } satisfies AzureResourceManagerPrivateDecorators, + "Azure.ResourceManager.Extension.Private": { + builtInResource: $builtInResource, + } satisfies AzureResourceManagerExtensionPrivateDecorators, }; diff --git a/packages/typespec-azure-resource-manager/src/resource.ts b/packages/typespec-azure-resource-manager/src/resource.ts index 6d702e0a5e..81da79c01c 100644 --- a/packages/typespec-azure-resource-manager/src/resource.ts +++ b/packages/typespec-azure-resource-manager/src/resource.ts @@ -60,6 +60,11 @@ export interface ArmResourceDetails extends ArmResourceDetailsBase { resourceTypePath?: string; } +export interface ArmVirtualResourceDetails { + kind: "Virtual"; + provider?: string; +} + /** * Marks the given resource as an external resource * @param context The decorator context @@ -69,10 +74,15 @@ export interface ArmResourceDetails extends ArmResourceDetailsBase { export const $armVirtualResource: ArmVirtualResourceDecorator = ( context: DecoratorContext, entity: Model, + provider: string | undefined = undefined, ) => { const { program } = context; if (isTemplateDeclaration(entity)) return; - program.stateMap(ArmStateKeys.armBuiltInResource).set(entity, "Virtual"); + const result: ArmVirtualResourceDetails = { + kind: "Virtual", + provider, + }; + program.stateMap(ArmStateKeys.armBuiltInResource).set(entity, result); const pathProperty = getProperty( entity, (p) => isPathParam(program, p) && getSegment(program, p) !== undefined, @@ -131,6 +141,27 @@ export function isArmVirtualResource(program: Program, target: Model): boolean { return false; } +/** + * + * @param program The program to process. + * @param target The model to get details for + * @returns The resource details if the model is an external resource, otherwise undefined. + */ +export function getArmVirtualResourceDetails( + program: Program, + target: Model, +): ArmVirtualResourceDetails | undefined { + if (program.stateMap(ArmStateKeys.armBuiltInResource).has(target)) { + return program + .stateMap(ArmStateKeys.armBuiltInResource) + .get(target) as ArmVirtualResourceDetails; + } + if (target.baseModel) { + return getArmVirtualResourceDetails(program, target.baseModel); + } + return undefined; +} + /** * Determine if the given model is a custom resource. * @param program The program to process. @@ -333,6 +364,7 @@ export enum ResourceBaseType { Location = "Location", ResourceGroup = "ResourceGroup", Extension = "Extension", + BuiltIn = "BuiltIn", } export const $resourceBaseType: ResourceBaseTypeDecorator = ( @@ -508,7 +540,7 @@ function getServiceNamespace(program: Program, type: Type | undefined): string | } } -function setResourceBaseType(program: Program, resource: Model, type: string) { +export function setResourceBaseType(program: Program, resource: Model, type: string) { if (program.stateMap(ArmStateKeys.resourceBaseType).has(resource)) { reportDiagnostic(program, { code: "arm-resource-duplicate-base-parameter", From 1cbf84b656748e5ed748f17e335b0df4eadc9697 Mon Sep 17 00:00:00 2001 From: Mark Cowlishaw Date: Mon, 23 Jun 2025 00:12:18 -0700 Subject: [PATCH 03/16] End-to-end sample --- .vscode/launch.json | 20 ++++ .../specific-extension/main.tsp | 110 ++++++++++++++++++ .../generated-defs/Azure.ResourceManager.ts | 48 ++++---- .../commontypes.extension.models.tsp | 12 -- .../lib/common-types/types-ref.tsp | 3 +- .../lib/common-types/types.tsp | 2 + .../lib/extension/operations.tsp | 2 +- .../lib/extension/parameters.tsp | 66 ++++++++--- .../src/namespace.ts | 25 ++-- .../src/private.decorators.ts | 5 +- .../src/resource.ts | 3 + 11 files changed, 232 insertions(+), 64 deletions(-) create mode 100644 packages/samples/specs/resource-manager/resource-types/specific-extension/main.tsp diff --git a/.vscode/launch.json b/.vscode/launch.json index e29626c3ba..e7439ab1f7 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -144,6 +144,26 @@ "order": 2 } }, + { + "type": "node", + "request": "launch", + "name": "Compile Extensions", + "program": "${workspaceRoot}/core/packages/compiler/entrypoints/cli.js", + "args": ["compile", ".", "--emit=@azure-tools/typespec-autorest"], + "smartStep": true, + "sourceMaps": true, + "skipFiles": ["/**/*.js"], + "outFiles": [ + "${workspaceFolder}/packages/*/dist/**/*.js", + "${workspaceFolder}/packages/*/dist-dev/**/*.js", + "${workspaceFolder}/core/packages/*/dist/**/*.js", + "${workspaceFolder}/core/packages/*/dist-dev/**/*.js" + ], + "cwd": "${workspaceRoot}/packages/samples/specs/resource-manager/resource-types/specific-extension", + "presentation": { + "order": 2 + } + }, { "name": "Regenerate .tmlanguage", "type": "node", diff --git a/packages/samples/specs/resource-manager/resource-types/specific-extension/main.tsp b/packages/samples/specs/resource-manager/resource-types/specific-extension/main.tsp new file mode 100644 index 0000000000..a380196a7e --- /dev/null +++ b/packages/samples/specs/resource-manager/resource-types/specific-extension/main.tsp @@ -0,0 +1,110 @@ +import "@typespec/rest"; +import "@typespec/versioning"; +import "@azure-tools/typespec-azure-core"; +import "@azure-tools/typespec-azure-resource-manager"; + +using Http; +using Rest; +using Versioning; +using Azure.Core; +using Azure.ResourceManager; + +/** Contoso Resource Provider management API. */ +@armProviderNamespace +@service(#{ title: "ContosoProviderHubClient" }) +@versioned(Versions) +namespace Microsoft.ContosoProviderHub; + +/** Contoso API versions */ +enum Versions { + /** 2021-10-01-preview version */ + @useDependency(Azure.ResourceManager.Versions.v1_0_Preview_1) + @armCommonTypesVersion(Azure.ResourceManager.CommonTypes.Versions.v5) + `2021-10-01-preview`, +} + +/** A ContosoProviderHub resource */ +model Employee is ExtensionResource { + ...ResourceNameParameter; +} + +/** Employee properties */ +model EmployeeProperties { + /** Age of employee */ + age?: int32; + + /** City of employee */ + city?: string; + + /** Profile of employee */ + @encode("base64url") + profile?: bytes; + + /** The status of the last operation. */ + @visibility(Lifecycle.Read) + provisioningState?: ProvisioningState; +} + +/** The provisioning state of a resource. */ +@lroStatus +union ProvisioningState { + ResourceProvisioningState, + + /** The resource is being provisioned */ + Provisioning: "Provisioning", + + /** The resource is updating */ + Updating: "Updating", + + /** The resource is being deleted */ + Deleting: "Deleting", + + /** The resource create request has been accepted */ + Accepted: "Accepted", + + string, +} + +interface Operations extends Azure.ResourceManager.Operations {} + +interface EmplOps { + get is Extension.Read; + #suppress "@azure-tools/typespec-azure-resource-manager/arm-resource-operation-response" "" + create is Extension.CreateOrReplaceAsync; + update is Extension.CustomPatchSync< + Scope, + Employee, + Azure.ResourceManager.Foundations.ResourceUpdateModel + >; + delete is Extension.DeleteWithoutOkAsync; + list is Extension.ListByTarget; + move is Extension.ActionSync; +} + +model Mg is Extension.ManagementGroup; +@armResourceOperations +interface Employees extends EmplOps {} +@armResourceOperations +interface Tenants extends EmplOps {} +@armResourceOperations +interface Subscriptions extends EmplOps {} +@armResourceOperations +interface ResourceGroups extends EmplOps {} +#suppress "@azure-tools/typespec-azure-resource-manager/arm-resource-operation-response" "" +@armResourceOperations +interface ManagementGroups extends EmplOps {} + +/** Employee move request */ +model MoveRequest { + /** The moving from location */ + from: string; + + /** The moving to location */ + to: string; +} + +/** Employee move response */ +model MoveResponse { + /** The status of the move */ + movingStatus: string; +} diff --git a/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.ts b/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.ts index 793d783ac6..b1b2f5172d 100644 --- a/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.ts +++ b/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.ts @@ -26,28 +26,6 @@ export type ArmResourceCollectionActionDecorator = ( */ export type ArmProviderNameValueDecorator = (context: DecoratorContext, target: Operation) => void; -/** - * `@tenantResource` marks an Azure Resource Manager resource model as a Tenant resource/Root resource/Top-Level resource. - * - * Tenant resources have REST API paths like: - * `/provider/Microsoft.Contoso/FooResources` - * - * See more details on [different Azure Resource Manager resource type here.](https://azure.github.io/typespec-azure/docs/howtos/ARM/resource-type) - */ -export type TenantResourceDecorator = (context: DecoratorContext, target: Model) => void; - -/** - * This decorator is used on Azure Resource Manager resources that are not based on - * Azure.ResourceManager common types. - * - * @param propertiesType : The type of the resource properties. - */ -export type ArmVirtualResourceDecorator = ( - context: DecoratorContext, - target: Model, - provider?: string, -) => void; - /** * `@armProviderNamespace` sets the Azure Resource Manager provider name. It will default to use the * Namespace element value unless an override value is specified. @@ -110,6 +88,16 @@ export type SingletonDecorator = ( keyValue?: string | "default", ) => void; +/** + * `@tenantResource` marks an Azure Resource Manager resource model as a Tenant resource/Root resource/Top-Level resource. + * + * Tenant resources have REST API paths like: + * `/provider/Microsoft.Contoso/FooResources` + * + * See more details on [different Azure Resource Manager resource type here.](https://azure.github.io/typespec-azure/docs/howtos/ARM/resource-type) + */ +export type TenantResourceDecorator = (context: DecoratorContext, target: Model) => void; + /** * `@subscriptionResource` marks an Azure Resource Manager resource model as a subscription resource. * @@ -254,6 +242,18 @@ export type ArmCommonTypesVersionDecorator = ( version: string | EnumValue, ) => void; +/** + * This decorator is used on Azure Resource Manager resources that are not based on + * Azure.ResourceManager common types. + * + * @param propertiesType : The type of the resource properties. + */ +export type ArmVirtualResourceDecorator = ( + context: DecoratorContext, + target: Model, + provider?: string, +) => void; + /** * This decorator sets the base type of the given resource. * @@ -287,12 +287,11 @@ export type IdentifiersDecorator = ( export type AzureResourceManagerDecorators = { armResourceCollectionAction: ArmResourceCollectionActionDecorator; armProviderNameValue: ArmProviderNameValueDecorator; - tenantResource: TenantResourceDecorator; - armVirtualResource: ArmVirtualResourceDecorator; armProviderNamespace: ArmProviderNamespaceDecorator; useLibraryNamespace: UseLibraryNamespaceDecorator; armLibraryNamespace: ArmLibraryNamespaceDecorator; singleton: SingletonDecorator; + tenantResource: TenantResourceDecorator; subscriptionResource: SubscriptionResourceDecorator; locationResource: LocationResourceDecorator; resourceGroupResource: ResourceGroupResourceDecorator; @@ -305,6 +304,7 @@ export type AzureResourceManagerDecorators = { armResourceList: ArmResourceListDecorator; armResourceOperations: ArmResourceOperationsDecorator; armCommonTypesVersion: ArmCommonTypesVersionDecorator; + armVirtualResource: ArmVirtualResourceDecorator; resourceBaseType: ResourceBaseTypeDecorator; identifiers: IdentifiersDecorator; }; diff --git a/packages/typespec-azure-resource-manager/lib/common-types/commontypes.extension.models.tsp b/packages/typespec-azure-resource-manager/lib/common-types/commontypes.extension.models.tsp index 64ea0c3650..dfa68a7c5e 100644 --- a/packages/typespec-azure-resource-manager/lib/common-types/commontypes.extension.models.tsp +++ b/packages/typespec-azure-resource-manager/lib/common-types/commontypes.extension.models.tsp @@ -13,15 +13,3 @@ model ResourceGroupTarget is ResourceGroupParameter; @builtInResource model SubscriptionTarget is SubscriptionIdParameter; - -/** Represents a management group */ -@tenantResource -@armVirtualResource("Microsoft.Management") -model ManagementGroup { - @path - @minLength(1) - @segment("managementGroups") - @key - @doc("The management group ID.") - managementGroupName: string; -} diff --git a/packages/typespec-azure-resource-manager/lib/common-types/types-ref.tsp b/packages/typespec-azure-resource-manager/lib/common-types/types-ref.tsp index 455b00e80f..f3ae0aca16 100644 --- a/packages/typespec-azure-resource-manager/lib/common-types/types-ref.tsp +++ b/packages/typespec-azure-resource-manager/lib/common-types/types-ref.tsp @@ -376,7 +376,8 @@ namespace Azure.ResourceManager.CommonTypes; ResourceHome.Subscription, ResourceHome.Location, ResourceHome.Tenant, - ResourceHome.Extension + ResourceHome.Extension, + ResourceHome.BuiltIn ] ); diff --git a/packages/typespec-azure-resource-manager/lib/common-types/types.tsp b/packages/typespec-azure-resource-manager/lib/common-types/types.tsp index 08c8592826..2b0539eccc 100644 --- a/packages/typespec-azure-resource-manager/lib/common-types/types.tsp +++ b/packages/typespec-azure-resource-manager/lib/common-types/types.tsp @@ -524,6 +524,7 @@ model LocationParameter { */ model ResourceGroupNameParameter { /** The name of the resource group. The name is case insensitive. */ + @key @path @minLength(1) @maxLength(90) @@ -541,6 +542,7 @@ model SubscriptionIdParameter { @path @segment("subscriptions") @minLength(1) + @key subscriptionId: uuid; } diff --git a/packages/typespec-azure-resource-manager/lib/extension/operations.tsp b/packages/typespec-azure-resource-manager/lib/extension/operations.tsp index b578bdf306..00431ad9ed 100644 --- a/packages/typespec-azure-resource-manager/lib/extension/operations.tsp +++ b/packages/typespec-azure-resource-manager/lib/extension/operations.tsp @@ -304,7 +304,7 @@ op DeleteAsync< */ @enforceConstraint(TargetResource, Foundations.Resource) @enforceConstraint(ExtensionResource, Foundations.Resource) -op ArmResourceDeleteWithoutOkAsync< +op DeleteWithoutOkAsync< TargetResource extends Foundations.SimpleResource, ExtensionResource extends Foundations.SimpleResource, LroHeaders extends TypeSpec.Reflection.Model = ArmLroLocationHeader & diff --git a/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp b/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp index 4d830e6433..5a93ff9a2b 100644 --- a/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp +++ b/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp @@ -1,12 +1,10 @@ +namespace Azure.ResourceManager.Extension; + using Http; using Rest; -using Azure.Core; -using Azure.ResourceManager; using Azure.ResourceManager.Private; -using Azure.ResourceManager.Foundations; using Azure.ResourceManager.Extension.Private; - -namespace Azure.ResourceManager.Extension; +using Azure.ResourceManager.CommonTypes; /** * The default scope parameter type. @@ -18,12 +16,13 @@ namespace Azure.ResourceManager.Extension; * } * ``` */ -@doc("The default resourceUri parameter type.") +@doc("The default scope parameter type.") @builtInResource -model ScopeParameter { +model ScopeParameter { @path(#{ allowReserved: true }) + @key @doc("The fully qualified Azure Resource manager identifier of the resource.") - scope: Type; + scope: string; } /** * Base parameters for a resource. @@ -33,32 +32,52 @@ model ScopeParameter { model TargetBaseParameters { ...ApiVersionParameter; - // unless tenant or extension + // unless built-in, tenant or extension ...CommonTypes.SubscriptionIdParameter; - // unless tenant, subscription, location, or extension + // unless built-in tenant, subscription, location, or extension ...CommonTypes.ResourceGroupNameParameter; + + // unless built-in + ...TargetProviderNamespace; } model TargetParameters { ...TargetBaseParameters; - ...ProviderNamespace; ...KeysOf; } -model ExtensionProviderNamespace { +model ExtensionProviderNamespace { @path @segment("providers") @key - @assignProviderNameValue(ExtensionResource) + @assignProviderNameValue(Resource) @doc("The provider namespace for the resource.") extensionProvider: "Microsoft.ThisWillBeReplaced"; } -model ExtensionInstanceParameters { +model TargetProviderNamespace { + @resourceParameterBaseFor( + [ + ResourceHome.Extension, + ResourceHome.Location, + ResourceHome.ResourceGroup, + ResourceHome.Subscription, + ResourceHome.Tenant + ] + ) + @path + @segment("provider") + @key + @doc("The provider namespace for the resource.") + @assignProviderNameValue(Resource) + provider: "Microsoft.ThisWillBeReplaced"; +} + +model ExtensionInstanceParameters { ...TargetParameters; - ...ExtensionProviderNamespace; - ...KeysOf; + ...ExtensionProviderNamespace; + ...KeysOf; } model ExtensionParentParameters { @@ -67,6 +86,19 @@ model ExtensionParentParameters; } -alias ManagementGroupResource = CommonTypes.Extension.ManagementGroup; +@builtInResource +model Tenant {} +/** Represents a management group */ +@tenantResource +@armVirtualResource("Microsoft.Management") +model ManagementGroup { + @path + @minLength(1) + @segment("managementGroups") + @key("managementGroupName") + @doc("The management group ID.") + name: string; +} + alias Subscription = CommonTypes.Extension.SubscriptionTarget; alias ResourceGroup = CommonTypes.Extension.ResourceGroupTarget; diff --git a/packages/typespec-azure-resource-manager/src/namespace.ts b/packages/typespec-azure-resource-manager/src/namespace.ts index 9e40336e57..d787b716a7 100644 --- a/packages/typespec-azure-resource-manager/src/namespace.ts +++ b/packages/typespec-azure-resource-manager/src/namespace.ts @@ -23,7 +23,7 @@ import { } from "../generated-defs/Azure.ResourceManager.js"; import { $armCommonTypesVersion } from "./common-types.js"; import { reportDiagnostic } from "./lib.js"; -import { getSingletonResourceKey } from "./resource.js"; +import { getArmVirtualResourceDetails, getSingletonResourceKey } from "./resource.js"; import { ArmStateKeys } from "./state.js"; function getArmCommonTypesVersion( @@ -271,19 +271,30 @@ export function getArmProviderNamespace( program: Program, entity: Namespace | Model, ): string | undefined { - let currentNamespace: Namespace | undefined = + if (entity.kind === "Model") { + const details = getArmVirtualResourceDetails(program, entity); + if (details?.provider !== undefined) { + return details.provider; + } + } + + const currentNamespace: Namespace | undefined = entity.kind === "Namespace" ? entity : entity.namespace; + return getArmProviderFromNamespace(program, currentNamespace); +} +function getArmProviderFromNamespace( + program: Program, + ns: Namespace | undefined, +): string | undefined { let armProviderNamespace: string | undefined; - while (currentNamespace) { - armProviderNamespace = program - .stateMap(ArmStateKeys.armProviderNamespaces) - .get(currentNamespace); + while (ns) { + armProviderNamespace = program.stateMap(ArmStateKeys.armProviderNamespaces).get(ns); if (armProviderNamespace) { return armProviderNamespace; } - currentNamespace = currentNamespace.namespace; + ns = ns.namespace; } return undefined; diff --git a/packages/typespec-azure-resource-manager/src/private.decorators.ts b/packages/typespec-azure-resource-manager/src/private.decorators.ts index a944dfc779..749738f231 100644 --- a/packages/typespec-azure-resource-manager/src/private.decorators.ts +++ b/packages/typespec-azure-resource-manager/src/private.decorators.ts @@ -100,7 +100,7 @@ function checkAllowedVirtualResource( case "delete": return true; default: - return false; + return true; } } @@ -117,6 +117,7 @@ const $enforceConstraint: EnforceConstraintDecorator = ( if ( baseType === constraintType || isCustomAzureResource(context.program, baseType) || + getResourceBaseType(context.program, baseType) === ResourceBaseType.BuiltIn || checkAllowedVirtualResource(context.program, entity, baseType) ) return; @@ -345,7 +346,7 @@ export function registerArmResource(context: DecoratorContext, resourceType: Mod } // Locate the ARM namespace in the namespace hierarchy - const armProviderNamespace = getArmProviderNamespace(program, resourceType.namespace); + const armProviderNamespace = getArmProviderNamespace(program, resourceType); const armLibraryNamespace = isArmLibraryNamespace(program, resourceType.namespace); const armExternalNamespace = getArmVirtualResourceDetails(program, resourceType)?.provider; if (!armProviderNamespace && !armLibraryNamespace && armExternalNamespace === undefined) { diff --git a/packages/typespec-azure-resource-manager/src/resource.ts b/packages/typespec-azure-resource-manager/src/resource.ts index 81da79c01c..a0674d87ad 100644 --- a/packages/typespec-azure-resource-manager/src/resource.ts +++ b/packages/typespec-azure-resource-manager/src/resource.ts @@ -586,6 +586,9 @@ export function resolveResourceBaseType(type?: string | undefined): ResourceBase case "Extension": resolvedType = ResourceBaseType.Extension; break; + case "BuiltIn": + resolvedType = ResourceBaseType.BuiltIn; + break; } } return resolvedType; From ccbd4b8b34dd87f3123e6b5f3c7a330d5bf4d856 Mon Sep 17 00:00:00 2001 From: Mark Cowlishaw Date: Mon, 23 Jun 2025 15:42:43 -0700 Subject: [PATCH 04/16] Adding sample --- .../specific-extension/main.tsp | 26 +- .../2021-10-01-preview/openapi.json | 2115 +++++++++++++++++ ...Azure.ResourceManager.Extension.Private.ts | 24 +- .../lib/common-types/common-types.tsp | 1 - .../commontypes.extension.models.tsp | 15 - .../lib/common-types/internal.tsp | 6 + .../lib/common-types/types-ref.tsp | 14 +- .../lib/common-types/types.tsp | 2 - .../lib/extension/operations.tsp | 62 +- .../lib/extension/parameters.tsp | 58 +- .../lib/extension/private.decorators.tsp | 16 +- .../src/private.decorators.ts | 44 +- .../src/resource.ts | 8 + 13 files changed, 2325 insertions(+), 66 deletions(-) create mode 100644 packages/samples/test/output/azure/resource-manager/resource-types/specific-extension/@azure-tools/typespec-autorest/2021-10-01-preview/openapi.json delete mode 100644 packages/typespec-azure-resource-manager/lib/common-types/commontypes.extension.models.tsp diff --git a/packages/samples/specs/resource-manager/resource-types/specific-extension/main.tsp b/packages/samples/specs/resource-manager/resource-types/specific-extension/main.tsp index a380196a7e..0aec655779 100644 --- a/packages/samples/specs/resource-manager/resource-types/specific-extension/main.tsp +++ b/packages/samples/specs/resource-manager/resource-types/specific-extension/main.tsp @@ -67,21 +67,27 @@ union ProvisioningState { interface Operations extends Azure.ResourceManager.Operations {} -interface EmplOps { - get is Extension.Read; +interface EmplOps< + Scope extends Azure.ResourceManager.Foundations.SimpleResource, + Provider extends string = "" +> { + get is Extension.Read; #suppress "@azure-tools/typespec-azure-resource-manager/arm-resource-operation-response" "" - create is Extension.CreateOrReplaceAsync; + create is Extension.CreateOrReplaceAsync; update is Extension.CustomPatchSync< Scope, + Provider, Employee, Azure.ResourceManager.Foundations.ResourceUpdateModel >; - delete is Extension.DeleteWithoutOkAsync; - list is Extension.ListByTarget; - move is Extension.ActionSync; + delete is Extension.DeleteWithoutOkAsync; + list is Extension.ListByTarget; + move is Extension.ActionSync; } -model Mg is Extension.ManagementGroup; +/** Virtual resource for a virtual machine */ +alias VirtualMachine = Extension.ExternalResource<"Microsoft.Compute", "virtualMachines", "vmName">; + @armResourceOperations interface Employees extends EmplOps {} @armResourceOperations @@ -90,9 +96,11 @@ interface Tenants extends EmplOps {} interface Subscriptions extends EmplOps {} @armResourceOperations interface ResourceGroups extends EmplOps {} -#suppress "@azure-tools/typespec-azure-resource-manager/arm-resource-operation-response" "" @armResourceOperations -interface ManagementGroups extends EmplOps {} +interface ManagementGroups extends EmplOps {} +#suppress "@azure-tools/typespec-azure-resource-manager/improper-subscription-list-operation" "" +@armResourceOperations +interface VirtualMachines extends EmplOps {} /** Employee move request */ model MoveRequest { diff --git a/packages/samples/test/output/azure/resource-manager/resource-types/specific-extension/@azure-tools/typespec-autorest/2021-10-01-preview/openapi.json b/packages/samples/test/output/azure/resource-manager/resource-types/specific-extension/@azure-tools/typespec-autorest/2021-10-01-preview/openapi.json new file mode 100644 index 0000000000..5aea1cc6f4 --- /dev/null +++ b/packages/samples/test/output/azure/resource-manager/resource-types/specific-extension/@azure-tools/typespec-autorest/2021-10-01-preview/openapi.json @@ -0,0 +1,2115 @@ +{ + "swagger": "2.0", + "info": { + "title": "ContosoProviderHubClient", + "version": "2021-10-01-preview", + "description": "Contoso Resource Provider management API.", + "x-typespec-generated": [ + { + "emitter": "@azure-tools/typespec-autorest" + } + ] + }, + "schemes": [ + "https" + ], + "host": "management.azure.com", + "produces": [ + "application/json" + ], + "consumes": [ + "application/json" + ], + "security": [ + { + "azure_auth": [ + "user_impersonation" + ] + } + ], + "securityDefinitions": { + "azure_auth": { + "type": "oauth2", + "description": "Azure Active Directory OAuth2 Flow.", + "flow": "implicit", + "authorizationUrl": "https://login.microsoftonline.com/common/oauth2/authorize", + "scopes": { + "user_impersonation": "impersonate your user account" + } + } + }, + "tags": [ + { + "name": "Operations" + }, + { + "name": "Employees" + }, + { + "name": "Tenants" + }, + { + "name": "Subscriptions" + }, + { + "name": "ResourceGroups" + }, + { + "name": "ManagementGroups" + }, + { + "name": "VirtualMachines" + } + ], + "paths": { + "/{scope}/providers/Microsoft.ContosoProviderHub/employees": { + "get": { + "operationId": "Employees_List", + "tags": [ + "Employees" + ], + "description": "List Employee resources by subscription ID", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "scope", + "in": "path", + "description": "The fully qualified Azure Resource manager identifier of the resource.", + "required": true, + "type": "string", + "x-ms-skip-url-encoding": true + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/EmployeeListResult" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "nextLink" + } + } + }, + "/{scope}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}": { + "get": { + "operationId": "Employees_Get", + "tags": [ + "Employees" + ], + "description": "Get a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "scope", + "in": "path", + "description": "The fully qualified Azure Resource manager identifier of the resource.", + "required": true, + "type": "string", + "x-ms-skip-url-encoding": true + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + }, + "put": { + "operationId": "Employees_Create", + "tags": [ + "Employees" + ], + "description": "Create a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "scope", + "in": "path", + "description": "The fully qualified Azure Resource manager identifier of the resource.", + "required": true, + "type": "string", + "x-ms-skip-url-encoding": true + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "resource", + "in": "body", + "description": "Resource create parameters.", + "required": true, + "schema": { + "$ref": "#/definitions/Employee" + } + } + ], + "responses": { + "200": { + "description": "Resource 'Employee' update operation succeeded", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "201": { + "description": "Resource 'Employee' create operation succeeded", + "schema": { + "$ref": "#/definitions/Employee" + }, + "headers": { + "Azure-AsyncOperation": { + "type": "string", + "description": "A link to the status monitor" + }, + "Retry-After": { + "type": "integer", + "format": "int32", + "description": "The Retry-After header can indicate how long the client should wait before polling the operation status." + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-long-running-operation-options": { + "final-state-via": "azure-async-operation" + }, + "x-ms-long-running-operation": true + }, + "patch": { + "operationId": "Employees_Update", + "tags": [ + "Employees" + ], + "description": "Update a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "scope", + "in": "path", + "description": "The fully qualified Azure Resource manager identifier of the resource.", + "required": true, + "type": "string", + "x-ms-skip-url-encoding": true + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "properties", + "in": "body", + "description": "The resource properties to be updated.", + "required": true, + "schema": { + "$ref": "#/definitions/EmployeeUpdate" + } + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + }, + "delete": { + "operationId": "Employees_Delete", + "tags": [ + "Employees" + ], + "description": "Delete a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "scope", + "in": "path", + "description": "The fully qualified Azure Resource manager identifier of the resource.", + "required": true, + "type": "string", + "x-ms-skip-url-encoding": true + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + } + ], + "responses": { + "202": { + "description": "Resource deletion accepted.", + "headers": { + "Location": { + "type": "string", + "description": "The Location header contains the URL where the status of the long running operation can be checked." + }, + "Retry-After": { + "type": "integer", + "format": "int32", + "description": "The Retry-After header can indicate how long the client should wait before polling the operation status." + } + } + }, + "204": { + "description": "Resource does not exist." + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-long-running-operation-options": { + "final-state-via": "location" + }, + "x-ms-long-running-operation": true + } + }, + "/{scope}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}/move": { + "post": { + "operationId": "Employees_Move", + "tags": [ + "Employees" + ], + "description": "A synchronous resource action.", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "scope", + "in": "path", + "description": "The fully qualified Azure Resource manager identifier of the resource.", + "required": true, + "type": "string", + "x-ms-skip-url-encoding": true + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "body", + "in": "body", + "description": "The content of the action request", + "required": true, + "schema": { + "$ref": "#/definitions/MoveRequest" + } + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/MoveResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + } + }, + "/providers/Microsoft.ContosoProviderHub/employees": { + "get": { + "operationId": "Tenants_List", + "tags": [ + "Tenants" + ], + "description": "List Employee resources by subscription ID", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/EmployeeListResult" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "nextLink" + } + } + }, + "/providers/Microsoft.ContosoProviderHub/employees/{employeeName}": { + "get": { + "operationId": "Tenants_Get", + "tags": [ + "Tenants" + ], + "description": "Get a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + }, + "put": { + "operationId": "Tenants_Create", + "tags": [ + "Tenants" + ], + "description": "Create a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "resource", + "in": "body", + "description": "Resource create parameters.", + "required": true, + "schema": { + "$ref": "#/definitions/Employee" + } + } + ], + "responses": { + "200": { + "description": "Resource 'Employee' update operation succeeded", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "201": { + "description": "Resource 'Employee' create operation succeeded", + "schema": { + "$ref": "#/definitions/Employee" + }, + "headers": { + "Azure-AsyncOperation": { + "type": "string", + "description": "A link to the status monitor" + }, + "Retry-After": { + "type": "integer", + "format": "int32", + "description": "The Retry-After header can indicate how long the client should wait before polling the operation status." + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-long-running-operation-options": { + "final-state-via": "azure-async-operation" + }, + "x-ms-long-running-operation": true + }, + "patch": { + "operationId": "Tenants_Update", + "tags": [ + "Tenants" + ], + "description": "Update a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "properties", + "in": "body", + "description": "The resource properties to be updated.", + "required": true, + "schema": { + "$ref": "#/definitions/EmployeeUpdate" + } + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + }, + "delete": { + "operationId": "Tenants_Delete", + "tags": [ + "Tenants" + ], + "description": "Delete a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + } + ], + "responses": { + "202": { + "description": "Resource deletion accepted.", + "headers": { + "Location": { + "type": "string", + "description": "The Location header contains the URL where the status of the long running operation can be checked." + }, + "Retry-After": { + "type": "integer", + "format": "int32", + "description": "The Retry-After header can indicate how long the client should wait before polling the operation status." + } + } + }, + "204": { + "description": "Resource does not exist." + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-long-running-operation-options": { + "final-state-via": "location" + }, + "x-ms-long-running-operation": true + } + }, + "/providers/Microsoft.ContosoProviderHub/employees/{employeeName}/move": { + "post": { + "operationId": "Tenants_Move", + "tags": [ + "Tenants" + ], + "description": "A synchronous resource action.", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "body", + "in": "body", + "description": "The content of the action request", + "required": true, + "schema": { + "$ref": "#/definitions/MoveRequest" + } + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/MoveResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + } + }, + "/providers/Microsoft.ContosoProviderHub/operations": { + "get": { + "operationId": "Operations_List", + "tags": [ + "Operations" + ], + "description": "List the operations for the provider", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/OperationListResult" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "nextLink" + } + } + }, + "/providers/Microsoft.Management/managementGroups/{managementGroupName}/providers/Microsoft.ContosoProviderHub/employees": { + "get": { + "operationId": "ManagementGroups_List", + "tags": [ + "ManagementGroups" + ], + "description": "List Employee resources by subscription ID", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "managementGroupName", + "in": "path", + "description": "The management group ID.", + "required": true, + "type": "string", + "minLength": 1 + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/EmployeeListResult" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "nextLink" + } + } + }, + "/providers/Microsoft.Management/managementGroups/{managementGroupName}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}": { + "get": { + "operationId": "ManagementGroups_Get", + "tags": [ + "ManagementGroups" + ], + "description": "Get a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "managementGroupName", + "in": "path", + "description": "The management group ID.", + "required": true, + "type": "string", + "minLength": 1 + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + }, + "put": { + "operationId": "ManagementGroups_Create", + "tags": [ + "ManagementGroups" + ], + "description": "Create a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "managementGroupName", + "in": "path", + "description": "The management group ID.", + "required": true, + "type": "string", + "minLength": 1 + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "resource", + "in": "body", + "description": "Resource create parameters.", + "required": true, + "schema": { + "$ref": "#/definitions/Employee" + } + } + ], + "responses": { + "200": { + "description": "Resource 'Employee' update operation succeeded", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "201": { + "description": "Resource 'Employee' create operation succeeded", + "schema": { + "$ref": "#/definitions/Employee" + }, + "headers": { + "Azure-AsyncOperation": { + "type": "string", + "description": "A link to the status monitor" + }, + "Retry-After": { + "type": "integer", + "format": "int32", + "description": "The Retry-After header can indicate how long the client should wait before polling the operation status." + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-long-running-operation-options": { + "final-state-via": "azure-async-operation" + }, + "x-ms-long-running-operation": true + }, + "patch": { + "operationId": "ManagementGroups_Update", + "tags": [ + "ManagementGroups" + ], + "description": "Update a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "managementGroupName", + "in": "path", + "description": "The management group ID.", + "required": true, + "type": "string", + "minLength": 1 + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "properties", + "in": "body", + "description": "The resource properties to be updated.", + "required": true, + "schema": { + "$ref": "#/definitions/EmployeeUpdate" + } + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + }, + "delete": { + "operationId": "ManagementGroups_Delete", + "tags": [ + "ManagementGroups" + ], + "description": "Delete a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "managementGroupName", + "in": "path", + "description": "The management group ID.", + "required": true, + "type": "string", + "minLength": 1 + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + } + ], + "responses": { + "202": { + "description": "Resource deletion accepted.", + "headers": { + "Location": { + "type": "string", + "description": "The Location header contains the URL where the status of the long running operation can be checked." + }, + "Retry-After": { + "type": "integer", + "format": "int32", + "description": "The Retry-After header can indicate how long the client should wait before polling the operation status." + } + } + }, + "204": { + "description": "Resource does not exist." + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-long-running-operation-options": { + "final-state-via": "location" + }, + "x-ms-long-running-operation": true + } + }, + "/providers/Microsoft.Management/managementGroups/{managementGroupName}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}/move": { + "post": { + "operationId": "ManagementGroups_Move", + "tags": [ + "ManagementGroups" + ], + "description": "A synchronous resource action.", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "managementGroupName", + "in": "path", + "description": "The management group ID.", + "required": true, + "type": "string", + "minLength": 1 + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "body", + "in": "body", + "description": "The content of the action request", + "required": true, + "schema": { + "$ref": "#/definitions/MoveRequest" + } + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/MoveResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + } + }, + "/subscriptions/{subscriptionId}/providers/Microsoft.ContosoProviderHub/employees": { + "get": { + "operationId": "Subscriptions_List", + "tags": [ + "Subscriptions" + ], + "description": "List Employee resources by subscription ID", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/EmployeeListResult" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "nextLink" + } + } + }, + "/subscriptions/{subscriptionId}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}": { + "get": { + "operationId": "Subscriptions_Get", + "tags": [ + "Subscriptions" + ], + "description": "Get a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + }, + "put": { + "operationId": "Subscriptions_Create", + "tags": [ + "Subscriptions" + ], + "description": "Create a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "resource", + "in": "body", + "description": "Resource create parameters.", + "required": true, + "schema": { + "$ref": "#/definitions/Employee" + } + } + ], + "responses": { + "200": { + "description": "Resource 'Employee' update operation succeeded", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "201": { + "description": "Resource 'Employee' create operation succeeded", + "schema": { + "$ref": "#/definitions/Employee" + }, + "headers": { + "Azure-AsyncOperation": { + "type": "string", + "description": "A link to the status monitor" + }, + "Retry-After": { + "type": "integer", + "format": "int32", + "description": "The Retry-After header can indicate how long the client should wait before polling the operation status." + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-long-running-operation-options": { + "final-state-via": "azure-async-operation" + }, + "x-ms-long-running-operation": true + }, + "patch": { + "operationId": "Subscriptions_Update", + "tags": [ + "Subscriptions" + ], + "description": "Update a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "properties", + "in": "body", + "description": "The resource properties to be updated.", + "required": true, + "schema": { + "$ref": "#/definitions/EmployeeUpdate" + } + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + }, + "delete": { + "operationId": "Subscriptions_Delete", + "tags": [ + "Subscriptions" + ], + "description": "Delete a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + } + ], + "responses": { + "202": { + "description": "Resource deletion accepted.", + "headers": { + "Location": { + "type": "string", + "description": "The Location header contains the URL where the status of the long running operation can be checked." + }, + "Retry-After": { + "type": "integer", + "format": "int32", + "description": "The Retry-After header can indicate how long the client should wait before polling the operation status." + } + } + }, + "204": { + "description": "Resource does not exist." + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-long-running-operation-options": { + "final-state-via": "location" + }, + "x-ms-long-running-operation": true + } + }, + "/subscriptions/{subscriptionId}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}/move": { + "post": { + "operationId": "Subscriptions_Move", + "tags": [ + "Subscriptions" + ], + "description": "A synchronous resource action.", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "body", + "in": "body", + "description": "The content of the action request", + "required": true, + "schema": { + "$ref": "#/definitions/MoveRequest" + } + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/MoveResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + } + }, + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/virtualMachines/{vmName}/providers/Microsoft.ContosoProviderHub/employees": { + "get": { + "operationId": "VirtualMachines_List", + "tags": [ + "VirtualMachines" + ], + "description": "List Employee resources by subscription ID", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "vmName", + "in": "path", + "description": "The name of the virtual machine", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/EmployeeListResult" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "nextLink" + } + } + }, + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/virtualMachines/{vmName}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}": { + "get": { + "operationId": "VirtualMachines_Get", + "tags": [ + "VirtualMachines" + ], + "description": "Get a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "vmName", + "in": "path", + "description": "The name of the virtual machine", + "required": true, + "type": "string" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + }, + "put": { + "operationId": "VirtualMachines_Create", + "tags": [ + "VirtualMachines" + ], + "description": "Create a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "vmName", + "in": "path", + "description": "The name of the virtual machine", + "required": true, + "type": "string" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "resource", + "in": "body", + "description": "Resource create parameters.", + "required": true, + "schema": { + "$ref": "#/definitions/Employee" + } + } + ], + "responses": { + "200": { + "description": "Resource 'Employee' update operation succeeded", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "201": { + "description": "Resource 'Employee' create operation succeeded", + "schema": { + "$ref": "#/definitions/Employee" + }, + "headers": { + "Azure-AsyncOperation": { + "type": "string", + "description": "A link to the status monitor" + }, + "Retry-After": { + "type": "integer", + "format": "int32", + "description": "The Retry-After header can indicate how long the client should wait before polling the operation status." + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-long-running-operation-options": { + "final-state-via": "azure-async-operation" + }, + "x-ms-long-running-operation": true + }, + "patch": { + "operationId": "VirtualMachines_Update", + "tags": [ + "VirtualMachines" + ], + "description": "Update a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "vmName", + "in": "path", + "description": "The name of the virtual machine", + "required": true, + "type": "string" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "properties", + "in": "body", + "description": "The resource properties to be updated.", + "required": true, + "schema": { + "$ref": "#/definitions/EmployeeUpdate" + } + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + }, + "delete": { + "operationId": "VirtualMachines_Delete", + "tags": [ + "VirtualMachines" + ], + "description": "Delete a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "vmName", + "in": "path", + "description": "The name of the virtual machine", + "required": true, + "type": "string" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + } + ], + "responses": { + "202": { + "description": "Resource deletion accepted.", + "headers": { + "Location": { + "type": "string", + "description": "The Location header contains the URL where the status of the long running operation can be checked." + }, + "Retry-After": { + "type": "integer", + "format": "int32", + "description": "The Retry-After header can indicate how long the client should wait before polling the operation status." + } + } + }, + "204": { + "description": "Resource does not exist." + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-long-running-operation-options": { + "final-state-via": "location" + }, + "x-ms-long-running-operation": true + } + }, + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/virtualMachines/{vmName}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}/move": { + "post": { + "operationId": "VirtualMachines_Move", + "tags": [ + "VirtualMachines" + ], + "description": "A synchronous resource action.", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "vmName", + "in": "path", + "description": "The name of the virtual machine", + "required": true, + "type": "string" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "body", + "in": "body", + "description": "The content of the action request", + "required": true, + "schema": { + "$ref": "#/definitions/MoveRequest" + } + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/MoveResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + } + }, + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ContosoProviderHub/employees": { + "get": { + "operationId": "ResourceGroups_List", + "tags": [ + "ResourceGroups" + ], + "description": "List Employee resources by subscription ID", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/EmployeeListResult" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "nextLink" + } + } + }, + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}": { + "get": { + "operationId": "ResourceGroups_Get", + "tags": [ + "ResourceGroups" + ], + "description": "Get a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + }, + "put": { + "operationId": "ResourceGroups_Create", + "tags": [ + "ResourceGroups" + ], + "description": "Create a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "resource", + "in": "body", + "description": "Resource create parameters.", + "required": true, + "schema": { + "$ref": "#/definitions/Employee" + } + } + ], + "responses": { + "200": { + "description": "Resource 'Employee' update operation succeeded", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "201": { + "description": "Resource 'Employee' create operation succeeded", + "schema": { + "$ref": "#/definitions/Employee" + }, + "headers": { + "Azure-AsyncOperation": { + "type": "string", + "description": "A link to the status monitor" + }, + "Retry-After": { + "type": "integer", + "format": "int32", + "description": "The Retry-After header can indicate how long the client should wait before polling the operation status." + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-long-running-operation-options": { + "final-state-via": "azure-async-operation" + }, + "x-ms-long-running-operation": true + }, + "patch": { + "operationId": "ResourceGroups_Update", + "tags": [ + "ResourceGroups" + ], + "description": "Update a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "properties", + "in": "body", + "description": "The resource properties to be updated.", + "required": true, + "schema": { + "$ref": "#/definitions/EmployeeUpdate" + } + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + }, + "delete": { + "operationId": "ResourceGroups_Delete", + "tags": [ + "ResourceGroups" + ], + "description": "Delete a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + } + ], + "responses": { + "202": { + "description": "Resource deletion accepted.", + "headers": { + "Location": { + "type": "string", + "description": "The Location header contains the URL where the status of the long running operation can be checked." + }, + "Retry-After": { + "type": "integer", + "format": "int32", + "description": "The Retry-After header can indicate how long the client should wait before polling the operation status." + } + } + }, + "204": { + "description": "Resource does not exist." + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-long-running-operation-options": { + "final-state-via": "location" + }, + "x-ms-long-running-operation": true + } + }, + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}/move": { + "post": { + "operationId": "ResourceGroups_Move", + "tags": [ + "ResourceGroups" + ], + "description": "A synchronous resource action.", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "body", + "in": "body", + "description": "The content of the action request", + "required": true, + "schema": { + "$ref": "#/definitions/MoveRequest" + } + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/MoveResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + } + } + }, + "definitions": { + "Employee": { + "type": "object", + "description": "A ContosoProviderHub resource", + "properties": { + "properties": { + "$ref": "#/definitions/EmployeeProperties", + "description": "The resource-specific properties for this resource.", + "x-ms-client-flatten": true + } + }, + "allOf": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ProxyResource" + } + ] + }, + "EmployeeListResult": { + "type": "object", + "description": "The response of a Employee list operation.", + "properties": { + "value": { + "type": "array", + "description": "The Employee items on this page", + "items": { + "$ref": "#/definitions/Employee" + } + }, + "nextLink": { + "type": "string", + "format": "uri", + "description": "The link to the next page of items" + } + }, + "required": [ + "value" + ] + }, + "EmployeeProperties": { + "type": "object", + "description": "Employee properties", + "properties": { + "age": { + "type": "integer", + "format": "int32", + "description": "Age of employee" + }, + "city": { + "type": "string", + "description": "City of employee" + }, + "profile": { + "type": "string", + "format": "base64url", + "description": "Profile of employee" + }, + "provisioningState": { + "$ref": "#/definitions/ProvisioningState", + "description": "The status of the last operation.", + "readOnly": true + } + } + }, + "EmployeeUpdate": { + "type": "object", + "description": "The type used for update operations of the Employee.", + "properties": { + "properties": { + "$ref": "#/definitions/EmployeeUpdateProperties", + "description": "The resource-specific properties for this resource.", + "x-ms-client-flatten": true + } + } + }, + "EmployeeUpdateProperties": { + "type": "object", + "description": "The updatable properties of the Employee.", + "properties": { + "age": { + "type": "integer", + "format": "int32", + "description": "Age of employee" + }, + "city": { + "type": "string", + "description": "City of employee" + }, + "profile": { + "type": "string", + "format": "base64url", + "description": "Profile of employee" + } + } + }, + "MoveRequest": { + "type": "object", + "description": "Employee move request", + "properties": { + "from": { + "type": "string", + "description": "The moving from location" + }, + "to": { + "type": "string", + "description": "The moving to location" + } + }, + "required": [ + "from", + "to" + ] + }, + "MoveResponse": { + "type": "object", + "description": "Employee move response", + "properties": { + "movingStatus": { + "type": "string", + "description": "The status of the move" + } + }, + "required": [ + "movingStatus" + ] + }, + "ProvisioningState": { + "type": "string", + "description": "The provisioning state of a resource.", + "enum": [ + "Succeeded", + "Failed", + "Canceled", + "Provisioning", + "Updating", + "Deleting", + "Accepted" + ], + "x-ms-enum": { + "name": "ProvisioningState", + "modelAsString": true, + "values": [ + { + "name": "Succeeded", + "value": "Succeeded", + "description": "Resource has been created." + }, + { + "name": "Failed", + "value": "Failed", + "description": "Resource creation failed." + }, + { + "name": "Canceled", + "value": "Canceled", + "description": "Resource creation was canceled." + }, + { + "name": "Provisioning", + "value": "Provisioning", + "description": "The resource is being provisioned" + }, + { + "name": "Updating", + "value": "Updating", + "description": "The resource is updating" + }, + { + "name": "Deleting", + "value": "Deleting", + "description": "The resource is being deleted" + }, + { + "name": "Accepted", + "value": "Accepted", + "description": "The resource create request has been accepted" + } + ] + }, + "readOnly": true + } + }, + "parameters": {} +} diff --git a/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.Extension.Private.ts b/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.Extension.Private.ts index efb9bccd24..76884198af 100644 --- a/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.Extension.Private.ts +++ b/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.Extension.Private.ts @@ -1,12 +1,34 @@ import type { DecoratorContext, Model } from "@typespec/compiler"; /** - * `@builtInResource` marks a model as built-in to Azure ResourceManager + * `@builtInResource` marks a model as built-in to Azure ResourceManager at the tenant level * * @param target The model that is marked as built-in. */ export type BuiltInResourceDecorator = (context: DecoratorContext, target: Model) => void; +/** + * `@builtInResource` marks a model as built-in to Azure ResourceManager at the Subscription level + * + * @param target The model that is marked as built-in. + */ +export type BuiltInSubscriptionResourceDecorator = ( + context: DecoratorContext, + target: Model, +) => void; + +/** + * `@builtInResource` marks a model as built-in to Azure ResourceManager at the ResourceGroup level + * + * @param target The model that is marked as built-in. + */ +export type BuiltInResourceGroupResourceDecorator = ( + context: DecoratorContext, + target: Model, +) => void; + export type AzureResourceManagerExtensionPrivateDecorators = { builtInResource: BuiltInResourceDecorator; + builtInSubscriptionResource: BuiltInSubscriptionResourceDecorator; + builtInResourceGroupResource: BuiltInResourceGroupResourceDecorator; }; diff --git a/packages/typespec-azure-resource-manager/lib/common-types/common-types.tsp b/packages/typespec-azure-resource-manager/lib/common-types/common-types.tsp index c344f7181a..f1f2af0394 100644 --- a/packages/typespec-azure-resource-manager/lib/common-types/common-types.tsp +++ b/packages/typespec-azure-resource-manager/lib/common-types/common-types.tsp @@ -9,7 +9,6 @@ import "./customer-managed-keys-ref.tsp"; import "./extended-location-ref.tsp"; import "./internal.tsp"; import "./commontypes.private.decorators.tsp"; -import "./commontypes.extension.models.tsp"; import "./versions.tsp"; import "./mobo-ref.tsp"; import "./network-security-perimeter-ref.tsp"; diff --git a/packages/typespec-azure-resource-manager/lib/common-types/commontypes.extension.models.tsp b/packages/typespec-azure-resource-manager/lib/common-types/commontypes.extension.models.tsp deleted file mode 100644 index dfa68a7c5e..0000000000 --- a/packages/typespec-azure-resource-manager/lib/common-types/commontypes.extension.models.tsp +++ /dev/null @@ -1,15 +0,0 @@ -using Http; -using Rest; -using Azure.Core; -using Azure.ResourceManager.Private; -using Azure.ResourceManager.Extension.Private; - -namespace Azure.ResourceManager.CommonTypes.Extension; - -/** Represents an extension resource group */ -@parentResource(SubscriptionTarget) -@builtInResource -model ResourceGroupTarget is ResourceGroupParameter; - -@builtInResource -model SubscriptionTarget is SubscriptionIdParameter; diff --git a/packages/typespec-azure-resource-manager/lib/common-types/internal.tsp b/packages/typespec-azure-resource-manager/lib/common-types/internal.tsp index f2d0c3acf4..0390fb6b88 100644 --- a/packages/typespec-azure-resource-manager/lib/common-types/internal.tsp +++ b/packages/typespec-azure-resource-manager/lib/common-types/internal.tsp @@ -21,6 +21,12 @@ enum ResourceHome { @doc("The resource is built in") BuiltIn, + + @doc("The resource is built in") + BuiltInSubscription, + + @doc("The resource is built in") + BuiltInResourceGroup, } /** Alias of keyEncryptionKeyIdentity for back compatibility. Please change to keyEncryptionKeyIdentity. */ diff --git a/packages/typespec-azure-resource-manager/lib/common-types/types-ref.tsp b/packages/typespec-azure-resource-manager/lib/common-types/types-ref.tsp index f3ae0aca16..6498cccac2 100644 --- a/packages/typespec-azure-resource-manager/lib/common-types/types-ref.tsp +++ b/packages/typespec-azure-resource-manager/lib/common-types/types-ref.tsp @@ -377,7 +377,9 @@ namespace Azure.ResourceManager.CommonTypes; ResourceHome.Location, ResourceHome.Tenant, ResourceHome.Extension, - ResourceHome.BuiltIn + ResourceHome.BuiltIn, + ResourceHome.BuiltInSubscription, + ResourceHome.BuiltInResourceGroup ] ); @@ -399,7 +401,13 @@ namespace Azure.ResourceManager.CommonTypes; Azure.ResourceManager.CommonTypes.Versions.v6 ); @@resourceParameterBaseFor(SubscriptionIdParameter.subscriptionId, - [ResourceHome.ResourceGroup, ResourceHome.Subscription, ResourceHome.Location] + [ + ResourceHome.ResourceGroup, + ResourceHome.Subscription, + ResourceHome.Location, + ResourceHome.BuiltInSubscription, + ResourceHome.BuiltInResourceGroup + ] ); /** ResourceGroupNameParameter */ @@ -420,7 +428,7 @@ namespace Azure.ResourceManager.CommonTypes; Azure.ResourceManager.CommonTypes.Versions.v6 ); @@resourceParameterBaseFor(ResourceGroupNameParameter.resourceGroupName, - [ResourceHome.ResourceGroup] + [ResourceHome.ResourceGroup, ResourceHome.BuiltInResourceGroup] ); /** ManagementGroupNameParameter */ diff --git a/packages/typespec-azure-resource-manager/lib/common-types/types.tsp b/packages/typespec-azure-resource-manager/lib/common-types/types.tsp index 2b0539eccc..08c8592826 100644 --- a/packages/typespec-azure-resource-manager/lib/common-types/types.tsp +++ b/packages/typespec-azure-resource-manager/lib/common-types/types.tsp @@ -524,7 +524,6 @@ model LocationParameter { */ model ResourceGroupNameParameter { /** The name of the resource group. The name is case insensitive. */ - @key @path @minLength(1) @maxLength(90) @@ -542,7 +541,6 @@ model SubscriptionIdParameter { @path @segment("subscriptions") @minLength(1) - @key subscriptionId: uuid; } diff --git a/packages/typespec-azure-resource-manager/lib/extension/operations.tsp b/packages/typespec-azure-resource-manager/lib/extension/operations.tsp index 00431ad9ed..37d0616022 100644 --- a/packages/typespec-azure-resource-manager/lib/extension/operations.tsp +++ b/packages/typespec-azure-resource-manager/lib/extension/operations.tsp @@ -25,12 +25,13 @@ using Azure.ResourceManager.Private; @enforceConstraint(ExtensionResource, Foundations.Resource) op ListByTarget< TargetResource extends Foundations.SimpleResource, + TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, Parameters extends {} = {}, Response extends {} = ArmResponse>, Error extends {} = ErrorResponse > is ArmReadOperation< - ExtensionParentParameters & Parameters, + ExtensionParentParameters & Parameters, Response, Error >; @@ -51,12 +52,13 @@ op ListByTarget< @armResourceRead(ExtensionResource) op Read< TargetResource extends SimpleResource, + TargetNamespace extends string, ExtensionResource extends SimpleResource, Parameters extends {} = {}, Response extends {} = ArmResponse, Error extends {} = ErrorResponse > is ArmReadOperation< - ExtensionInstanceParameters & Parameters, + ExtensionInstanceParameters & Parameters, Response, Error >; @@ -76,12 +78,13 @@ op Read< @head op CheckExistence< TargetResource extends SimpleResource, + TargetNamespace extends string, ExtensionResource extends SimpleResource, Parameters extends {} = {}, Response extends {} = ArmResourceExistsResponse | ArmResourceNotFoundResponse, Error extends {} = ErrorResponse > is ArmReadOperation< - ExtensionInstanceParameters & Parameters, + ExtensionInstanceParameters & Parameters, Response, Error >; @@ -104,6 +107,7 @@ op CheckExistence< @put op CreateOrUpdateAsync< TargetResource extends Foundations.SimpleResource, + TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, LroHeaders extends TypeSpec.Reflection.Model = ArmAsyncOperationHeader & Azure.Core.Foundations.RetryAfterHeader, @@ -114,7 +118,7 @@ op CreateOrUpdateAsync< >, Error extends {} = ErrorResponse > is ArmCreateOperation< - ExtensionInstanceParameters & Parameters, + ExtensionInstanceParameters & Parameters, ExtensionResource, Response, Error @@ -136,12 +140,13 @@ op CreateOrUpdateAsync< @put op CreateOrReplaceSync< TargetResource extends Foundations.SimpleResource, + TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, Parameters extends {} = {}, Response extends {} = ArmResourceUpdatedResponse | ArmResourceCreatedSyncResponse, Error extends {} = ErrorResponse > is ArmCreateOperation< - ExtensionInstanceParameters & Parameters, + ExtensionInstanceParameters & Parameters, ExtensionResource, Response, Error @@ -160,6 +165,7 @@ op CreateOrReplaceSync< @enforceConstraint(ExtensionResource, Foundations.Resource) op CreateOrReplaceAsync< TargetResource extends Foundations.SimpleResource, + TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, LroHeaders extends TypeSpec.Reflection.Model = ArmAsyncOperationHeader & Azure.Core.Foundations.RetryAfterHeader, @@ -171,6 +177,7 @@ op CreateOrReplaceAsync< Error extends {} = ErrorResponse > is CreateOrUpdateAsync< TargetResource, + TargetNamespace, ExtensionResource, LroHeaders, Parameters, @@ -196,6 +203,7 @@ op CreateOrReplaceAsync< @patch(#{ implicitOptionality: true }) op CustomPatchAsync< TargetResource extends Foundations.SimpleResource, + TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, PatchModel extends TypeSpec.Reflection.Model = TagsUpdateModel, LroHeaders extends TypeSpec.Reflection.Model = ArmLroLocationHeader< @@ -211,7 +219,7 @@ op CustomPatchAsync< >, Error extends {} = ErrorResponse > is ArmUpdateOperation< - ExtensionInstanceParameters & Parameters, + ExtensionInstanceParameters & Parameters, PatchModel, Response, Error @@ -234,13 +242,14 @@ op CustomPatchAsync< @patch(#{ implicitOptionality: true }) op CustomPatchSync< TargetResource extends Foundations.SimpleResource, + TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, PatchModel extends TypeSpec.Reflection.Model = TagsUpdateModel, Parameters extends {} = {}, Response extends {} = ArmResponse, Error extends {} = ErrorResponse > is ArmUpdateOperation< - ExtensionInstanceParameters & Parameters, + ExtensionInstanceParameters & Parameters, PatchModel, Response, Error @@ -262,12 +271,13 @@ op CustomPatchSync< @delete op DeleteAsyncBase< TargetResource extends Foundations.SimpleResource, + TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, Response, Parameters extends {} = {}, Error extends {} = ErrorResponse >( - ...ExtensionInstanceParameters, + ...ExtensionInstanceParameters, ...Parameters, ): Response | Error; @@ -285,13 +295,21 @@ op DeleteAsyncBase< @enforceConstraint(ExtensionResource, Foundations.Resource) op DeleteAsync< TargetResource extends Foundations.SimpleResource, + TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, LroHeaders extends TypeSpec.Reflection.Model = ArmLroLocationHeader & Azure.Core.Foundations.RetryAfterHeader, Parameters extends {} = {}, Response extends {} = ArmDeletedResponse | ArmDeleteAcceptedLroResponse | ArmDeletedNoContentResponse, Error extends {} = ErrorResponse -> is DeleteAsyncBase; +> is DeleteAsyncBase< + TargetResource, + TargetNamespace, + ExtensionResource, + Response, + Parameters, + Error +>; /** * @dev Delete a resource asynchronously @@ -306,13 +324,21 @@ op DeleteAsync< @enforceConstraint(ExtensionResource, Foundations.Resource) op DeleteWithoutOkAsync< TargetResource extends Foundations.SimpleResource, + TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, LroHeaders extends TypeSpec.Reflection.Model = ArmLroLocationHeader & Azure.Core.Foundations.RetryAfterHeader, Parameters extends {} = {}, Response extends {} = ArmDeleteAcceptedLroResponse | ArmDeletedNoContentResponse, Error extends {} = ErrorResponse -> is DeleteAsyncBase; +> is DeleteAsyncBase< + TargetResource, + TargetNamespace, + ExtensionResource, + Response, + Parameters, + Error +>; /** * Delete a resource synchronously @@ -330,12 +356,13 @@ op DeleteWithoutOkAsync< @delete op DeleteSync< TargetResource extends Foundations.SimpleResource, + TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, Parameters extends {} = {}, Response extends {} = ArmDeletedResponse | ArmDeletedNoContentResponse, Error = ErrorResponse >( - ...ExtensionInstanceParameters, + ...ExtensionInstanceParameters, ...Parameters, ): Response | Error; @@ -356,6 +383,7 @@ op DeleteSync< @post op ActionAsyncBase< TargetResource extends Foundations.SimpleResource, + TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, Request extends TypeSpec.Reflection.Model | void, Response extends TypeSpec.Reflection.Model | void, @@ -363,7 +391,7 @@ op ActionAsyncBase< Error extends {} = ErrorResponse, OptionalRequestBody extends valueof boolean = false >( - ...ExtensionInstanceParameters, + ...ExtensionInstanceParameters, ...Parameters, @doc("The content of the action request") @@ -386,6 +414,7 @@ op ActionAsyncBase< @enforceConstraint(ExtensionResource, Foundations.Resource) op ActionAsync< TargetResource extends Foundations.SimpleResource, + TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, Request extends TypeSpec.Reflection.Model | void, Response extends TypeSpec.Reflection.Model | void, @@ -400,6 +429,7 @@ op ActionAsync< OptionalRequestBody extends valueof boolean = false > is ActionAsyncBase< TargetResource, + TargetNamespace, ExtensionResource, Request, ArmAcceptedLroResponse<"Resource operation accepted.", LroHeaders> | Response, @@ -426,6 +456,7 @@ op ActionAsync< @returnsDoc("Azure operation completed successfully.") op ActionSync< TargetResource extends Foundations.SimpleResource, + TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, Request extends TypeSpec.Reflection.Model | void, Response extends TypeSpec.Reflection.Model | void, @@ -433,7 +464,7 @@ op ActionSync< Error extends {} = ErrorResponse, OptionalRequestBody extends valueof boolean = false >( - ...ExtensionInstanceParameters, + ...ExtensionInstanceParameters, ...Parameters, @doc("The content of the action request") @@ -455,6 +486,7 @@ op ActionSync< @enforceConstraint(ExtensionResource, Foundations.Resource) op ActionNoResponseContentAsync< TargetResource extends Foundations.SimpleResource, + TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, Request extends TypeSpec.Reflection.Model | void, LroHeaders extends TypeSpec.Reflection.Model = ArmLroLocationHeader< @@ -468,6 +500,7 @@ op ActionNoResponseContentAsync< OptionalRequestBody extends valueof boolean = false > is ActionAsyncBase< TargetResource, + TargetNamespace, ExtensionResource, Request, ArmAcceptedLroResponse<"Resource operation accepted.", LroHeaders>, @@ -492,13 +525,14 @@ op ActionNoResponseContentAsync< @post op ActionNoContentSync< TargetResource extends Foundations.SimpleResource, + TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, Request extends TypeSpec.Reflection.Model | void, Parameters extends {} = {}, Error extends {} = ErrorResponse, OptionalRequestBody extends valueof boolean = false >( - ...ExtensionInstanceParameters, + ...ExtensionInstanceParameters, ...Parameters, @doc("The content of the action request") diff --git a/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp b/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp index 5a93ff9a2b..ac67582f5d 100644 --- a/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp +++ b/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp @@ -29,7 +29,10 @@ model ScopeParameter { * @template Resource The type of the resource. */ @resourceBaseParametersOf(Resource) -model TargetBaseParameters { +model TargetBaseParameters< + Resource extends {}, + TargetNamespace extends string = "Microsoft.ThisWillBeReplaced" +> { ...ApiVersionParameter; // unless built-in, tenant or extension @@ -39,24 +42,26 @@ model TargetBaseParameters { ...CommonTypes.ResourceGroupNameParameter; // unless built-in - ...TargetProviderNamespace; + ...TargetProviderNamespace; } -model TargetParameters { - ...TargetBaseParameters; +model TargetParameters< + Resource extends {}, + TargetNamespace extends string = "Microsoft.ThisWillBeReplaced" +> { + ...TargetBaseParameters; ...KeysOf; } model ExtensionProviderNamespace { @path @segment("providers") - @key @assignProviderNameValue(Resource) @doc("The provider namespace for the resource.") extensionProvider: "Microsoft.ThisWillBeReplaced"; } -model TargetProviderNamespace { +model TargetProviderNamespace { @resourceParameterBaseFor( [ ResourceHome.Extension, @@ -67,21 +72,28 @@ model TargetProviderNamespace { ] ) @path - @segment("provider") - @key + @segment("providers") @doc("The provider namespace for the resource.") @assignProviderNameValue(Resource) provider: "Microsoft.ThisWillBeReplaced"; } -model ExtensionInstanceParameters { - ...TargetParameters; +model ExtensionInstanceParameters< + TargetResource extends {}, + TargetNamespace extends string, + Resource extends {} +> { + ...TargetParameters; ...ExtensionProviderNamespace; ...KeysOf; } -model ExtensionParentParameters { - ...TargetParameters; +model ExtensionParentParameters< + TargetResource extends {}, + TargetNamespace extends string, + ExtensionResource extends {} +> { + ...TargetParameters; ...ExtensionProviderNamespace; ...ParentKeysOf; } @@ -100,5 +112,23 @@ model ManagementGroup { name: string; } -alias Subscription = CommonTypes.Extension.SubscriptionTarget; -alias ResourceGroup = CommonTypes.Extension.ResourceGroupTarget; +@armVirtualResource(TargetNamespace) +@Http.Private.includeInapplicableMetadataInPayload(false) +model ExternalResource< + TargetNamespace extends valueof string, + ResourceType extends valueof string, + ResourceParameterName extends valueof string +> { + /** The name of the virtual machine */ + @visibility(Lifecycle.Read) + @path + @key(ResourceParameterName) + @segment(ResourceType) + name: string; +} + +@builtInSubscriptionResource +model Subscription {} + +@builtInResourceGroupResource +model ResourceGroup {} diff --git a/packages/typespec-azure-resource-manager/lib/extension/private.decorators.tsp b/packages/typespec-azure-resource-manager/lib/extension/private.decorators.tsp index 12c17e9f2e..d58099959d 100644 --- a/packages/typespec-azure-resource-manager/lib/extension/private.decorators.tsp +++ b/packages/typespec-azure-resource-manager/lib/extension/private.decorators.tsp @@ -6,8 +6,22 @@ using Reflection; namespace Azure.ResourceManager.Extension.Private; /** - * `@builtInResource` marks a model as built-in to Azure ResourceManager + * `@builtInResource` marks a model as built-in to Azure ResourceManager at the tenant level * * @param target - The model that is marked as built-in. */ extern dec builtInResource(target: Model); + +/** + * `@builtInResource` marks a model as built-in to Azure ResourceManager at the Subscription level + * + * @param target - The model that is marked as built-in. + */ +extern dec builtInSubscriptionResource(target: Model); + +/** + * `@builtInResource` marks a model as built-in to Azure ResourceManager at the ResourceGroup level + * + * @param target - The model that is marked as built-in. + */ +extern dec builtInResourceGroupResource(target: Model); diff --git a/packages/typespec-azure-resource-manager/src/private.decorators.ts b/packages/typespec-azure-resource-manager/src/private.decorators.ts index 749738f231..65fb40f2b3 100644 --- a/packages/typespec-azure-resource-manager/src/private.decorators.ts +++ b/packages/typespec-azure-resource-manager/src/private.decorators.ts @@ -6,7 +6,6 @@ import { ModelProperty, Operation, Program, - StringLiteral, Tuple, Type, addVisibilityModifiers, @@ -17,6 +16,7 @@ import { isKey, sealVisibilityModifiers, } from "@typespec/compiler"; +import { $ } from "@typespec/compiler/typekit"; import { $bodyRoot, getHttpOperation } from "@typespec/http"; import { $segment, getSegment } from "@typespec/rest"; import { camelCase } from "change-case"; @@ -24,6 +24,8 @@ import pluralize from "pluralize"; import { AzureResourceManagerExtensionPrivateDecorators, BuiltInResourceDecorator, + BuiltInResourceGroupResourceDecorator, + BuiltInSubscriptionResourceDecorator, } from "../generated-defs/Azure.ResourceManager.Extension.Private.js"; import { ArmBodyRootDecorator, @@ -69,6 +71,24 @@ const $builtInResource: BuiltInResourceDecorator = ( setResourceBaseType(program, resourceType, ResourceBaseType.BuiltIn); }; + +const $builtInSubscriptionResource: BuiltInSubscriptionResourceDecorator = ( + context: DecoratorContext, + resourceType: Model, +) => { + const { program } = context; + + setResourceBaseType(program, resourceType, ResourceBaseType.BuiltInSubscription); +}; + +const $builtInResourceGroupResource: BuiltInResourceGroupResourceDecorator = ( + context: DecoratorContext, + resourceType: Model, +) => { + const { program } = context; + + setResourceBaseType(program, resourceType, ResourceBaseType.BuiltInResourceGroup); +}; const $omitIfEmpty: OmitIfEmptyDecorator = ( context: DecoratorContext, entity: Model, @@ -104,6 +124,13 @@ function checkAllowedVirtualResource( } } +function isBuiltIn(baseType: ResourceBaseType): boolean { + return ( + baseType === ResourceBaseType.BuiltIn || + baseType === ResourceBaseType.BuiltInSubscription || + baseType === ResourceBaseType.BuiltInResourceGroup + ); +} const $enforceConstraint: EnforceConstraintDecorator = ( context: DecoratorContext, entity: Operation | Model, @@ -117,7 +144,7 @@ const $enforceConstraint: EnforceConstraintDecorator = ( if ( baseType === constraintType || isCustomAzureResource(context.program, baseType) || - getResourceBaseType(context.program, baseType) === ResourceBaseType.BuiltIn || + isBuiltIn(getResourceBaseType(context.program, baseType)) || checkAllowedVirtualResource(context.program, entity, baseType) ) return; @@ -241,10 +268,13 @@ const $assignProviderNameValue: AssignProviderNameValueDecorator = ( resourceType: Model, ) => { const { program } = context; - - const armProviderNamespace = getArmProviderNamespace(program, resourceType as Model); - if (armProviderNamespace) { - (target.type as StringLiteral).value = armProviderNamespace; + const details = getArmVirtualResourceDetails(program, resourceType); + const armProviderNamespace = + details?.provider ?? getArmProviderNamespace(program, resourceType as Model); + if (armProviderNamespace && target.type.kind === "String") { + const targetType = $(program).realm.clone(target.type); + targetType.value = armProviderNamespace; + target.type = targetType; } }; @@ -529,5 +559,7 @@ export const $decorators = { } satisfies AzureResourceManagerPrivateDecorators, "Azure.ResourceManager.Extension.Private": { builtInResource: $builtInResource, + builtInSubscriptionResource: $builtInSubscriptionResource, + builtInResourceGroupResource: $builtInResourceGroupResource, } satisfies AzureResourceManagerExtensionPrivateDecorators, }; diff --git a/packages/typespec-azure-resource-manager/src/resource.ts b/packages/typespec-azure-resource-manager/src/resource.ts index a0674d87ad..d4d4855159 100644 --- a/packages/typespec-azure-resource-manager/src/resource.ts +++ b/packages/typespec-azure-resource-manager/src/resource.ts @@ -365,6 +365,8 @@ export enum ResourceBaseType { ResourceGroup = "ResourceGroup", Extension = "Extension", BuiltIn = "BuiltIn", + BuiltInSubscription = "BuiltInSubscription", + BuiltInResourceGroup = "BuiltInResourceGroup", } export const $resourceBaseType: ResourceBaseTypeDecorator = ( @@ -589,6 +591,12 @@ export function resolveResourceBaseType(type?: string | undefined): ResourceBase case "BuiltIn": resolvedType = ResourceBaseType.BuiltIn; break; + case "BuiltInSubscription": + resolvedType = ResourceBaseType.BuiltInSubscription; + break; + case "BuiltInResourceGroup": + resolvedType = ResourceBaseType.BuiltInResourceGroup; + break; } } return resolvedType; From 584faf57daf1d6b698199529cc16f6b4627300fc Mon Sep 17 00:00:00 2001 From: Mark Cowlishaw <1054056+markcowl@users.noreply.github.com> Date: Mon, 23 Jun 2025 15:51:38 -0700 Subject: [PATCH 05/16] Update changelog --- .chronus/changes/extension-res-2025-5-23-22-49-14.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .chronus/changes/extension-res-2025-5-23-22-49-14.md diff --git a/.chronus/changes/extension-res-2025-5-23-22-49-14.md b/.chronus/changes/extension-res-2025-5-23-22-49-14.md new file mode 100644 index 0000000000..2dd40053e0 --- /dev/null +++ b/.chronus/changes/extension-res-2025-5-23-22-49-14.md @@ -0,0 +1,8 @@ +--- +# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking +changeKind: fix +packages: + - "@azure-tools/typespec-azure-resource-manager" +--- + +Fix #2764 Add advanced extension resource support From 5d81330acb669a9958e70cc55b7fec322fbe721d Mon Sep 17 00:00:00 2001 From: Mark Cowlishaw Date: Mon, 23 Jun 2025 20:57:31 -0700 Subject: [PATCH 06/16] Update docs, virtual resource detection, and rules --- .../specific-extension/main.tsp | 40 +- .../2021-10-01-preview/openapi.json | 412 ++++++++++++++++++ .../typespec-azure-resource-manager/README.md | 6 +- .../lib/extension/operations.tsp | 62 +-- .../lib/extension/parameters.tsp | 102 +++-- .../src/private.decorators.ts | 28 +- .../src/resource.ts | 15 +- .../src/rules/list-operation.ts | 2 +- .../src/state.ts | 1 + .../reference/data-types.md | 280 +++++++++++- .../reference/decorators.md | 6 +- .../reference/index.mdx | 41 ++ .../reference/interfaces.md | 317 ++++++++++++++ 13 files changed, 1200 insertions(+), 112 deletions(-) diff --git a/packages/samples/specs/resource-manager/resource-types/specific-extension/main.tsp b/packages/samples/specs/resource-manager/resource-types/specific-extension/main.tsp index 0aec655779..e582ab7c58 100644 --- a/packages/samples/specs/resource-manager/resource-types/specific-extension/main.tsp +++ b/packages/samples/specs/resource-manager/resource-types/specific-extension/main.tsp @@ -67,27 +67,40 @@ union ProvisioningState { interface Operations extends Azure.ResourceManager.Operations {} -interface EmplOps< - Scope extends Azure.ResourceManager.Foundations.SimpleResource, - Provider extends string = "" -> { - get is Extension.Read; - #suppress "@azure-tools/typespec-azure-resource-manager/arm-resource-operation-response" "" - create is Extension.CreateOrReplaceAsync; +interface EmplOps { + get is Extension.Read; + + create is Extension.CreateOrReplaceAsync; update is Extension.CustomPatchSync< Scope, - Provider, Employee, Azure.ResourceManager.Foundations.ResourceUpdateModel >; - delete is Extension.DeleteWithoutOkAsync; - list is Extension.ListByTarget; - move is Extension.ActionSync; + delete is Extension.DeleteWithoutOkAsync; + list is Extension.ListByTarget; + move is Extension.ActionSync; } /** Virtual resource for a virtual machine */ alias VirtualMachine = Extension.ExternalResource<"Microsoft.Compute", "virtualMachines", "vmName">; +alias Scaleset = Extension.ExternalResource< + "Microsoft.Compute", + "virtualMachineScaleSets", + "scaleSetName" +>; +/** A scaleset VM */ +@parentResource(Scaleset) +model VirtualMachineScaleSetVm { + /** Name of the scaleset VM */ + @visibility(Lifecycle.Read) + @path + @segment("virtualMachineScaleSetVms") + @key("scaleSetVmName") + @pattern("^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$") + name: string; +} + @armResourceOperations interface Employees extends EmplOps {} @armResourceOperations @@ -98,10 +111,13 @@ interface Subscriptions extends EmplOps {} interface ResourceGroups extends EmplOps {} @armResourceOperations interface ManagementGroups extends EmplOps {} -#suppress "@azure-tools/typespec-azure-resource-manager/improper-subscription-list-operation" "" + @armResourceOperations interface VirtualMachines extends EmplOps {} +@armResourceOperations +interface ScaleSetVms extends EmplOps {} + /** Employee move request */ model MoveRequest { /** The moving from location */ diff --git a/packages/samples/test/output/azure/resource-manager/resource-types/specific-extension/@azure-tools/typespec-autorest/2021-10-01-preview/openapi.json b/packages/samples/test/output/azure/resource-manager/resource-types/specific-extension/@azure-tools/typespec-autorest/2021-10-01-preview/openapi.json index 5aea1cc6f4..057fe13f43 100644 --- a/packages/samples/test/output/azure/resource-manager/resource-types/specific-extension/@azure-tools/typespec-autorest/2021-10-01-preview/openapi.json +++ b/packages/samples/test/output/azure/resource-manager/resource-types/specific-extension/@azure-tools/typespec-autorest/2021-10-01-preview/openapi.json @@ -59,6 +59,9 @@ }, { "name": "VirtualMachines" + }, + { + "name": "ScaleSetVms" } ], "paths": { @@ -1279,6 +1282,400 @@ } } }, + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/virtualMachineScaleSets/{scaleSetName}/virtualMachineScaleSetVms/{scaleSetVmName}/providers/Microsoft.ContosoProviderHub/employees": { + "get": { + "operationId": "ScaleSetVms_List", + "tags": [ + "ScaleSetVms" + ], + "description": "List Employee resources by subscription ID", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "scaleSetName", + "in": "path", + "description": "The name of the virtual machine", + "required": true, + "type": "string" + }, + { + "name": "scaleSetVmName", + "in": "path", + "description": "Name of the scaleset VM", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/EmployeeListResult" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "nextLink" + } + } + }, + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/virtualMachineScaleSets/{scaleSetName}/virtualMachineScaleSetVms/{scaleSetVmName}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}": { + "get": { + "operationId": "ScaleSetVms_Get", + "tags": [ + "ScaleSetVms" + ], + "description": "Get a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "scaleSetName", + "in": "path", + "description": "The name of the virtual machine", + "required": true, + "type": "string" + }, + { + "name": "scaleSetVmName", + "in": "path", + "description": "Name of the scaleset VM", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + }, + "put": { + "operationId": "ScaleSetVms_Create", + "tags": [ + "ScaleSetVms" + ], + "description": "Create a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "scaleSetName", + "in": "path", + "description": "The name of the virtual machine", + "required": true, + "type": "string" + }, + { + "name": "scaleSetVmName", + "in": "path", + "description": "Name of the scaleset VM", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "resource", + "in": "body", + "description": "Resource create parameters.", + "required": true, + "schema": { + "$ref": "#/definitions/Employee" + } + } + ], + "responses": { + "200": { + "description": "Resource 'Employee' update operation succeeded", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "201": { + "description": "Resource 'Employee' create operation succeeded", + "schema": { + "$ref": "#/definitions/Employee" + }, + "headers": { + "Azure-AsyncOperation": { + "type": "string", + "description": "A link to the status monitor" + }, + "Retry-After": { + "type": "integer", + "format": "int32", + "description": "The Retry-After header can indicate how long the client should wait before polling the operation status." + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-long-running-operation-options": { + "final-state-via": "azure-async-operation" + }, + "x-ms-long-running-operation": true + }, + "patch": { + "operationId": "ScaleSetVms_Update", + "tags": [ + "ScaleSetVms" + ], + "description": "Update a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "scaleSetName", + "in": "path", + "description": "The name of the virtual machine", + "required": true, + "type": "string" + }, + { + "name": "scaleSetVmName", + "in": "path", + "description": "Name of the scaleset VM", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "properties", + "in": "body", + "description": "The resource properties to be updated.", + "required": true, + "schema": { + "$ref": "#/definitions/EmployeeUpdate" + } + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + }, + "delete": { + "operationId": "ScaleSetVms_Delete", + "tags": [ + "ScaleSetVms" + ], + "description": "Delete a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "scaleSetName", + "in": "path", + "description": "The name of the virtual machine", + "required": true, + "type": "string" + }, + { + "name": "scaleSetVmName", + "in": "path", + "description": "Name of the scaleset VM", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + } + ], + "responses": { + "202": { + "description": "Resource deletion accepted.", + "headers": { + "Location": { + "type": "string", + "description": "The Location header contains the URL where the status of the long running operation can be checked." + }, + "Retry-After": { + "type": "integer", + "format": "int32", + "description": "The Retry-After header can indicate how long the client should wait before polling the operation status." + } + } + }, + "204": { + "description": "Resource does not exist." + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-long-running-operation-options": { + "final-state-via": "location" + }, + "x-ms-long-running-operation": true + } + }, + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/virtualMachineScaleSets/{scaleSetName}/virtualMachineScaleSetVms/{scaleSetVmName}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}/move": { + "post": { + "operationId": "ScaleSetVms_Move", + "tags": [ + "ScaleSetVms" + ], + "description": "A synchronous resource action.", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "scaleSetName", + "in": "path", + "description": "The name of the virtual machine", + "required": true, + "type": "string" + }, + { + "name": "scaleSetVmName", + "in": "path", + "description": "Name of the scaleset VM", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "body", + "in": "body", + "description": "The content of the action request", + "required": true, + "schema": { + "$ref": "#/definitions/MoveRequest" + } + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/MoveResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + } + }, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/virtualMachines/{vmName}/providers/Microsoft.ContosoProviderHub/employees": { "get": { "operationId": "VirtualMachines_List", @@ -2109,6 +2506,21 @@ ] }, "readOnly": true + }, + "VirtualMachineScaleSetVm": { + "type": "object", + "description": "A scaleset VM", + "properties": { + "name": { + "type": "string", + "description": "Name of the scaleset VM", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$", + "readOnly": true + } + }, + "required": [ + "name" + ] } }, "parameters": {} diff --git a/packages/typespec-azure-resource-manager/README.md b/packages/typespec-azure-resource-manager/README.md index 77b2b765e5..b4f68a3a7b 100644 --- a/packages/typespec-azure-resource-manager/README.md +++ b/packages/typespec-azure-resource-manager/README.md @@ -322,7 +322,7 @@ This decorator is used on Azure Resource Manager resources that are not based on Azure.ResourceManager common types. ```typespec -@Azure.ResourceManager.armVirtualResource +@Azure.ResourceManager.armVirtualResource(provider?: valueof string) ``` ##### Target @@ -331,7 +331,9 @@ Azure.ResourceManager common types. ##### Parameters -None +| Name | Type | Description | +| -------- | ---------------- | ----------- | +| provider | `valueof string` | | #### `@extensionResource` diff --git a/packages/typespec-azure-resource-manager/lib/extension/operations.tsp b/packages/typespec-azure-resource-manager/lib/extension/operations.tsp index 37d0616022..00431ad9ed 100644 --- a/packages/typespec-azure-resource-manager/lib/extension/operations.tsp +++ b/packages/typespec-azure-resource-manager/lib/extension/operations.tsp @@ -25,13 +25,12 @@ using Azure.ResourceManager.Private; @enforceConstraint(ExtensionResource, Foundations.Resource) op ListByTarget< TargetResource extends Foundations.SimpleResource, - TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, Parameters extends {} = {}, Response extends {} = ArmResponse>, Error extends {} = ErrorResponse > is ArmReadOperation< - ExtensionParentParameters & Parameters, + ExtensionParentParameters & Parameters, Response, Error >; @@ -52,13 +51,12 @@ op ListByTarget< @armResourceRead(ExtensionResource) op Read< TargetResource extends SimpleResource, - TargetNamespace extends string, ExtensionResource extends SimpleResource, Parameters extends {} = {}, Response extends {} = ArmResponse, Error extends {} = ErrorResponse > is ArmReadOperation< - ExtensionInstanceParameters & Parameters, + ExtensionInstanceParameters & Parameters, Response, Error >; @@ -78,13 +76,12 @@ op Read< @head op CheckExistence< TargetResource extends SimpleResource, - TargetNamespace extends string, ExtensionResource extends SimpleResource, Parameters extends {} = {}, Response extends {} = ArmResourceExistsResponse | ArmResourceNotFoundResponse, Error extends {} = ErrorResponse > is ArmReadOperation< - ExtensionInstanceParameters & Parameters, + ExtensionInstanceParameters & Parameters, Response, Error >; @@ -107,7 +104,6 @@ op CheckExistence< @put op CreateOrUpdateAsync< TargetResource extends Foundations.SimpleResource, - TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, LroHeaders extends TypeSpec.Reflection.Model = ArmAsyncOperationHeader & Azure.Core.Foundations.RetryAfterHeader, @@ -118,7 +114,7 @@ op CreateOrUpdateAsync< >, Error extends {} = ErrorResponse > is ArmCreateOperation< - ExtensionInstanceParameters & Parameters, + ExtensionInstanceParameters & Parameters, ExtensionResource, Response, Error @@ -140,13 +136,12 @@ op CreateOrUpdateAsync< @put op CreateOrReplaceSync< TargetResource extends Foundations.SimpleResource, - TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, Parameters extends {} = {}, Response extends {} = ArmResourceUpdatedResponse | ArmResourceCreatedSyncResponse, Error extends {} = ErrorResponse > is ArmCreateOperation< - ExtensionInstanceParameters & Parameters, + ExtensionInstanceParameters & Parameters, ExtensionResource, Response, Error @@ -165,7 +160,6 @@ op CreateOrReplaceSync< @enforceConstraint(ExtensionResource, Foundations.Resource) op CreateOrReplaceAsync< TargetResource extends Foundations.SimpleResource, - TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, LroHeaders extends TypeSpec.Reflection.Model = ArmAsyncOperationHeader & Azure.Core.Foundations.RetryAfterHeader, @@ -177,7 +171,6 @@ op CreateOrReplaceAsync< Error extends {} = ErrorResponse > is CreateOrUpdateAsync< TargetResource, - TargetNamespace, ExtensionResource, LroHeaders, Parameters, @@ -203,7 +196,6 @@ op CreateOrReplaceAsync< @patch(#{ implicitOptionality: true }) op CustomPatchAsync< TargetResource extends Foundations.SimpleResource, - TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, PatchModel extends TypeSpec.Reflection.Model = TagsUpdateModel, LroHeaders extends TypeSpec.Reflection.Model = ArmLroLocationHeader< @@ -219,7 +211,7 @@ op CustomPatchAsync< >, Error extends {} = ErrorResponse > is ArmUpdateOperation< - ExtensionInstanceParameters & Parameters, + ExtensionInstanceParameters & Parameters, PatchModel, Response, Error @@ -242,14 +234,13 @@ op CustomPatchAsync< @patch(#{ implicitOptionality: true }) op CustomPatchSync< TargetResource extends Foundations.SimpleResource, - TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, PatchModel extends TypeSpec.Reflection.Model = TagsUpdateModel, Parameters extends {} = {}, Response extends {} = ArmResponse, Error extends {} = ErrorResponse > is ArmUpdateOperation< - ExtensionInstanceParameters & Parameters, + ExtensionInstanceParameters & Parameters, PatchModel, Response, Error @@ -271,13 +262,12 @@ op CustomPatchSync< @delete op DeleteAsyncBase< TargetResource extends Foundations.SimpleResource, - TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, Response, Parameters extends {} = {}, Error extends {} = ErrorResponse >( - ...ExtensionInstanceParameters, + ...ExtensionInstanceParameters, ...Parameters, ): Response | Error; @@ -295,21 +285,13 @@ op DeleteAsyncBase< @enforceConstraint(ExtensionResource, Foundations.Resource) op DeleteAsync< TargetResource extends Foundations.SimpleResource, - TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, LroHeaders extends TypeSpec.Reflection.Model = ArmLroLocationHeader & Azure.Core.Foundations.RetryAfterHeader, Parameters extends {} = {}, Response extends {} = ArmDeletedResponse | ArmDeleteAcceptedLroResponse | ArmDeletedNoContentResponse, Error extends {} = ErrorResponse -> is DeleteAsyncBase< - TargetResource, - TargetNamespace, - ExtensionResource, - Response, - Parameters, - Error ->; +> is DeleteAsyncBase; /** * @dev Delete a resource asynchronously @@ -324,21 +306,13 @@ op DeleteAsync< @enforceConstraint(ExtensionResource, Foundations.Resource) op DeleteWithoutOkAsync< TargetResource extends Foundations.SimpleResource, - TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, LroHeaders extends TypeSpec.Reflection.Model = ArmLroLocationHeader & Azure.Core.Foundations.RetryAfterHeader, Parameters extends {} = {}, Response extends {} = ArmDeleteAcceptedLroResponse | ArmDeletedNoContentResponse, Error extends {} = ErrorResponse -> is DeleteAsyncBase< - TargetResource, - TargetNamespace, - ExtensionResource, - Response, - Parameters, - Error ->; +> is DeleteAsyncBase; /** * Delete a resource synchronously @@ -356,13 +330,12 @@ op DeleteWithoutOkAsync< @delete op DeleteSync< TargetResource extends Foundations.SimpleResource, - TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, Parameters extends {} = {}, Response extends {} = ArmDeletedResponse | ArmDeletedNoContentResponse, Error = ErrorResponse >( - ...ExtensionInstanceParameters, + ...ExtensionInstanceParameters, ...Parameters, ): Response | Error; @@ -383,7 +356,6 @@ op DeleteSync< @post op ActionAsyncBase< TargetResource extends Foundations.SimpleResource, - TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, Request extends TypeSpec.Reflection.Model | void, Response extends TypeSpec.Reflection.Model | void, @@ -391,7 +363,7 @@ op ActionAsyncBase< Error extends {} = ErrorResponse, OptionalRequestBody extends valueof boolean = false >( - ...ExtensionInstanceParameters, + ...ExtensionInstanceParameters, ...Parameters, @doc("The content of the action request") @@ -414,7 +386,6 @@ op ActionAsyncBase< @enforceConstraint(ExtensionResource, Foundations.Resource) op ActionAsync< TargetResource extends Foundations.SimpleResource, - TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, Request extends TypeSpec.Reflection.Model | void, Response extends TypeSpec.Reflection.Model | void, @@ -429,7 +400,6 @@ op ActionAsync< OptionalRequestBody extends valueof boolean = false > is ActionAsyncBase< TargetResource, - TargetNamespace, ExtensionResource, Request, ArmAcceptedLroResponse<"Resource operation accepted.", LroHeaders> | Response, @@ -456,7 +426,6 @@ op ActionAsync< @returnsDoc("Azure operation completed successfully.") op ActionSync< TargetResource extends Foundations.SimpleResource, - TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, Request extends TypeSpec.Reflection.Model | void, Response extends TypeSpec.Reflection.Model | void, @@ -464,7 +433,7 @@ op ActionSync< Error extends {} = ErrorResponse, OptionalRequestBody extends valueof boolean = false >( - ...ExtensionInstanceParameters, + ...ExtensionInstanceParameters, ...Parameters, @doc("The content of the action request") @@ -486,7 +455,6 @@ op ActionSync< @enforceConstraint(ExtensionResource, Foundations.Resource) op ActionNoResponseContentAsync< TargetResource extends Foundations.SimpleResource, - TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, Request extends TypeSpec.Reflection.Model | void, LroHeaders extends TypeSpec.Reflection.Model = ArmLroLocationHeader< @@ -500,7 +468,6 @@ op ActionNoResponseContentAsync< OptionalRequestBody extends valueof boolean = false > is ActionAsyncBase< TargetResource, - TargetNamespace, ExtensionResource, Request, ArmAcceptedLroResponse<"Resource operation accepted.", LroHeaders>, @@ -525,14 +492,13 @@ op ActionNoResponseContentAsync< @post op ActionNoContentSync< TargetResource extends Foundations.SimpleResource, - TargetNamespace extends string, ExtensionResource extends Foundations.SimpleResource, Request extends TypeSpec.Reflection.Model | void, Parameters extends {} = {}, Error extends {} = ErrorResponse, OptionalRequestBody extends valueof boolean = false >( - ...ExtensionInstanceParameters, + ...ExtensionInstanceParameters, ...Parameters, @doc("The content of the action request") diff --git a/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp b/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp index ac67582f5d..c68ae9c40c 100644 --- a/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp +++ b/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp @@ -7,7 +7,7 @@ using Azure.ResourceManager.Extension.Private; using Azure.ResourceManager.CommonTypes; /** - * The default scope parameter type. + * The default scope parameter for an extension resource. * * @example * ```typespec @@ -16,7 +16,6 @@ using Azure.ResourceManager.CommonTypes; * } * ``` */ -@doc("The default scope parameter type.") @builtInResource model ScopeParameter { @path(#{ allowReserved: true }) @@ -24,15 +23,14 @@ model ScopeParameter { @doc("The fully qualified Azure Resource manager identifier of the resource.") scope: string; } + /** - * Base parameters for a resource. - * @template Resource The type of the resource. + * Base parameters for an extension target. + * @template Resource The resource model for an extension target (usually Extension.Tenant, Extension.Subscription, Extension.ResourceGroup, Extension.Scope, Extension.ManagementGroup or an external resource). + * */ @resourceBaseParametersOf(Resource) -model TargetBaseParameters< - Resource extends {}, - TargetNamespace extends string = "Microsoft.ThisWillBeReplaced" -> { +model TargetBaseParameters { ...ApiVersionParameter; // unless built-in, tenant or extension @@ -42,17 +40,20 @@ model TargetBaseParameters< ...CommonTypes.ResourceGroupNameParameter; // unless built-in - ...TargetProviderNamespace; + ...TargetProviderNamespace; } -model TargetParameters< - Resource extends {}, - TargetNamespace extends string = "Microsoft.ThisWillBeReplaced" -> { - ...TargetBaseParameters; +/** The path parameters for a target resource for an extension + * @template Resource The resource model for an extension target (usually Extension.Tenant, Extension.Subscription, Extension.ResourceGroup, Extension.Scope, Extension.ManagementGroup or an external resource). + */ +model TargetParameters { + ...TargetBaseParameters; ...KeysOf; } +/** The provider namespace for an extension resource + * @template Resource The extension resource model + */ model ExtensionProviderNamespace { @path @segment("providers") @@ -61,7 +62,10 @@ model ExtensionProviderNamespace { extensionProvider: "Microsoft.ThisWillBeReplaced"; } -model TargetProviderNamespace { +/** The provider namespace (if any) for a target resource for an extension + * @template Resource The resource model for an extension target (usually Extension.Tenant, Extension.Subscription, Extension.ResourceGroup, Extension.Scope, Extension.ManagementGroup or an external resource) + */ +model TargetProviderNamespace { @resourceParameterBaseFor( [ ResourceHome.Extension, @@ -78,40 +82,76 @@ model TargetProviderNamespace { provider: "Microsoft.ThisWillBeReplaced"; } -model ExtensionInstanceParameters< - TargetResource extends {}, - TargetNamespace extends string, - Resource extends {} -> { - ...TargetParameters; +/** The path parameters for an extension resource at the given target + * @template TargetResource The target of the extension resource (Extension.Tenant, Extension.Subscription, Extension.ResourceGroup, Extension.Scope, Extension.ManagementGroup or another resource). + * @template Resource The extension resource. + */ +model ExtensionInstanceParameters { + ...TargetParameters; ...ExtensionProviderNamespace; ...KeysOf; } -model ExtensionParentParameters< - TargetResource extends {}, - TargetNamespace extends string, - ExtensionResource extends {} -> { - ...TargetParameters; +/** The path parameters for a collection of extension resources at the given target + * @template TargetResource The target of the extension resource (Extension.Tenant, Extension.Subscription, Extension.ResourceGroup, Extension.Scope, Extension.ManagementGroup or another resource). + * @template ExtensionResource The extension resource. + */ +model ExtensionParentParameters { + ...TargetParameters; ...ExtensionProviderNamespace; ...ParentKeysOf; } +/** A tenant target for the extension resource */ @builtInResource model Tenant {} -/** Represents a management group */ + +/** A management group + * @template ParameterName The name of the 'name' parameter of the management group (usually managementGroupName or managementGroupId). + */ @tenantResource @armVirtualResource("Microsoft.Management") -model ManagementGroup { +model ManagementGroup { @path @minLength(1) @segment("managementGroups") - @key("managementGroupName") + @key(ParameterName) @doc("The management group ID.") name: string; } +/** An external resource target, used when an extension targets a resource from another provider namespace + * @template TargetNamespace The provider namespace for the external resource. + * @template ResourceType The type of the external resource. + * @template ResourceParameterName The name of the 'name' parameter of the external resource. + * + * @example + * ```typespec + * alias VirtualMachine = ExternalResource<"Microsoft.Compute", "virtualMachines", "vmName">; + * + * ``` + * + * @example + * ```typespec + * alias Scaleset = Extension.ExternalResource< + * "Microsoft.Compute", + * "virtualMachineScaleSets", + * "scaleSetName" + * >; + * + * @parentResource(Scaleset) + * model VirtualMachineScaleSetVm { + * @visibility(Lifecycle.Read) + * @path + * @segment("virtualMachineScaleSetVms") + * @key("scaleSetVmName") + * @pattern("^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$") + * @doc("Name of the scaleset VM") + * name: string; + * } + * + * ``` + */ @armVirtualResource(TargetNamespace) @Http.Private.includeInapplicableMetadataInPayload(false) model ExternalResource< @@ -127,8 +167,10 @@ model ExternalResource< name: string; } +/** A subscription target for an extension resource */ @builtInSubscriptionResource model Subscription {} +/** A resource group target for an extension resource */ @builtInResourceGroupResource model ResourceGroup {} diff --git a/packages/typespec-azure-resource-manager/src/private.decorators.ts b/packages/typespec-azure-resource-manager/src/private.decorators.ts index 65fb40f2b3..19f39d0804 100644 --- a/packages/typespec-azure-resource-manager/src/private.decorators.ts +++ b/packages/typespec-azure-resource-manager/src/private.decorators.ts @@ -6,6 +6,7 @@ import { ModelProperty, Operation, Program, + StringLiteral, Tuple, Type, addVisibilityModifiers, @@ -61,6 +62,12 @@ import { ArmStateKeys } from "./state.js"; export const namespace = "Azure.ResourceManager.Private"; +const PROVIDER_NAME_CACHE = Symbol.for("Azure.ResourceManager.Private.ProviderNameCache"); + +interface ProviderNameCache { + [PROVIDER_NAME_CACHE]?: Map; +} + /** @internal */ const $builtInResource: BuiltInResourceDecorator = ( @@ -268,16 +275,25 @@ const $assignProviderNameValue: AssignProviderNameValueDecorator = ( resourceType: Model, ) => { const { program } = context; - const details = getArmVirtualResourceDetails(program, resourceType); - const armProviderNamespace = - details?.provider ?? getArmProviderNamespace(program, resourceType as Model); + const armProviderNamespace = getArmProviderNamespace(program, resourceType as Model); if (armProviderNamespace && target.type.kind === "String") { - const targetType = $(program).realm.clone(target.type); - targetType.value = armProviderNamespace; - target.type = targetType; + target.type = createOrGetProviderType(program, armProviderNamespace); } }; +function createOrGetProviderType(program: Program, provider: string): StringLiteral { + const cache = ((program as ProviderNameCache)[PROVIDER_NAME_CACHE] ??= new Map< + string, + StringLiteral + >()); + if (cache.has(provider)) { + return cache.get(provider)!; + } + + const newType = $(program).realm.typekit.literal.createString(provider); + cache.set(provider, newType); + return newType; +} /** * Update the ARM provider namespace for a given entity. * @param {DecoratorContext} context DecoratorContext diff --git a/packages/typespec-azure-resource-manager/src/resource.ts b/packages/typespec-azure-resource-manager/src/resource.ts index d4d4855159..d053d407dd 100644 --- a/packages/typespec-azure-resource-manager/src/resource.ts +++ b/packages/typespec-azure-resource-manager/src/resource.ts @@ -136,9 +136,7 @@ function getProperty( * @returns true if the model or any model it extends is marked as a resource, otherwise false. */ export function isArmVirtualResource(program: Program, target: Model): boolean { - if (program.stateMap(ArmStateKeys.armBuiltInResource).has(target) === true) return true; - if (target.baseModel) return isArmVirtualResource(program, target.baseModel); - return false; + return getArmVirtualResourceDetails(program, target) !== undefined; } /** @@ -150,14 +148,23 @@ export function isArmVirtualResource(program: Program, target: Model): boolean { export function getArmVirtualResourceDetails( program: Program, target: Model, + visited: Set = new Set(), ): ArmVirtualResourceDetails | undefined { + if (visited.has(target)) return undefined; + visited.add(target); if (program.stateMap(ArmStateKeys.armBuiltInResource).has(target)) { return program .stateMap(ArmStateKeys.armBuiltInResource) .get(target) as ArmVirtualResourceDetails; } + if (target.baseModel) { - return getArmVirtualResourceDetails(program, target.baseModel); + const details = getArmVirtualResourceDetails(program, target.baseModel, visited); + if (details) return details; + } + const parent = getParentResource(program, target); + if (parent) { + return getArmVirtualResourceDetails(program, parent, visited); } return undefined; } diff --git a/packages/typespec-azure-resource-manager/src/rules/list-operation.ts b/packages/typespec-azure-resource-manager/src/rules/list-operation.ts index 0042f65174..c95dc2b1a4 100644 --- a/packages/typespec-azure-resource-manager/src/rules/list-operation.ts +++ b/packages/typespec-azure-resource-manager/src/rules/list-operation.ts @@ -19,7 +19,7 @@ export const listBySubscriptionRule = createRule({ for (const armResource of resources) { if (armResource && armResource.operations.lists) { const baseType = getResourceBaseType(context.program, armResource.typespecType); - if (baseType === ResourceBaseType.Extension || baseType === ResourceBaseType.Tenant) { + if (baseType === ResourceBaseType.Tenant) { for (const listOperationName of Object.keys(armResource.operations.lists)) { const listOperation = armResource.operations.lists[listOperationName]; if (listOperation.path.includes("{subscriptionId}")) { diff --git a/packages/typespec-azure-resource-manager/src/state.ts b/packages/typespec-azure-resource-manager/src/state.ts index 4ae43e9d64..4322b67e59 100644 --- a/packages/typespec-azure-resource-manager/src/state.ts +++ b/packages/typespec-azure-resource-manager/src/state.ts @@ -6,6 +6,7 @@ function azureResourceManagerCreateStateSymbol(name: string): symbol { } export const ArmStateKeys = { + armProviderCache: azureResourceManagerCreateStateSymbol("armProviderCache"), armProviderNamespaces: azureResourceManagerCreateStateSymbol("armProviderNamespaces"), armResourceOperations: azureResourceManagerCreateStateSymbol("armResourceOperations"), armResourceCollectionAction: azureResourceManagerCreateStateSymbol("armResourceCollectionAction"), diff --git a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/data-types.md b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/data-types.md index 999ce3744f..7d8de19a20 100644 --- a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/data-types.md +++ b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/data-types.md @@ -2444,13 +2444,16 @@ An internal enum to indicate the resource support for various path types enum Azure.ResourceManager.CommonTypes.ResourceHome ``` -| Name | Value | Description | -| ------------- | ----- | ----------------------------------------- | -| Tenant | | The resource is bound to a tenant | -| Subscription | | The resource is bound to a subscription | -| Location | | The resource is bound to a location | -| ResourceGroup | | The resource is bound to a resource group | -| Extension | | The resource is bound to an extension | +| Name | Value | Description | +| -------------------- | ----- | ----------------------------------------- | +| Tenant | | The resource is bound to a tenant | +| Subscription | | The resource is bound to a subscription | +| Location | | The resource is bound to a location | +| ResourceGroup | | The resource is bound to a resource group | +| Extension | | The resource is bound to an extension | +| BuiltIn | | The resource is built in | +| BuiltInSubscription | | The resource is built in | +| BuiltInResourceGroup | | The resource is built in | ### `Versions` {#Azure.ResourceManager.CommonTypes.Versions} @@ -2625,6 +2628,269 @@ Type of managed service identity (either system assigned, or none). union Azure.ResourceManager.CommonTypes.SystemAssignedServiceIdentityType ``` +## Azure.ResourceManager.Extension + +### `ExtensionInstanceParameters` {#Azure.ResourceManager.Extension.ExtensionInstanceParameters} + +The path parameters for an extension resource at the given target + +```typespec +model Azure.ResourceManager.Extension.ExtensionInstanceParameters +``` + +#### Template Parameters + +| Name | Description | +| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| TargetResource | The target of the extension resource (Extension.Tenant, Extension.Subscription, Extension.ResourceGroup, Extension.Scope, Extension.ManagementGroup or another resource). | +| Resource | The extension resource. | + +#### Properties + +| Name | Type | Description | +| ----------------- | -------------------------------- | ------------------------------------------------------------- | +| apiVersion | `string` | The API version to use for this operation. | +| subscriptionId | `Core.uuid` | The ID of the target subscription. The value must be an UUID. | +| resourceGroupName | `string` | The name of the resource group. The name is case insensitive. | +| provider | `"Microsoft.ThisWillBeReplaced"` | | +| extensionProvider | `"Microsoft.ThisWillBeReplaced"` | | + +### `ExtensionParentParameters` {#Azure.ResourceManager.Extension.ExtensionParentParameters} + +The path parameters for a collection of extension resources at the given target + +```typespec +model Azure.ResourceManager.Extension.ExtensionParentParameters +``` + +#### Template Parameters + +| Name | Description | +| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| TargetResource | The target of the extension resource (Extension.Tenant, Extension.Subscription, Extension.ResourceGroup, Extension.Scope, Extension.ManagementGroup or another resource). | +| ExtensionResource | The extension resource. | + +#### Properties + +| Name | Type | Description | +| ----------------- | -------------------------------- | ------------------------------------------------------------- | +| apiVersion | `string` | The API version to use for this operation. | +| subscriptionId | `Core.uuid` | The ID of the target subscription. The value must be an UUID. | +| resourceGroupName | `string` | The name of the resource group. The name is case insensitive. | +| provider | `"Microsoft.ThisWillBeReplaced"` | | +| extensionProvider | `"Microsoft.ThisWillBeReplaced"` | | + +### `ExtensionProviderNamespace` {#Azure.ResourceManager.Extension.ExtensionProviderNamespace} + +The provider namespace for an extension resource + +```typespec +model Azure.ResourceManager.Extension.ExtensionProviderNamespace +``` + +#### Template Parameters + +| Name | Description | +| -------- | ---------------------------- | +| Resource | The extension resource model | + +#### Properties + +| Name | Type | Description | +| ----------------- | -------------------------------- | ----------- | +| extensionProvider | `"Microsoft.ThisWillBeReplaced"` | | + +### `ExternalResource` {#Azure.ResourceManager.Extension.ExternalResource} + +An external resource target, used when an extension targets a resource from another provider namespace + +```typespec +model Azure.ResourceManager.Extension.ExternalResource +``` + +#### Template Parameters + +| Name | Description | +| --------------------- | ---------------------------------------------------------- | +| TargetNamespace | The provider namespace for the external resource. | +| ResourceType | The type of the external resource. | +| ResourceParameterName | The name of the 'name' parameter of the external resource. | + +#### Examples + +```typespec +alias VirtualMachine = ExternalResource<"Microsoft.Compute", "virtualMachines", "vmName">; +``` + +```typespec +alias Scaleset = Extension.ExternalResource< + "Microsoft.Compute", + "virtualMachineScaleSets", + "scaleSetName" +>; + +@parentResource(Scaleset) +model VirtualMachineScaleSetVm { + @visibility(Lifecycle.Read) + @path + @segment("virtualMachineScaleSetVms") + @key("scaleSetVmName") + @pattern("^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$") + @doc("Name of the scaleset VM") + name: string; +} +``` + +#### Properties + +| Name | Type | Description | +| ---- | -------- | ------------------------------- | +| name | `string` | The name of the virtual machine | + +### `ManagementGroup` {#Azure.ResourceManager.Extension.ManagementGroup} + +A management group + +```typespec +model Azure.ResourceManager.Extension.ManagementGroup +``` + +#### Template Parameters + +| Name | Description | +| ------------- | ------------------------------------------------------------------------------------------------------------ | +| ParameterName | The name of the 'name' parameter of the management group (usually managementGroupName or managementGroupId). | + +#### Properties + +| Name | Type | Description | +| ---- | -------- | ----------- | +| name | `string` | | + +### `ResourceGroup` {#Azure.ResourceManager.Extension.ResourceGroup} + +A resource group target for an extension resource + +```typespec +model Azure.ResourceManager.Extension.ResourceGroup +``` + +#### Properties + +None + +### `ScopeParameter` {#Azure.ResourceManager.Extension.ScopeParameter} + +The default scope parameter for an extension resource. + +```typespec +model Azure.ResourceManager.Extension.ScopeParameter +``` + +#### Examples + +```typespec +model Employee { + ...ResourceUriParameter; +} +``` + +#### Properties + +| Name | Type | Description | +| ----- | -------- | ---------------------------------------------------------------------- | +| scope | `string` | The fully qualified Azure Resource manager identifier of the resource. | + +### `Subscription` {#Azure.ResourceManager.Extension.Subscription} + +A subscription target for an extension resource + +```typespec +model Azure.ResourceManager.Extension.Subscription +``` + +#### Properties + +None + +### `TargetBaseParameters` {#Azure.ResourceManager.Extension.TargetBaseParameters} + +Base parameters for an extension target. + +```typespec +model Azure.ResourceManager.Extension.TargetBaseParameters +``` + +#### Template Parameters + +| Name | Description | +| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Resource | The resource model for an extension target (usually Extension.Tenant, Extension.Subscription, Extension.ResourceGroup, Extension.Scope, Extension.ManagementGroup or an external resource). | + +#### Properties + +| Name | Type | Description | +| ----------------- | -------------------------------- | ------------------------------------------------------------- | +| apiVersion | `string` | The API version to use for this operation. | +| subscriptionId | `Core.uuid` | The ID of the target subscription. The value must be an UUID. | +| resourceGroupName | `string` | The name of the resource group. The name is case insensitive. | +| provider | `"Microsoft.ThisWillBeReplaced"` | | + +### `TargetParameters` {#Azure.ResourceManager.Extension.TargetParameters} + +The path parameters for a target resource for an extension + +```typespec +model Azure.ResourceManager.Extension.TargetParameters +``` + +#### Template Parameters + +| Name | Description | +| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Resource | The resource model for an extension target (usually Extension.Tenant, Extension.Subscription, Extension.ResourceGroup, Extension.Scope, Extension.ManagementGroup or an external resource). | + +#### Properties + +| Name | Type | Description | +| ----------------- | -------------------------------- | ------------------------------------------------------------- | +| apiVersion | `string` | The API version to use for this operation. | +| subscriptionId | `Core.uuid` | The ID of the target subscription. The value must be an UUID. | +| resourceGroupName | `string` | The name of the resource group. The name is case insensitive. | +| provider | `"Microsoft.ThisWillBeReplaced"` | | + +### `TargetProviderNamespace` {#Azure.ResourceManager.Extension.TargetProviderNamespace} + +The provider namespace (if any) for a target resource for an extension + +```typespec +model Azure.ResourceManager.Extension.TargetProviderNamespace +``` + +#### Template Parameters + +| Name | Description | +| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Resource | The resource model for an extension target (usually Extension.Tenant, Extension.Subscription, Extension.ResourceGroup, Extension.Scope, Extension.ManagementGroup or an external resource) | + +#### Properties + +| Name | Type | Description | +| -------- | -------------------------------- | ----------- | +| provider | `"Microsoft.ThisWillBeReplaced"` | | + +### `Tenant` {#Azure.ResourceManager.Extension.Tenant} + +A tenant target for the extension resource + +```typespec +model Azure.ResourceManager.Extension.Tenant +``` + +#### Properties + +None + ## Azure.ResourceManager.Foundations ### `ArmTagsProperty` {#Azure.ResourceManager.Foundations.ArmTagsProperty} diff --git a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/decorators.md b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/decorators.md index 94e8760657..bff0f8aa3c 100644 --- a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/decorators.md +++ b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/decorators.md @@ -239,7 +239,7 @@ This decorator is used on Azure Resource Manager resources that are not based on Azure.ResourceManager common types. ```typespec -@Azure.ResourceManager.armVirtualResource +@Azure.ResourceManager.armVirtualResource(provider?: valueof string) ``` #### Target @@ -248,7 +248,9 @@ Azure.ResourceManager common types. #### Parameters -None +| Name | Type | Description | +| -------- | ---------------- | ----------- | +| provider | `valueof string` | | ### `@extensionResource` {#@Azure.ResourceManager.extensionResource} diff --git a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx index 7b59c2b2d9..83d303fbd6 100644 --- a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx +++ b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx @@ -30,6 +30,8 @@ npm install --save-peer @azure-tools/typespec-azure-resource-manager ## Azure +## Azure.resourceManager + ## Azure.ResourceManager ### Decorators @@ -238,6 +240,45 @@ npm install --save-peer @azure-tools/typespec-azure-resource-manager - [`UserAssignedIdentities`](./data-types.md#Azure.ResourceManager.CommonTypes.UserAssignedIdentities) - [`UserAssignedIdentity`](./data-types.md#Azure.ResourceManager.CommonTypes.UserAssignedIdentity) +## Azure.resourceManager.Extension + +## Azure.ResourceManager.Extension + +### Operations + +- [`ActionAsync`](./interfaces.md#Azure.ResourceManager.Extension.ActionAsync) +- [`ActionAsyncBase`](./interfaces.md#Azure.ResourceManager.Extension.ActionAsyncBase) +- [`ActionNoContentSync`](./interfaces.md#Azure.ResourceManager.Extension.ActionNoContentSync) +- [`ActionNoResponseContentAsync`](./interfaces.md#Azure.ResourceManager.Extension.ActionNoResponseContentAsync) +- [`ActionSync`](./interfaces.md#Azure.ResourceManager.Extension.ActionSync) +- [`CheckExistence`](./interfaces.md#Azure.ResourceManager.Extension.CheckExistence) +- [`CreateOrReplaceAsync`](./interfaces.md#Azure.ResourceManager.Extension.CreateOrReplaceAsync) +- [`CreateOrReplaceSync`](./interfaces.md#Azure.ResourceManager.Extension.CreateOrReplaceSync) +- [`CreateOrUpdateAsync`](./interfaces.md#Azure.ResourceManager.Extension.CreateOrUpdateAsync) +- [`CustomPatchAsync`](./interfaces.md#Azure.ResourceManager.Extension.CustomPatchAsync) +- [`CustomPatchSync`](./interfaces.md#Azure.ResourceManager.Extension.CustomPatchSync) +- [`DeleteAsync`](./interfaces.md#Azure.ResourceManager.Extension.DeleteAsync) +- [`DeleteAsyncBase`](./interfaces.md#Azure.ResourceManager.Extension.DeleteAsyncBase) +- [`DeleteSync`](./interfaces.md#Azure.ResourceManager.Extension.DeleteSync) +- [`DeleteWithoutOkAsync`](./interfaces.md#Azure.ResourceManager.Extension.DeleteWithoutOkAsync) +- [`ListByTarget`](./interfaces.md#Azure.ResourceManager.Extension.ListByTarget) +- [`Read`](./interfaces.md#Azure.ResourceManager.Extension.Read) + +### Models + +- [`ExtensionInstanceParameters`](./data-types.md#Azure.ResourceManager.Extension.ExtensionInstanceParameters) +- [`ExtensionParentParameters`](./data-types.md#Azure.ResourceManager.Extension.ExtensionParentParameters) +- [`ExtensionProviderNamespace`](./data-types.md#Azure.ResourceManager.Extension.ExtensionProviderNamespace) +- [`ExternalResource`](./data-types.md#Azure.ResourceManager.Extension.ExternalResource) +- [`ManagementGroup`](./data-types.md#Azure.ResourceManager.Extension.ManagementGroup) +- [`ResourceGroup`](./data-types.md#Azure.ResourceManager.Extension.ResourceGroup) +- [`ScopeParameter`](./data-types.md#Azure.ResourceManager.Extension.ScopeParameter) +- [`Subscription`](./data-types.md#Azure.ResourceManager.Extension.Subscription) +- [`TargetBaseParameters`](./data-types.md#Azure.ResourceManager.Extension.TargetBaseParameters) +- [`TargetParameters`](./data-types.md#Azure.ResourceManager.Extension.TargetParameters) +- [`TargetProviderNamespace`](./data-types.md#Azure.ResourceManager.Extension.TargetProviderNamespace) +- [`Tenant`](./data-types.md#Azure.ResourceManager.Extension.Tenant) + ## Azure.ResourceManager.Foundations ### Operations diff --git a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/interfaces.md b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/interfaces.md index 654d8ea463..ef3e93b865 100644 --- a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/interfaces.md +++ b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/interfaces.md @@ -1127,6 +1127,323 @@ op Azure.ResourceManager.checkLocalNameAvailability(apiVersion: string, subscrip | Response | the availability response, default to the standard response | | AdditionalParams | A model specifying additional non-path parameters to the availability request | +## Azure.ResourceManager.Extension + +### `ActionAsync` {#Azure.ResourceManager.Extension.ActionAsync} + +```typespec +op Azure.ResourceManager.Extension.ActionAsync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced", body: Request): Azure.ResourceManager.ArmAcceptedLroResponse | Response | Error +``` + +#### Template Parameters + +| Name | Description | +| ------------------- | -------------------------------------------------------------------------------------------------------- | +| TargetResource | The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup | +| ExtensionResource | The resource being acted upon | +| Request | The request model for the action | +| Response | The response model for the action | +| LroHeaders | Optional. Allows overriding the headers returned in the Accepted response | +| Parameters | Optional. Additional parameters after the path parameters | +| Error | Optional. The error response, if non-standard. | +| OptionalRequestBody | Optional. Indicates whether the body parameter is optional. | + +### `ActionAsyncBase` {#Azure.ResourceManager.Extension.ActionAsyncBase} + +A long-running resource action. + +```typespec +op Azure.ResourceManager.Extension.ActionAsyncBase(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced", body: Request): Response | Error +``` + +#### Template Parameters + +| Name | Description | +| ------------------- | -------------------------------------------------------------------------------------------------------- | +| TargetResource | The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup | +| ExtensionResource | The resource being acted upon | +| Request | The request model for the action | +| Response | The response type for the action | +| Parameters | Optional. Additional parameters after the path parameters | +| Error | Optional. The error response, if non-standard. | +| OptionalRequestBody | Optional. Indicates whether the request body is optional. | + +### `ActionNoContentSync` {#Azure.ResourceManager.Extension.ActionNoContentSync} + +A synchronous resource action that returns no content. + +```typespec +op Azure.ResourceManager.Extension.ActionNoContentSync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced", body: Request): Azure.ResourceManager.ArmNoContentResponse<"Action completed successfully."> | Error +``` + +#### Template Parameters + +| Name | Description | +| ------------------- | -------------------------------------------------------------------------------------------------------- | +| TargetResource | The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup | +| ExtensionResource | The resource being acted upon | +| Request | The request model for the action | +| Parameters | Optional. Additional parameters after the path parameters | +| Error | Optional. The error response, if non-standard. | +| OptionalRequestBody | Optional. Indicates whether the request body is optional. | + +### `ActionNoResponseContentAsync` {#Azure.ResourceManager.Extension.ActionNoResponseContentAsync} + +```typespec +op Azure.ResourceManager.Extension.ActionNoResponseContentAsync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced", body: Request): Azure.ResourceManager.ArmAcceptedLroResponse | Error +``` + +#### Template Parameters + +| Name | Description | +| ------------------- | -------------------------------------------------------------------------------------------------------- | +| TargetResource | The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup | +| ExtensionResource | The resource being acted upon | +| Request | The request model for the action | +| LroHeaders | Optional. Allows overriding the headers returned in the Accepted response | +| Parameters | Optional. Additional parameters after the path parameters | +| Error | Optional. The error response, if non-standard. | +| OptionalRequestBody | Optional. Indicates whether the body parameter is optional. | + +### `ActionSync` {#Azure.ResourceManager.Extension.ActionSync} + +A synchronous resource action. + +```typespec +op Azure.ResourceManager.Extension.ActionSync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced", body: Request): Response | Error +``` + +#### Template Parameters + +| Name | Description | +| ------------------- | -------------------------------------------------------------------------------------------------------- | +| TargetResource | The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup | +| ExtensionResource | The resource being acted upon | +| Request | The request model for the action | +| Response | The response model for the action | +| Parameters | Optional. Additional parameters after the path parameters | +| Error | Optional. The error response, if non-standard. | +| OptionalRequestBody | Optional. Indicates whether the body parameter is optional. | + +### `CheckExistence` {#Azure.ResourceManager.Extension.CheckExistence} + +Check a resource's existence via HEAD operation + +```typespec +op Azure.ResourceManager.Extension.CheckExistence(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced"): Response | Error +``` + +#### Template Parameters + +| Name | Description | +| ----------------- | -------------------------------------------------------------------------------------------------------- | +| TargetResource | The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup | +| ExtensionResource | the extension resource being checked | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | Optional. The success response for the read operation | +| Error | Optional. The error response, if non-standard. | + +### `CreateOrReplaceAsync` {#Azure.ResourceManager.Extension.CreateOrReplaceAsync} + +```typespec +op Azure.ResourceManager.Extension.CreateOrReplaceAsync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced", resource: ExtensionResource): Response | Error +``` + +#### Template Parameters + +| Name | Description | +| ----------------- | -------------------------------------------------------------------------------------------------------- | +| TargetResource | the target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup | +| ExtensionResource | the resource being created or replaced | +| LroHeaders | Optional. Allows overriding the lro headers returned on resource create | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | Optional. The success response for the createOrReplace operation | +| Error | Optional. The error response, if non-standard. | + +### `CreateOrReplaceSync` {#Azure.ResourceManager.Extension.CreateOrReplaceSync} + +Synchronous PUT operation for Azure Resource Manager resources + +```typespec +op Azure.ResourceManager.Extension.CreateOrReplaceSync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced", resource: ExtensionResource): Response | Error +``` + +#### Template Parameters + +| Name | Description | +| ----------------- | -------------------------------------------------------------------------------------------------------- | +| TargetResource | the target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup | +| ExtensionResource | the resource being created or replaced | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | Optional. The success response for the createOrUpdate operation | +| Error | Optional. The error response, if non-standard. | + +### `CreateOrUpdateAsync` {#Azure.ResourceManager.Extension.CreateOrUpdateAsync} + +A long-running resource CreateOrUpdate (PUT) + +```typespec +op Azure.ResourceManager.Extension.CreateOrUpdateAsync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced", resource: ExtensionResource): Response | Error +``` + +#### Template Parameters + +| Name | Description | +| ----------------- | -------------------------------------------------------------------------------------------------------- | +| TargetResource | the target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup | +| ExtensionResource | the resource being created or updated | +| LroHeaders | Optional. Allows overriding the lro headers returned on resource create | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | Optional. The success response for the createOrUpdate operation | +| Error | Optional. The error response, if non-standard. | + +### `CustomPatchAsync` {#Azure.ResourceManager.Extension.CustomPatchAsync} + +A long-running resource update using a custom PATCH payload (Asynchronous) + +```typespec +op Azure.ResourceManager.Extension.CustomPatchAsync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced", properties: PatchModel): Response | Error +``` + +#### Template Parameters + +| Name | Description | +| ----------------- | -------------------------------------------------------------------------------------------------------- | +| TargetResource | the target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup | +| ExtensionResource | the resource being patched | +| PatchModel | The input model for the PATCH request | +| LroHeaders | Optional. Allows overriding the lro headers returned in the Accepted response | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | Optional. The success response for the patch operation | +| Error | Optional. The error response, if non-standard. | + +### `CustomPatchSync` {#Azure.ResourceManager.Extension.CustomPatchSync} + +A resource update using a custom PATCH payload (synchronous) + +```typespec +op Azure.ResourceManager.Extension.CustomPatchSync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced", properties: PatchModel): Response | Error +``` + +#### Template Parameters + +| Name | Description | +| ----------------- | -------------------------------------------------------------------------------------------------------- | +| TargetResource | the target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup | +| ExtensionResource | the resource being patched | +| PatchModel | The input model for the PATCH request | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | Optional. The success response for the patch operation | +| Error | Optional. The error response, if non-standard. | + +### `DeleteAsync` {#Azure.ResourceManager.Extension.DeleteAsync} + +:::caution +**Deprecated**: Use 'DeleteWithoutOkAsync' instead +::: + +```typespec +op Azure.ResourceManager.Extension.DeleteAsync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced"): Response | Error +``` + +#### Template Parameters + +| Name | Description | +| ----------------- | -------------------------------------------------------------------------------------------------------- | +| TargetResource | The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup | +| ExtensionResource | The resource being deleted | +| LroHeaders | Optional. Allows overriding the headers in the Accepted response | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | Optional. The success response(s) for the delete operation | +| Error | Optional. The error response, if non-standard. | + +### `DeleteAsyncBase` {#Azure.ResourceManager.Extension.DeleteAsyncBase} + +```typespec +op Azure.ResourceManager.Extension.DeleteAsyncBase(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced"): Response | Error +``` + +#### Template Parameters + +| Name | Description | +| ----------------- | -------------------------------------------------------------------------------------------------------- | +| TargetResource | The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup | +| ExtensionResource | The resource being deleted | +| Response | The response type for the operation | +| Parameters | Optional. Additional parameters after the path parameters | +| Error | Optional. The error response, if non-standard. | + +### `DeleteSync` {#Azure.ResourceManager.Extension.DeleteSync} + +Delete a resource synchronously + +```typespec +op Azure.ResourceManager.Extension.DeleteSync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced"): Response | Error +``` + +#### Template Parameters + +| Name | Description | +| ----------------- | -------------------------------------------------------------------------------------------------------- | +| TargetResource | The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup | +| ExtensionResource | The resource being deleted | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | Optional. The success response(s) for the delete operation | +| Error | Optional. The error response, if non-standard. | + +### `DeleteWithoutOkAsync` {#Azure.ResourceManager.Extension.DeleteWithoutOkAsync} + +```typespec +op Azure.ResourceManager.Extension.DeleteWithoutOkAsync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced"): Response | Error +``` + +#### Template Parameters + +| Name | Description | +| ----------------- | -------------------------------------------------------------------------------------------------------- | +| TargetResource | The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup | +| ExtensionResource | The resource being deleted | +| LroHeaders | Optional. Allows overriding the headers returned in the Accepted response | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | Optional. The success response(s) for the delete operation | +| Error | Optional. The error response, if non-standard. | + +### `ListByTarget` {#Azure.ResourceManager.Extension.ListByTarget} + +List an extension resource at the given target scope + +```typespec +op Azure.ResourceManager.Extension.ListByTarget(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced"): Response | Error +``` + +#### Template Parameters + +| Name | Description | +| ----------------- | ---------------------------------------------------------------------------------------------------------- | +| TargetResource | The target to list at, e.g. Extension.Subscription or Extension>ManagementGroup or Extension.ResourceGroup | +| ExtensionResource | the resource being listed | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | Optional. The success response for the list operation | +| Error | Optional. The error response, if non-standard. | + +### `Read` {#Azure.ResourceManager.Extension.Read} + +A resource GET operation + +```typespec +op Azure.ResourceManager.Extension.Read(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced"): Response | Error +``` + +#### Template Parameters + +| Name | Description | +| ----------------- | -------------------------------------------------------------------------------------------------------- | +| TargetResource | The target resource, e.g. Extension.Subscription or Extension.ManagementGroup or Extension.ResourceGroup | +| ExtensionResource | the resource being rea | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | Optional. The success response for the read operation | +| Error | Optional. The error response, if non-standard. | + ## Azure.ResourceManager.Foundations ### `ArmCreateOperation` {#Azure.ResourceManager.Foundations.ArmCreateOperation} From 23d65f8cd446a309a3af8821da0e2ff6e676472f Mon Sep 17 00:00:00 2001 From: Mark Cowlishaw Date: Tue, 24 Jun 2025 15:38:21 -0700 Subject: [PATCH 07/16] Update templates, docs, and sample --- .../specific-extension/main.tsp | 33 +++---- .../2021-10-01-preview/openapi.json | 75 ++++++++-------- .../lib/extension/parameters.tsp | 81 +++++++++++++---- .../src/private.decorators.ts | 15 +--- .../reference/data-types.md | 89 ++++++++++++++----- .../reference/index.mdx | 1 + 6 files changed, 185 insertions(+), 109 deletions(-) diff --git a/packages/samples/specs/resource-manager/resource-types/specific-extension/main.tsp b/packages/samples/specs/resource-manager/resource-types/specific-extension/main.tsp index e582ab7c58..1384362506 100644 --- a/packages/samples/specs/resource-manager/resource-types/specific-extension/main.tsp +++ b/packages/samples/specs/resource-manager/resource-types/specific-extension/main.tsp @@ -3,8 +3,6 @@ import "@typespec/versioning"; import "@azure-tools/typespec-azure-core"; import "@azure-tools/typespec-azure-resource-manager"; -using Http; -using Rest; using Versioning; using Azure.Core; using Azure.ResourceManager; @@ -82,24 +80,29 @@ interface EmplOps; +alias VirtualMachine = Extension.ExternalResource< + "Microsoft.Compute", + "virtualMachines", + "vmName", + NamePattern = "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$", + Description = "The name of the virtual machine" +>; alias Scaleset = Extension.ExternalResource< "Microsoft.Compute", "virtualMachineScaleSets", - "scaleSetName" + "scaleSetName", + NamePattern = "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$", + Description = "The name of the virtual machine scale set" +>; + +alias VirtualMachineScaleSetVm = Extension.ExternalChildResource< + Scaleset, + "virtualMachineScaleSetVms", + "scaleSetVmName", + NamePattern = "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$", + Description = "The name of the virtual machine scale set VM" >; -/** A scaleset VM */ -@parentResource(Scaleset) -model VirtualMachineScaleSetVm { - /** Name of the scaleset VM */ - @visibility(Lifecycle.Read) - @path - @segment("virtualMachineScaleSetVms") - @key("scaleSetVmName") - @pattern("^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$") - name: string; -} @armResourceOperations interface Employees extends EmplOps {} diff --git a/packages/samples/test/output/azure/resource-manager/resource-types/specific-extension/@azure-tools/typespec-autorest/2021-10-01-preview/openapi.json b/packages/samples/test/output/azure/resource-manager/resource-types/specific-extension/@azure-tools/typespec-autorest/2021-10-01-preview/openapi.json index 057fe13f43..16907dc61a 100644 --- a/packages/samples/test/output/azure/resource-manager/resource-types/specific-extension/@azure-tools/typespec-autorest/2021-10-01-preview/openapi.json +++ b/packages/samples/test/output/azure/resource-manager/resource-types/specific-extension/@azure-tools/typespec-autorest/2021-10-01-preview/openapi.json @@ -1302,14 +1302,15 @@ { "name": "scaleSetName", "in": "path", - "description": "The name of the virtual machine", + "description": "The name of the virtual machine scale set", "required": true, - "type": "string" + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" }, { "name": "scaleSetVmName", "in": "path", - "description": "Name of the scaleset VM", + "description": "The name of the virtual machine scale set VM", "required": true, "type": "string", "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" @@ -1354,14 +1355,15 @@ { "name": "scaleSetName", "in": "path", - "description": "The name of the virtual machine", + "description": "The name of the virtual machine scale set", "required": true, - "type": "string" + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" }, { "name": "scaleSetVmName", "in": "path", - "description": "Name of the scaleset VM", + "description": "The name of the virtual machine scale set VM", "required": true, "type": "string", "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" @@ -1409,14 +1411,15 @@ { "name": "scaleSetName", "in": "path", - "description": "The name of the virtual machine", + "description": "The name of the virtual machine scale set", "required": true, - "type": "string" + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" }, { "name": "scaleSetVmName", "in": "path", - "description": "Name of the scaleset VM", + "description": "The name of the virtual machine scale set VM", "required": true, "type": "string", "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" @@ -1494,14 +1497,15 @@ { "name": "scaleSetName", "in": "path", - "description": "The name of the virtual machine", + "description": "The name of the virtual machine scale set", "required": true, - "type": "string" + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" }, { "name": "scaleSetVmName", "in": "path", - "description": "Name of the scaleset VM", + "description": "The name of the virtual machine scale set VM", "required": true, "type": "string", "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" @@ -1558,14 +1562,15 @@ { "name": "scaleSetName", "in": "path", - "description": "The name of the virtual machine", + "description": "The name of the virtual machine scale set", "required": true, - "type": "string" + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" }, { "name": "scaleSetVmName", "in": "path", - "description": "Name of the scaleset VM", + "description": "The name of the virtual machine scale set VM", "required": true, "type": "string", "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" @@ -1630,14 +1635,15 @@ { "name": "scaleSetName", "in": "path", - "description": "The name of the virtual machine", + "description": "The name of the virtual machine scale set", "required": true, - "type": "string" + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" }, { "name": "scaleSetVmName", "in": "path", - "description": "Name of the scaleset VM", + "description": "The name of the virtual machine scale set VM", "required": true, "type": "string", "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" @@ -1698,7 +1704,8 @@ "in": "path", "description": "The name of the virtual machine", "required": true, - "type": "string" + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" } ], "responses": { @@ -1742,7 +1749,8 @@ "in": "path", "description": "The name of the virtual machine", "required": true, - "type": "string" + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" }, { "name": "employeeName", @@ -1789,7 +1797,8 @@ "in": "path", "description": "The name of the virtual machine", "required": true, - "type": "string" + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" }, { "name": "employeeName", @@ -1866,7 +1875,8 @@ "in": "path", "description": "The name of the virtual machine", "required": true, - "type": "string" + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" }, { "name": "employeeName", @@ -1922,7 +1932,8 @@ "in": "path", "description": "The name of the virtual machine", "required": true, - "type": "string" + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" }, { "name": "employeeName", @@ -1986,7 +1997,8 @@ "in": "path", "description": "The name of the virtual machine", "required": true, - "type": "string" + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$" }, { "name": "employeeName", @@ -2506,21 +2518,6 @@ ] }, "readOnly": true - }, - "VirtualMachineScaleSetVm": { - "type": "object", - "description": "A scaleset VM", - "properties": { - "name": { - "type": "string", - "description": "Name of the scaleset VM", - "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$", - "readOnly": true - } - }, - "required": [ - "name" - ] } }, "parameters": {} diff --git a/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp b/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp index c68ae9c40c..3e5d4ca428 100644 --- a/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp +++ b/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp @@ -8,6 +8,7 @@ using Azure.ResourceManager.CommonTypes; /** * The default scope parameter for an extension resource. + * @template Type The type of the scope parameter (default is string). This can be used to specify `Azure.Core.armResourceIdentifier` type or other constrained type * * @example * ```typespec @@ -17,11 +18,11 @@ using Azure.ResourceManager.CommonTypes; * ``` */ @builtInResource -model ScopeParameter { +model ScopeParameter { @path(#{ allowReserved: true }) @key @doc("The fully qualified Azure Resource manager identifier of the resource.") - scope: string; + scope: Type; } /** @@ -124,6 +125,9 @@ model ManagementGroup; - * - * @parentResource(Scaleset) - * model VirtualMachineScaleSetVm { - * @visibility(Lifecycle.Read) - * @path - * @segment("virtualMachineScaleSetVms") - * @key("scaleSetVmName") - * @pattern("^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$") - * @doc("Name of the scaleset VM") - * name: string; - * } - * + * ``` */ +@doc("") @armVirtualResource(TargetNamespace) @Http.Private.includeInapplicableMetadataInPayload(false) model ExternalResource< TargetNamespace extends valueof string, ResourceType extends valueof string, - ResourceParameterName extends valueof string + ResourceParameterName extends valueof string, + NamePattern extends valueof string = "", + NameType extends string = string, + Description extends valueof string = "The name of the resource" > { - /** The name of the virtual machine */ + @doc(Description) @visibility(Lifecycle.Read) @path @key(ResourceParameterName) @segment(ResourceType) - name: string; + @pattern(NamePattern) + name: NameType; } +/** An external child resource target, used when an extension targets a child resource from another provider namespace + * @template ParentModel The parent of this resource. + * @template ResourceType The type of this resource. + * @template ResourceParameterName The name of the 'name' parameter of this resource. + * @template NamePattern The pattern restriction for the name of this resource (default is none). + * @template NameType The type of the name parameter of this resource (default is string). + * @template Description The description of the name parameter of this resource (default is "The name of the resource"). + * + * @example + * ```typespec + * alias VirtualMachine = ExternalResource<"Microsoft.Compute", "virtualMachines", "vmName">; + * + * ``` + * + * @example + * ```typespec + * alias Scaleset = Extension.ExternalResource< + * "Microsoft.Compute", + * "virtualMachineScaleSets", + * "scaleSetName" + * >; + * + * alias VirtualMachineScaleSetVm = Extension.ExternalChildResource< + * Scaleset, + * "virtualMachineScaleSetVms", + * "scaleSetVmName" + * >; + * + * ``` + */ +@doc("") +@parentResource(ParentModel) +@Http.Private.includeInapplicableMetadataInPayload(false) +model ExternalChildResource< + ParentModel extends {}, + ResourceType extends valueof string, + ResourceParameterName extends valueof string, + NamePattern extends valueof string = "", + NameType extends string = string, + Description extends valueof string = "The name of the resource" +> { + @doc(Description) + @visibility(Lifecycle.Read) + @path + @key(ResourceParameterName) + @segment(ResourceType) + @pattern(NamePattern) + name: NameType; +} /** A subscription target for an extension resource */ @builtInSubscriptionResource model Subscription {} diff --git a/packages/typespec-azure-resource-manager/src/private.decorators.ts b/packages/typespec-azure-resource-manager/src/private.decorators.ts index 19f39d0804..1cc3487d4d 100644 --- a/packages/typespec-azure-resource-manager/src/private.decorators.ts +++ b/packages/typespec-azure-resource-manager/src/private.decorators.ts @@ -277,23 +277,10 @@ const $assignProviderNameValue: AssignProviderNameValueDecorator = ( const { program } = context; const armProviderNamespace = getArmProviderNamespace(program, resourceType as Model); if (armProviderNamespace && target.type.kind === "String") { - target.type = createOrGetProviderType(program, armProviderNamespace); + target.type = $(program).literal.createString(armProviderNamespace); } }; -function createOrGetProviderType(program: Program, provider: string): StringLiteral { - const cache = ((program as ProviderNameCache)[PROVIDER_NAME_CACHE] ??= new Map< - string, - StringLiteral - >()); - if (cache.has(provider)) { - return cache.get(provider)!; - } - - const newType = $(program).realm.typekit.literal.createString(provider); - cache.set(provider, newType); - return newType; -} /** * Update the ARM provider namespace for a given entity. * @param {DecoratorContext} context DecoratorContext diff --git a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/data-types.md b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/data-types.md index 7d8de19a20..9dffd4c5eb 100644 --- a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/data-types.md +++ b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/data-types.md @@ -2700,21 +2700,67 @@ model Azure.ResourceManager.Extension.ExtensionProviderNamespace | ----------------- | -------------------------------- | ----------- | | extensionProvider | `"Microsoft.ThisWillBeReplaced"` | | +### `ExternalChildResource` {#Azure.ResourceManager.Extension.ExternalChildResource} + +An external child resource target, used when an extension targets a child resource from another provider namespace + +```typespec +model Azure.ResourceManager.Extension.ExternalChildResource +``` + +#### Template Parameters + +| Name | Description | +| --------------------- | ------------------------------------------------------------------------ | +| ParentModel | The parent of this resource. | +| ResourceType | The type of this resource. | +| ResourceParameterName | The name of the 'name' parameter of this resource. | +| NamePattern | The pattern restriction for the name of this resource (default is none). | +| NameType | The type of the name parameter of this resource (default is string). | + +#### Examples + +```typespec +alias VirtualMachine = ExternalResource<"Microsoft.Compute", "virtualMachines", "vmName">; +``` + +```typespec +alias Scaleset = Extension.ExternalResource< + "Microsoft.Compute", + "virtualMachineScaleSets", + "scaleSetName" +>; + +alias VirtualMachineScaleSetVm = Extension.ExternalChildResource< + Scaleset, + "virtualMachineScaleSetVms", + "scaleSetVmName" +>; +``` + +#### Properties + +| Name | Type | Description | +| ---- | ---------- | ------------------------ | +| name | `NameType` | The name of the resource | + ### `ExternalResource` {#Azure.ResourceManager.Extension.ExternalResource} An external resource target, used when an extension targets a resource from another provider namespace ```typespec -model Azure.ResourceManager.Extension.ExternalResource +model Azure.ResourceManager.Extension.ExternalResource ``` #### Template Parameters -| Name | Description | -| --------------------- | ---------------------------------------------------------- | -| TargetNamespace | The provider namespace for the external resource. | -| ResourceType | The type of the external resource. | -| ResourceParameterName | The name of the 'name' parameter of the external resource. | +| Name | Description | +| --------------------- | -------------------------------------------------------------------------------- | +| TargetNamespace | The provider namespace for the external resource. | +| ResourceType | The type of the external resource. | +| ResourceParameterName | The name of the 'name' parameter of the external resource. | +| NamePattern | The pattern restriction for the name of the external resource (default is none). | +| NameType | The type of the name parameter of the external resource (default is string). | #### Examples @@ -2728,24 +2774,13 @@ alias Scaleset = Extension.ExternalResource< "virtualMachineScaleSets", "scaleSetName" >; - -@parentResource(Scaleset) -model VirtualMachineScaleSetVm { - @visibility(Lifecycle.Read) - @path - @segment("virtualMachineScaleSetVms") - @key("scaleSetVmName") - @pattern("^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$") - @doc("Name of the scaleset VM") - name: string; -} ``` #### Properties -| Name | Type | Description | -| ---- | -------- | ------------------------------- | -| name | `string` | The name of the virtual machine | +| Name | Type | Description | +| ---- | ---------- | ------------------------ | +| name | `NameType` | The name of the resource | ### `ManagementGroup` {#Azure.ResourceManager.Extension.ManagementGroup} @@ -2784,9 +2819,15 @@ None The default scope parameter for an extension resource. ```typespec -model Azure.ResourceManager.Extension.ScopeParameter +model Azure.ResourceManager.Extension.ScopeParameter ``` +#### Template Parameters + +| Name | Description | +| ---- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| Type | The type of the scope parameter (default is string). This can be used to specify `Azure.Core.armResourceIdentifier` type or other constrained type | + #### Examples ```typespec @@ -2797,9 +2838,9 @@ model Employee { #### Properties -| Name | Type | Description | -| ----- | -------- | ---------------------------------------------------------------------- | -| scope | `string` | The fully qualified Azure Resource manager identifier of the resource. | +| Name | Type | Description | +| ----- | ------ | ----------- | +| scope | `Type` | | ### `Subscription` {#Azure.ResourceManager.Extension.Subscription} diff --git a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx index 83d303fbd6..5dbb2720b3 100644 --- a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx +++ b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx @@ -269,6 +269,7 @@ npm install --save-peer @azure-tools/typespec-azure-resource-manager - [`ExtensionInstanceParameters`](./data-types.md#Azure.ResourceManager.Extension.ExtensionInstanceParameters) - [`ExtensionParentParameters`](./data-types.md#Azure.ResourceManager.Extension.ExtensionParentParameters) - [`ExtensionProviderNamespace`](./data-types.md#Azure.ResourceManager.Extension.ExtensionProviderNamespace) +- [`ExternalChildResource`](./data-types.md#Azure.ResourceManager.Extension.ExternalChildResource) - [`ExternalResource`](./data-types.md#Azure.ResourceManager.Extension.ExternalResource) - [`ManagementGroup`](./data-types.md#Azure.ResourceManager.Extension.ManagementGroup) - [`ResourceGroup`](./data-types.md#Azure.ResourceManager.Extension.ResourceGroup) From 6b31b3e07638a45696e75ed98baa7bc6d84354b8 Mon Sep 17 00:00:00 2001 From: Mark Cowlishaw Date: Tue, 24 Jun 2025 16:47:39 -0700 Subject: [PATCH 08/16] Adding legacy extensions interface --- .../specific-extension/main.tsp | 54 +++ .../2021-10-01-preview/openapi.json | 431 ++++++++++++++++++ .../lib/Legacy/extension.tsp | 301 ++++++++++++ .../reference/data-types.md | 46 +- .../reference/index.mdx | 1 + .../reference/interfaces.md | 199 ++++++++ 6 files changed, 1010 insertions(+), 22 deletions(-) diff --git a/packages/samples/specs/resource-manager/resource-types/specific-extension/main.tsp b/packages/samples/specs/resource-manager/resource-types/specific-extension/main.tsp index 1384362506..67d82570bb 100644 --- a/packages/samples/specs/resource-manager/resource-types/specific-extension/main.tsp +++ b/packages/samples/specs/resource-manager/resource-types/specific-extension/main.tsp @@ -3,6 +3,8 @@ import "@typespec/versioning"; import "@azure-tools/typespec-azure-core"; import "@azure-tools/typespec-azure-resource-manager"; +using Http; +using Rest; using Versioning; using Azure.Core; using Azure.ResourceManager; @@ -135,3 +137,55 @@ model MoveResponse { /** The status of the move */ movingStatus: string; } + +alias GenericResourceParameters = { + ...ApiVersionParameter; + ...SubscriptionIdParameter; + ...ResourceGroupParameter; + + /** the provider namespace */ + @path + @segment("providers") + @key + providerNamespace: string; + + /** the resource type of the parent */ + @path @key parentType: string; + + /** the name of the parent resource */ + @path @key parentName: string; + + /** the resource type of the target resource */ + @path @key resourceType: string; + + /** the name of the target resource */ + @path @key resourceName: string; +}; + +alias ParentParameters = { + ...Extension.ExtensionProviderNamespace; + ...ParentKeysOf; +}; + +#suppress "@azure-tools/typespec-azure-resource-manager/arm-resource-interface-requires-decorator" +interface GenericOps + extends Azure.ResourceManager.Legacy.ExtensionOperations< + GenericResourceParameters, + ParentParameters, + { + ...Extension.ExtensionProviderNamespace, + ...KeysOf, + } + > {} + +@armResourceOperations +interface GenericResources { + get is GenericOps.Read; + create is GenericOps.CreateOrUpdateAsync; + update is GenericOps.CustomPatchSync< + Employee, + Azure.ResourceManager.Foundations.ResourceUpdateModel + >; + delete is GenericOps.DeleteWithoutOkAsync; + list is GenericOps.List; +} diff --git a/packages/samples/test/output/azure/resource-manager/resource-types/specific-extension/@azure-tools/typespec-autorest/2021-10-01-preview/openapi.json b/packages/samples/test/output/azure/resource-manager/resource-types/specific-extension/@azure-tools/typespec-autorest/2021-10-01-preview/openapi.json index 16907dc61a..9bfc6e1c84 100644 --- a/packages/samples/test/output/azure/resource-manager/resource-types/specific-extension/@azure-tools/typespec-autorest/2021-10-01-preview/openapi.json +++ b/packages/samples/test/output/azure/resource-manager/resource-types/specific-extension/@azure-tools/typespec-autorest/2021-10-01-preview/openapi.json @@ -62,6 +62,9 @@ }, { "name": "ScaleSetVms" + }, + { + "name": "GenericResources" } ], "paths": { @@ -1282,6 +1285,434 @@ } } }, + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{providerNamespace}/{parentType}/{parentName}/{resourceType}/{resourceName}/providers/Microsoft.ContosoProviderHub/employees": { + "get": { + "operationId": "GenericResources_List", + "tags": [ + "GenericResources" + ], + "description": "List a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "providerNamespace", + "in": "path", + "description": "the provider namespace", + "required": true, + "type": "string" + }, + { + "name": "parentType", + "in": "path", + "description": "the resource type of the parent", + "required": true, + "type": "string" + }, + { + "name": "parentName", + "in": "path", + "description": "the name of the parent resource", + "required": true, + "type": "string" + }, + { + "name": "resourceType", + "in": "path", + "description": "the resource type of the target resource", + "required": true, + "type": "string" + }, + { + "name": "resourceName", + "in": "path", + "description": "the name of the target resource", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/EmployeeListResult" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "nextLink" + } + } + }, + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{providerNamespace}/{parentType}/{parentName}/{resourceType}/{resourceName}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}": { + "get": { + "operationId": "GenericResources_Get", + "tags": [ + "GenericResources" + ], + "description": "Get a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "providerNamespace", + "in": "path", + "description": "the provider namespace", + "required": true, + "type": "string" + }, + { + "name": "parentType", + "in": "path", + "description": "the resource type of the parent", + "required": true, + "type": "string" + }, + { + "name": "parentName", + "in": "path", + "description": "the name of the parent resource", + "required": true, + "type": "string" + }, + { + "name": "resourceType", + "in": "path", + "description": "the resource type of the target resource", + "required": true, + "type": "string" + }, + { + "name": "resourceName", + "in": "path", + "description": "the name of the target resource", + "required": true, + "type": "string" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + }, + "put": { + "operationId": "GenericResources_Create", + "tags": [ + "GenericResources" + ], + "description": "Create a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "providerNamespace", + "in": "path", + "description": "the provider namespace", + "required": true, + "type": "string" + }, + { + "name": "parentType", + "in": "path", + "description": "the resource type of the parent", + "required": true, + "type": "string" + }, + { + "name": "parentName", + "in": "path", + "description": "the name of the parent resource", + "required": true, + "type": "string" + }, + { + "name": "resourceType", + "in": "path", + "description": "the resource type of the target resource", + "required": true, + "type": "string" + }, + { + "name": "resourceName", + "in": "path", + "description": "the name of the target resource", + "required": true, + "type": "string" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "resource", + "in": "body", + "description": "Resource create parameters.", + "required": true, + "schema": { + "$ref": "#/definitions/Employee" + } + } + ], + "responses": { + "200": { + "description": "Resource 'Employee' update operation succeeded", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "201": { + "description": "Resource 'Employee' create operation succeeded", + "schema": { + "$ref": "#/definitions/Employee" + }, + "headers": { + "Azure-AsyncOperation": { + "type": "string", + "description": "A link to the status monitor" + }, + "Retry-After": { + "type": "integer", + "format": "int32", + "description": "The Retry-After header can indicate how long the client should wait before polling the operation status." + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-long-running-operation-options": { + "final-state-via": "azure-async-operation" + }, + "x-ms-long-running-operation": true + }, + "patch": { + "operationId": "GenericResources_Update", + "tags": [ + "GenericResources" + ], + "description": "Update a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "providerNamespace", + "in": "path", + "description": "the provider namespace", + "required": true, + "type": "string" + }, + { + "name": "parentType", + "in": "path", + "description": "the resource type of the parent", + "required": true, + "type": "string" + }, + { + "name": "parentName", + "in": "path", + "description": "the name of the parent resource", + "required": true, + "type": "string" + }, + { + "name": "resourceType", + "in": "path", + "description": "the resource type of the target resource", + "required": true, + "type": "string" + }, + { + "name": "resourceName", + "in": "path", + "description": "the name of the target resource", + "required": true, + "type": "string" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + }, + { + "name": "properties", + "in": "body", + "description": "Resource create parameters.", + "required": true, + "schema": { + "$ref": "#/definitions/EmployeeUpdate" + } + } + ], + "responses": { + "200": { + "description": "Azure operation completed successfully.", + "schema": { + "$ref": "#/definitions/Employee" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + } + }, + "delete": { + "operationId": "GenericResources_Delete", + "tags": [ + "GenericResources" + ], + "description": "Delete a Employee", + "parameters": [ + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ResourceGroupNameParameter" + }, + { + "name": "providerNamespace", + "in": "path", + "description": "the provider namespace", + "required": true, + "type": "string" + }, + { + "name": "parentType", + "in": "path", + "description": "the resource type of the parent", + "required": true, + "type": "string" + }, + { + "name": "parentName", + "in": "path", + "description": "the name of the parent resource", + "required": true, + "type": "string" + }, + { + "name": "resourceType", + "in": "path", + "description": "the resource type of the target resource", + "required": true, + "type": "string" + }, + { + "name": "resourceName", + "in": "path", + "description": "the name of the target resource", + "required": true, + "type": "string" + }, + { + "name": "employeeName", + "in": "path", + "description": "The name of the Employee", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9-]{3,24}$" + } + ], + "responses": { + "202": { + "description": "Resource deletion accepted.", + "headers": { + "Location": { + "type": "string", + "description": "The Location header contains the URL where the status of the long running operation can be checked." + }, + "Retry-After": { + "type": "integer", + "format": "int32", + "description": "The Retry-After header can indicate how long the client should wait before polling the operation status." + } + } + }, + "204": { + "description": "Resource does not exist." + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-long-running-operation-options": { + "final-state-via": "location" + }, + "x-ms-long-running-operation": true + } + }, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/virtualMachineScaleSets/{scaleSetName}/virtualMachineScaleSetVms/{scaleSetVmName}/providers/Microsoft.ContosoProviderHub/employees": { "get": { "operationId": "ScaleSetVms_List", diff --git a/packages/typespec-azure-resource-manager/lib/Legacy/extension.tsp b/packages/typespec-azure-resource-manager/lib/Legacy/extension.tsp index e69de29bb2..a71c840388 100644 --- a/packages/typespec-azure-resource-manager/lib/Legacy/extension.tsp +++ b/packages/typespec-azure-resource-manager/lib/Legacy/extension.tsp @@ -0,0 +1,301 @@ +import "@typespec/rest"; +import "@typespec/http"; + +namespace Azure.ResourceManager.Legacy; + +using Http; +using Azure.ResourceManager.Private; +using Rest; + +/** + * An operation template used to build extension resource operations using non-standard paths. + * @template TargetParameters The path parameters for the target resource + * @template ExtensionParentParameters Parent parameters of the extension resource + * @template ExtensionInstanceParameters The instance parameters of the extension resource + */ +@doc("") +interface ExtensionOperations< + TargetParameters extends {}, + ExtensionParentParameters extends {}, + ExtensionInstanceParameters extends {} +> { + /** + * A long-running resource CreateOrUpdate (PUT) + * @template Resource the resource being created or updated + * @template LroHeaders Optional. Allows overriding the lro headers returned on resource create + * @template Parameters Optional. Additional parameters after the path parameters + * @template Response Optional. The success response(s) for the PUT operation + * @template OptionalRequestBody Optional. Indicates whether the request body is optional + * @template ErrorType Optional. The error response, if non-standard. + */ + @autoRoute + @doc("Create a {name}", Resource) + @armResourceCreateOrUpdate(Resource) + @Azure.Core.Foundations.Private.defaultFinalStateVia(#["location", "azure-async-operation"]) + @put + CreateOrUpdateAsync< + Resource extends Foundations.SimpleResource, + LroHeaders extends TypeSpec.Reflection.Model = ArmAsyncOperationHeader & + Azure.Core.Foundations.RetryAfterHeader, + Parameters extends {} = {}, + Response extends {} = ArmResourceUpdatedResponse | ArmResourceCreatedResponse< + Resource, + LroHeaders + >, + OptionalRequestBody extends valueof boolean = false, + ErrorType extends {} = ErrorResponse + >( + ...TargetParameters, + ...ExtensionInstanceParameters, + ...Parameters, + @doc("Resource create parameters.") @armBodyRoot(OptionalRequestBody) resource: Resource, + ): Response | ErrorType; + + /** + * A synchronous resource CreateOrUpdate (PUT) + * @template Resource the resource being created or updated + * @template Parameters Optional. Additional parameters after the path parameters + * @template Response Optional. The success response(s) for the PUT operation + * @template OptionalRequestBody Optional. Indicates whether the request body is optional + * @template ErrorType Optional. The error response, if non-standard. + */ + #suppress "@azure-tools/typespec-azure-core/no-private-usage" + @autoRoute + @doc("Create a {name}", Resource) + @armResourceCreateOrUpdate(Resource) + @put + CreateOrUpdateSync< + Resource extends Foundations.SimpleResource, + Parameters extends {} = {}, + Response extends {} = ArmResourceUpdatedResponse | ArmResourceCreatedSyncResponse, + OptionalRequestBody extends valueof boolean = false, + ErrorType extends {} = ErrorResponse + >( + ...TargetParameters, + ...ExtensionInstanceParameters, + ...Parameters, + @doc("Resource create parameters.") @armBodyRoot(OptionalRequestBody) resource: Resource, + ): Response | ErrorType; + + /** + * A long-running resource Update (PATCH) + * @template Resource the resource being created or updated + * @template PatchModel the PATCH request model + * @template LroHeaders Optional. Allows overriding the lro headers returned on resource create + * @template Parameters Optional. Additional parameters after the path parameters + * @template Response Optional. The success response(s) for the PATCH operation + * @template OptionalRequestBody Optional. Indicates whether the request body is optional + * @template ErrorType Optional. The error response, if non-standard. + */ + @autoRoute + @doc("Update a {name}", Resource) + @armResourceUpdate(Resource) + @patch(#{ implicitOptionality: false }) + CustomPatchAsync< + Resource extends Foundations.SimpleResource, + PatchModel extends {} = Azure.ResourceManager.Foundations.TagsUpdateModel, + LroHeaders extends TypeSpec.Reflection.Model = ArmLroLocationHeader< + Azure.Core.StatusMonitorPollingOptions, + Resource, + string + > & + Azure.Core.Foundations.RetryAfterHeader, + Parameters extends {} = {}, + Response extends {} = ArmResponse | ArmAcceptedLroResponse< + "Resource update request accepted.", + LroHeaders + >, + OptionalRequestBody extends valueof boolean = false, + ErrorType extends {} = ErrorResponse + >( + ...TargetParameters, + ...ExtensionInstanceParameters, + ...Parameters, + @doc("Resource create parameters.") @armBodyRoot(OptionalRequestBody) properties: PatchModel, + ): Response | ErrorType; + + /** + * A synchronous resource Update (PATCH) + * @template Resource the resource being created or updated + * @template PatchModel the PATCH request model + * @template Parameters Optional. Additional parameters after the path parameters + * @template Response Optional. The success response(s) for the PATCH operation + * @template OptionalRequestBody Optional. Indicates whether the request body is optional + * @template ErrorType Optional. The error response, if non-standard. + */ + @autoRoute + @doc("Update a {name}", Resource) + @armResourceUpdate(Resource) + @patch(#{ implicitOptionality: false }) + CustomPatchSync< + Resource extends Foundations.SimpleResource, + PatchModel extends {} = Azure.ResourceManager.Foundations.TagsUpdateModel, + Parameters extends {} = {}, + Response extends {} = ArmResponse, + OptionalRequestBody extends valueof boolean = false, + ErrorType extends {} = ErrorResponse + >( + ...TargetParameters, + ...ExtensionInstanceParameters, + ...Parameters, + @doc("Resource create parameters.") @armBodyRoot(OptionalRequestBody) properties: PatchModel, + ): Response | ErrorType; + + /** + * Delete a resource asynchronously + * @template Resource The resource being deleted + * @template LroHeaders The lro headers for the operation + * @template Parameters Optional. Additional parameters after the path parameters + * @template Response Optional. The success response(s) for the delete operation + * @template ErrorType Optional. The error response, if non-standard. + */ + #suppress "@azure-tools/typespec-azure-core/no-response-body" "Valid" + @autoRoute + @doc("Delete a {name}", Resource) + @delete + @deletesResource(Resource) + @armResourceDelete(Resource) + DeleteWithoutOkAsync< + Resource extends Foundations.SimpleResource, + LroHeaders extends TypeSpec.Reflection.Model = ArmLroLocationHeader & + Azure.Core.Foundations.RetryAfterHeader, + Parameters extends {} = {}, + Response extends {} = ArmDeleteAcceptedLroResponse | ArmDeletedNoContentResponse, + ErrorType extends {} = ErrorResponse + >(...TargetParameters, ...ExtensionInstanceParameters, ...Parameters): Response | ErrorType; + + /** + * Delete a resource synchronously + * @template Resource The resource being deleted + * @template Parameters Optional. Additional parameters after the path parameters + * @template Response Optional. The success response(s) for the delete operation + * @template ErrorType Optional. The error response, if non-standard. + */ + #suppress "@azure-tools/typespec-azure-core/no-response-body" "Valid" + @autoRoute + @doc("Delete a {name}", Resource) + @delete + @deletesResource(Resource) + @armResourceDelete(Resource) + DeleteSync< + Resource extends Foundations.SimpleResource, + Parameters extends {} = {}, + Response extends {} = ArmDeletedResponse | ArmDeletedNoContentResponse, + ErrorType extends {} = ErrorResponse + >(...TargetParameters, ...ExtensionInstanceParameters, ...Parameters): Response | ErrorType; + + /** + * @dev Get a resource + * @template Resource The resource being read + * @template Parameters Optional. Additional parameters after the path parameters + * @template Response Optional. The success response for a get operation. + * @template ErrorType Optional. The error response, if non-standard. + */ + @autoRoute + @doc("Get a {name}", Resource) + @get + @readsResource(Resource) + @armResourceRead(Resource) + Read< + Resource extends Foundations.SimpleResource, + Parameters extends {} = {}, + Response extends {} = ArmResponse, + ErrorType extends {} = ErrorResponse + >(...TargetParameters, ...ExtensionInstanceParameters, ...Parameters): Response | ErrorType; + + /** + * List a resource + * @template Resource The resource being listed + * @template Parameters Optional. Additional parameters after the path parameters + * @template Response Optional. The response returned by the list + * @template ErrorType Optional. The error response, if non-standard. + */ + @autoRoute + @doc("List a {name}", Resource) + @get + @listsResource(Resource) + @armResourceList(Resource) + List< + Resource extends Foundations.SimpleResource, + Parameters extends {} = {}, + Response extends {} = ArmResponse>, + ErrorType extends {} = ErrorResponse + >(...TargetParameters, ...ExtensionParentParameters, ...Parameters): Response | ErrorType; + + /** + * A synchronous resource action. + * @template Resource The resource being acted upon + * @template Request The request model for the action + * @template Response The response model for the action + * @template Parameters Optional. Additional parameters after the path parameters + * @template OptionalRequestBody Optional. Indicates whether the request body is optional + * @template ErrorType Optional. The error response, if non-standard. + */ + @doc("") + @autoRoute + @armResourceAction(Resource) + @Private.enforceConstraint(Resource, Foundations.Resource) + @post + @returnsDoc("Azure operation completed successfully.") + ActionSync< + Resource extends Foundations.SimpleResource, + Request extends TypeSpec.Reflection.Model | void, + Response extends TypeSpec.Reflection.Model | void, + Parameters extends {} = {}, + OptionalRequestBody extends valueof boolean = false, + ErrorType extends {} = ErrorResponse + >( + ...TargetParameters, + ...ExtensionInstanceParameters, + ...Parameters, + + @doc("The content of the action request") + @armBodyRoot(OptionalRequestBody) + body: Request, + ): Response | ErrorType; + + /** + * A long-running resource action. + * @template Resource The resource being acted upon + * @template Request The request model for the action + * @template Result The result model for the action + * @template LroHeaders Optional. Allows overriding the headers returned in the Accepted response + * @template Response The full response union of the action + * @template Parameters Optional. Additional parameters after the path parameters + * @template OptionalRequestBody Optional. Indicates whether the request body is optional + * @template ErrorType Optional. The error response, if non-standard. + */ + #suppress "@azure-tools/typespec-azure-core/no-response-body" "ARM" + @doc("") + @autoRoute + @armResourceAction(Resource) + @Private.enforceConstraint(Resource, Foundations.Resource) + @post + @returnsDoc("Azure operation completed successfully.") + ActionAsync< + Resource extends Foundations.SimpleResource, + Request extends TypeSpec.Reflection.Model | void, + Result extends TypeSpec.Reflection.Model | void, + LroHeaders extends TypeSpec.Reflection.Model = ArmLroLocationHeader< + Azure.Core.StatusMonitorPollingOptions, + Result, + string + > & + Azure.Core.Foundations.RetryAfterHeader, + Parameters extends {} = {}, + Response extends {} | void = ArmAcceptedLroResponse< + "Resource operation accepted.", + LroHeaders + > | Result, + OptionalRequestBody extends valueof boolean = false, + ErrorType extends {} = ErrorResponse + >( + ...TargetParameters, + ...ExtensionInstanceParameters, + ...Parameters, + + @doc("The content of the action request") + @armBodyRoot(OptionalRequestBody) + body: Request, + ): Response | ErrorType; +} diff --git a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/data-types.md b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/data-types.md index 9dffd4c5eb..f260bbd031 100644 --- a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/data-types.md +++ b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/data-types.md @@ -2705,18 +2705,19 @@ model Azure.ResourceManager.Extension.ExtensionProviderNamespace An external child resource target, used when an extension targets a child resource from another provider namespace ```typespec -model Azure.ResourceManager.Extension.ExternalChildResource +model Azure.ResourceManager.Extension.ExternalChildResource ``` #### Template Parameters -| Name | Description | -| --------------------- | ------------------------------------------------------------------------ | -| ParentModel | The parent of this resource. | -| ResourceType | The type of this resource. | -| ResourceParameterName | The name of the 'name' parameter of this resource. | -| NamePattern | The pattern restriction for the name of this resource (default is none). | -| NameType | The type of the name parameter of this resource (default is string). | +| Name | Description | +| --------------------- | ----------------------------------------------------------------------------------------------- | +| ParentModel | The parent of this resource. | +| ResourceType | The type of this resource. | +| ResourceParameterName | The name of the 'name' parameter of this resource. | +| NamePattern | The pattern restriction for the name of this resource (default is none). | +| NameType | The type of the name parameter of this resource (default is string). | +| Description | The description of the name parameter of this resource (default is "The name of the resource"). | #### Examples @@ -2740,27 +2741,28 @@ alias VirtualMachineScaleSetVm = Extension.ExternalChildResource< #### Properties -| Name | Type | Description | -| ---- | ---------- | ------------------------ | -| name | `NameType` | The name of the resource | +| Name | Type | Description | +| ---- | ---------- | ----------- | +| name | `NameType` | | ### `ExternalResource` {#Azure.ResourceManager.Extension.ExternalResource} An external resource target, used when an extension targets a resource from another provider namespace ```typespec -model Azure.ResourceManager.Extension.ExternalResource +model Azure.ResourceManager.Extension.ExternalResource ``` #### Template Parameters -| Name | Description | -| --------------------- | -------------------------------------------------------------------------------- | -| TargetNamespace | The provider namespace for the external resource. | -| ResourceType | The type of the external resource. | -| ResourceParameterName | The name of the 'name' parameter of the external resource. | -| NamePattern | The pattern restriction for the name of the external resource (default is none). | -| NameType | The type of the name parameter of the external resource (default is string). | +| Name | Description | +| --------------------- | ------------------------------------------------------------------------------------------------------- | +| TargetNamespace | The provider namespace for the external resource. | +| ResourceType | The type of the external resource. | +| ResourceParameterName | The name of the 'name' parameter of the external resource. | +| NamePattern | The pattern restriction for the name of the external resource (default is none). | +| NameType | The type of the name parameter of the external resource (default is string). | +| Description | The description of the name parameter of the external resource (default is "The name of the resource"). | #### Examples @@ -2778,9 +2780,9 @@ alias Scaleset = Extension.ExternalResource< #### Properties -| Name | Type | Description | -| ---- | ---------- | ------------------------ | -| name | `NameType` | The name of the resource | +| Name | Type | Description | +| ---- | ---------- | ----------- | +| name | `NameType` | | ### `ManagementGroup` {#Azure.ResourceManager.Extension.ManagementGroup} diff --git a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx index 5dbb2720b3..33bc29a87f 100644 --- a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx +++ b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx @@ -318,6 +318,7 @@ npm install --save-peer @azure-tools/typespec-azure-resource-manager ### Interfaces +- [`ExtensionOperations`](./interfaces.md#Azure.ResourceManager.Legacy.ExtensionOperations) - [`LegacyOperations`](./interfaces.md#Azure.ResourceManager.Legacy.LegacyOperations) - [`Operations`](./interfaces.md#Azure.ResourceManager.Legacy.Operations) diff --git a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/interfaces.md b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/interfaces.md index ef3e93b865..465a3732dc 100644 --- a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/interfaces.md +++ b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/interfaces.md @@ -1511,6 +1511,205 @@ op Azure.ResourceManager.Foundations.checkNameAvailability(apiVersion: string, b ## Azure.ResourceManager.Legacy +### `ExtensionOperations` {#Azure.ResourceManager.Legacy.ExtensionOperations} + +An operation template used to build extension resource operations using non-standard paths. + +```typespec +interface Azure.ResourceManager.Legacy.ExtensionOperations +``` + +#### Template Parameters + +| Name | Description | +| --------------------------- | ------------------------------------------------- | +| TargetParameters | The path parameters for the target resource | +| ExtensionParentParameters | Parent parameters of the extension resource | +| ExtensionInstanceParameters | The instance parameters of the extension resource | + +#### `ExtensionOperations.CreateOrUpdateAsync` {#Azure.ResourceManager.Legacy.ExtensionOperations.CreateOrUpdateAsync} + +A long-running resource CreateOrUpdate (PUT) + +```typespec +op Azure.ResourceManager.Legacy.ExtensionOperations.CreateOrUpdateAsync(resource: Resource): Response | ErrorType +``` + +##### Template Parameters + +| Name | Description | +| ------------------- | ----------------------------------------------------------------------- | +| Resource | the resource being created or updated | +| LroHeaders | Optional. Allows overriding the lro headers returned on resource create | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | Optional. The success response(s) for the PUT operation | +| OptionalRequestBody | Optional. Indicates whether the request body is optional | +| ErrorType | Optional. The error response, if non-standard. | + +#### `ExtensionOperations.CreateOrUpdateSync` {#Azure.ResourceManager.Legacy.ExtensionOperations.CreateOrUpdateSync} + +A synchronous resource CreateOrUpdate (PUT) + +```typespec +op Azure.ResourceManager.Legacy.ExtensionOperations.CreateOrUpdateSync(resource: Resource): Response | ErrorType +``` + +##### Template Parameters + +| Name | Description | +| ------------------- | --------------------------------------------------------- | +| Resource | the resource being created or updated | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | Optional. The success response(s) for the PUT operation | +| OptionalRequestBody | Optional. Indicates whether the request body is optional | +| ErrorType | Optional. The error response, if non-standard. | + +#### `ExtensionOperations.CustomPatchAsync` {#Azure.ResourceManager.Legacy.ExtensionOperations.CustomPatchAsync} + +A long-running resource Update (PATCH) + +```typespec +op Azure.ResourceManager.Legacy.ExtensionOperations.CustomPatchAsync(properties: PatchModel): Response | ErrorType +``` + +##### Template Parameters + +| Name | Description | +| ------------------- | ----------------------------------------------------------------------- | +| Resource | the resource being created or updated | +| PatchModel | the PATCH request model | +| LroHeaders | Optional. Allows overriding the lro headers returned on resource create | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | Optional. The success response(s) for the PATCH operation | +| OptionalRequestBody | Optional. Indicates whether the request body is optional | +| ErrorType | Optional. The error response, if non-standard. | + +#### `ExtensionOperations.CustomPatchSync` {#Azure.ResourceManager.Legacy.ExtensionOperations.CustomPatchSync} + +A synchronous resource Update (PATCH) + +```typespec +op Azure.ResourceManager.Legacy.ExtensionOperations.CustomPatchSync(properties: PatchModel): Response | ErrorType +``` + +##### Template Parameters + +| Name | Description | +| ------------------- | --------------------------------------------------------- | +| Resource | the resource being created or updated | +| PatchModel | the PATCH request model | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | Optional. The success response(s) for the PATCH operation | +| OptionalRequestBody | Optional. Indicates whether the request body is optional | +| ErrorType | Optional. The error response, if non-standard. | + +#### `ExtensionOperations.DeleteWithoutOkAsync` {#Azure.ResourceManager.Legacy.ExtensionOperations.DeleteWithoutOkAsync} + +Delete a resource asynchronously + +```typespec +op Azure.ResourceManager.Legacy.ExtensionOperations.DeleteWithoutOkAsync(): Response | ErrorType +``` + +##### Template Parameters + +| Name | Description | +| ---------- | ---------------------------------------------------------- | +| Resource | The resource being deleted | +| LroHeaders | The lro headers for the operation | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | Optional. The success response(s) for the delete operation | +| ErrorType | Optional. The error response, if non-standard. | + +#### `ExtensionOperations.DeleteSync` {#Azure.ResourceManager.Legacy.ExtensionOperations.DeleteSync} + +Delete a resource synchronously + +```typespec +op Azure.ResourceManager.Legacy.ExtensionOperations.DeleteSync(): Response | ErrorType +``` + +##### Template Parameters + +| Name | Description | +| ---------- | ---------------------------------------------------------- | +| Resource | The resource being deleted | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | Optional. The success response(s) for the delete operation | +| ErrorType | Optional. The error response, if non-standard. | + +#### `ExtensionOperations.Read` {#Azure.ResourceManager.Legacy.ExtensionOperations.Read} + +```typespec +op Azure.ResourceManager.Legacy.ExtensionOperations.Read(): Response | ErrorType +``` + +##### Template Parameters + +| Name | Description | +| ---------- | --------------------------------------------------------- | +| Resource | The resource being read | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | Optional. The success response for a get operation. | +| ErrorType | Optional. The error response, if non-standard. | + +#### `ExtensionOperations.List` {#Azure.ResourceManager.Legacy.ExtensionOperations.List} + +List a resource + +```typespec +op Azure.ResourceManager.Legacy.ExtensionOperations.List(): Response | ErrorType +``` + +##### Template Parameters + +| Name | Description | +| ---------- | --------------------------------------------------------- | +| Resource | The resource being listed | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | Optional. The response returned by the list | +| ErrorType | Optional. The error response, if non-standard. | + +#### `ExtensionOperations.ActionSync` {#Azure.ResourceManager.Legacy.ExtensionOperations.ActionSync} + +A synchronous resource action. + +```typespec +op Azure.ResourceManager.Legacy.ExtensionOperations.ActionSync(body: Request): Response | ErrorType +``` + +##### Template Parameters + +| Name | Description | +| ------------------- | --------------------------------------------------------- | +| Resource | The resource being acted upon | +| Request | The request model for the action | +| Response | The response model for the action | +| Parameters | Optional. Additional parameters after the path parameters | +| OptionalRequestBody | Optional. Indicates whether the request body is optional | +| ErrorType | Optional. The error response, if non-standard. | + +#### `ExtensionOperations.ActionAsync` {#Azure.ResourceManager.Legacy.ExtensionOperations.ActionAsync} + +A long-running resource action. + +```typespec +op Azure.ResourceManager.Legacy.ExtensionOperations.ActionAsync(body: Request): Response | ErrorType +``` + +##### Template Parameters + +| Name | Description | +| ------------------- | ------------------------------------------------------------------------- | +| Resource | The resource being acted upon | +| Request | The request model for the action | +| Result | The result model for the action | +| LroHeaders | Optional. Allows overriding the headers returned in the Accepted response | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | The full response union of the action | +| OptionalRequestBody | Optional. Indicates whether the request body is optional | +| ErrorType | Optional. The error response, if non-standard. | + ### `LegacyOperations` {#Azure.ResourceManager.Legacy.LegacyOperations} An operation template used to build resource operations in which the same resource type From 9e41c1b25ef63d5601f1d0d643b2fb891331162c Mon Sep 17 00:00:00 2001 From: Mark Cowlishaw Date: Tue, 24 Jun 2025 17:21:24 -0700 Subject: [PATCH 09/16] Responding to review comments --- .vscode/launch.json | 20 ------------------- ...Azure.ResourceManager.Extension.Private.ts | 4 ++-- .../lib/common-types/internal.tsp | 6 +++--- .../lib/extension/private.decorators.tsp | 7 ++----- .../src/private.decorators.ts | 7 ------- .../reference/data-types.md | 20 +++++++++---------- 6 files changed, 17 insertions(+), 47 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index e7439ab1f7..e29626c3ba 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -144,26 +144,6 @@ "order": 2 } }, - { - "type": "node", - "request": "launch", - "name": "Compile Extensions", - "program": "${workspaceRoot}/core/packages/compiler/entrypoints/cli.js", - "args": ["compile", ".", "--emit=@azure-tools/typespec-autorest"], - "smartStep": true, - "sourceMaps": true, - "skipFiles": ["/**/*.js"], - "outFiles": [ - "${workspaceFolder}/packages/*/dist/**/*.js", - "${workspaceFolder}/packages/*/dist-dev/**/*.js", - "${workspaceFolder}/core/packages/*/dist/**/*.js", - "${workspaceFolder}/core/packages/*/dist-dev/**/*.js" - ], - "cwd": "${workspaceRoot}/packages/samples/specs/resource-manager/resource-types/specific-extension", - "presentation": { - "order": 2 - } - }, { "name": "Regenerate .tmlanguage", "type": "node", diff --git a/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.Extension.Private.ts b/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.Extension.Private.ts index 76884198af..d6113ba2c9 100644 --- a/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.Extension.Private.ts +++ b/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.Extension.Private.ts @@ -8,7 +8,7 @@ import type { DecoratorContext, Model } from "@typespec/compiler"; export type BuiltInResourceDecorator = (context: DecoratorContext, target: Model) => void; /** - * `@builtInResource` marks a model as built-in to Azure ResourceManager at the Subscription level + * `@builtInSubscriptionResource` marks a model as built-in to Azure ResourceManager at the Subscription level * * @param target The model that is marked as built-in. */ @@ -18,7 +18,7 @@ export type BuiltInSubscriptionResourceDecorator = ( ) => void; /** - * `@builtInResource` marks a model as built-in to Azure ResourceManager at the ResourceGroup level + * `@builtInResourceGroupResource` marks a model as built-in to Azure ResourceManager at the ResourceGroup level * * @param target The model that is marked as built-in. */ diff --git a/packages/typespec-azure-resource-manager/lib/common-types/internal.tsp b/packages/typespec-azure-resource-manager/lib/common-types/internal.tsp index 0390fb6b88..1e8179a375 100644 --- a/packages/typespec-azure-resource-manager/lib/common-types/internal.tsp +++ b/packages/typespec-azure-resource-manager/lib/common-types/internal.tsp @@ -19,13 +19,13 @@ enum ResourceHome { @doc("The resource is bound to an extension") Extension, - @doc("The resource is built in") + @doc("The resource is a built in tenant resource") BuiltIn, - @doc("The resource is built in") + @doc("The resource is a built in subscription resource") BuiltInSubscription, - @doc("The resource is built in") + @doc("The resource is a built in resource group resource") BuiltInResourceGroup, } diff --git a/packages/typespec-azure-resource-manager/lib/extension/private.decorators.tsp b/packages/typespec-azure-resource-manager/lib/extension/private.decorators.tsp index d58099959d..0c5b6e8393 100644 --- a/packages/typespec-azure-resource-manager/lib/extension/private.decorators.tsp +++ b/packages/typespec-azure-resource-manager/lib/extension/private.decorators.tsp @@ -1,6 +1,3 @@ -using Http; -using Rest; -using Azure.Core; using Reflection; namespace Azure.ResourceManager.Extension.Private; @@ -13,14 +10,14 @@ namespace Azure.ResourceManager.Extension.Private; extern dec builtInResource(target: Model); /** - * `@builtInResource` marks a model as built-in to Azure ResourceManager at the Subscription level + * `@builtInSubscriptionResource` marks a model as built-in to Azure ResourceManager at the Subscription level * * @param target - The model that is marked as built-in. */ extern dec builtInSubscriptionResource(target: Model); /** - * `@builtInResource` marks a model as built-in to Azure ResourceManager at the ResourceGroup level + * `@builtInResourceGroupResource` marks a model as built-in to Azure ResourceManager at the ResourceGroup level * * @param target - The model that is marked as built-in. */ diff --git a/packages/typespec-azure-resource-manager/src/private.decorators.ts b/packages/typespec-azure-resource-manager/src/private.decorators.ts index 1cc3487d4d..873edfa631 100644 --- a/packages/typespec-azure-resource-manager/src/private.decorators.ts +++ b/packages/typespec-azure-resource-manager/src/private.decorators.ts @@ -6,7 +6,6 @@ import { ModelProperty, Operation, Program, - StringLiteral, Tuple, Type, addVisibilityModifiers, @@ -62,12 +61,6 @@ import { ArmStateKeys } from "./state.js"; export const namespace = "Azure.ResourceManager.Private"; -const PROVIDER_NAME_CACHE = Symbol.for("Azure.ResourceManager.Private.ProviderNameCache"); - -interface ProviderNameCache { - [PROVIDER_NAME_CACHE]?: Map; -} - /** @internal */ const $builtInResource: BuiltInResourceDecorator = ( diff --git a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/data-types.md b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/data-types.md index f260bbd031..17fea390fe 100644 --- a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/data-types.md +++ b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/data-types.md @@ -2444,16 +2444,16 @@ An internal enum to indicate the resource support for various path types enum Azure.ResourceManager.CommonTypes.ResourceHome ``` -| Name | Value | Description | -| -------------------- | ----- | ----------------------------------------- | -| Tenant | | The resource is bound to a tenant | -| Subscription | | The resource is bound to a subscription | -| Location | | The resource is bound to a location | -| ResourceGroup | | The resource is bound to a resource group | -| Extension | | The resource is bound to an extension | -| BuiltIn | | The resource is built in | -| BuiltInSubscription | | The resource is built in | -| BuiltInResourceGroup | | The resource is built in | +| Name | Value | Description | +| -------------------- | ----- | -------------------------------------------------- | +| Tenant | | The resource is bound to a tenant | +| Subscription | | The resource is bound to a subscription | +| Location | | The resource is bound to a location | +| ResourceGroup | | The resource is bound to a resource group | +| Extension | | The resource is bound to an extension | +| BuiltIn | | The resource is a built in tenant resource | +| BuiltInSubscription | | The resource is a built in subscription resource | +| BuiltInResourceGroup | | The resource is a built in resource group resource | ### `Versions` {#Azure.ResourceManager.CommonTypes.Versions} From b5b173025ce67b7ca8f03430033b02ced3da0f40 Mon Sep 17 00:00:00 2001 From: Mark Cowlishaw Date: Tue, 24 Jun 2025 18:40:56 -0700 Subject: [PATCH 10/16] Fix #2863 Add missing operations --- .../lib/Legacy/extension.tsp | 20 ++++++++++ .../lib/Legacy/operations.tsp | 22 ++++++++++- .../lib/extension/operations.tsp | 2 +- .../reference/interfaces.md | 39 ++++++++++++++++++- 4 files changed, 79 insertions(+), 4 deletions(-) diff --git a/packages/typespec-azure-resource-manager/lib/Legacy/extension.tsp b/packages/typespec-azure-resource-manager/lib/Legacy/extension.tsp index a71c840388..262e32eb7a 100644 --- a/packages/typespec-azure-resource-manager/lib/Legacy/extension.tsp +++ b/packages/typespec-azure-resource-manager/lib/Legacy/extension.tsp @@ -203,6 +203,26 @@ interface ExtensionOperations< ErrorType extends {} = ErrorResponse >(...TargetParameters, ...ExtensionInstanceParameters, ...Parameters): Response | ErrorType; + /** + * Check a resource's existence via HEAD operation + * * @template Resource The resource being checked + * @template Parameters Optional. Additional parameters after the path parameters + * @template Response Optional. The success response for a head operation (by default NoContent or NotFound response). + * @template ErrorType Optional. The error response, if non-standard. + */ + @autoRoute + @doc("Check for the existence of a {name}", Resource) + @head + CheckExistence< + Resource extends Foundations.SimpleResource, + Parameters extends {} = {}, + Response extends {} = ArmResourceExistsResponse | ArmResourceNotFoundResponse, + ErrorType extends {} = ErrorResponse + > is Foundations.ArmReadOperation< + TargetParameters & ExtensionInstanceParameters & Parameters, + Response, + ErrorType + >; /** * List a resource * @template Resource The resource being listed diff --git a/packages/typespec-azure-resource-manager/lib/Legacy/operations.tsp b/packages/typespec-azure-resource-manager/lib/Legacy/operations.tsp index eb31a8987f..216a8bc354 100644 --- a/packages/typespec-azure-resource-manager/lib/Legacy/operations.tsp +++ b/packages/typespec-azure-resource-manager/lib/Legacy/operations.tsp @@ -191,6 +191,25 @@ interface LegacyOperations< Response extends {} = ArmResponse >(...ParentParameters, ...ResourceTypeParameter, ...Parameters): Response | ErrorType; + /** + * Check a resource's existence via HEAD operation + * @template Resource The resource being checked + * @template Parameters Optional. Additional parameters after the path parameters + * @template Response Optional. The success response for a head operation (by default NoContent or NotFound response). + */ + @autoRoute + @doc("Check for the existence of a {name}", Resource) + @head + CheckExistence< + Resource extends Foundations.SimpleResource, + Parameters extends {} = {}, + Response extends {} = ArmResourceExistsResponse | ArmResourceNotFoundResponse + > is Foundations.ArmReadOperation< + ParentParameters & ResourceTypeParameter & Parameters, + Response, + ErrorType + >; + /** * List a resource * @template Resource The resource being listed @@ -243,8 +262,9 @@ interface LegacyOperations< * A long-running resource action. * @template Resource The resource being acted upon * @template Request The request model for the action + * @template Result The result model for the action when the operation is successful * @template LroHeaders Optional. Allows overriding the headers returned in the Accepted response - * @template Response The response model for the action + * @template Response The union of successful responses for the action * @template Parameters Optional. Additional parameters after the path parameters * @template OptionalRequestBody Optional. Indicates whether the request body is optional */ diff --git a/packages/typespec-azure-resource-manager/lib/extension/operations.tsp b/packages/typespec-azure-resource-manager/lib/extension/operations.tsp index 00431ad9ed..3110db2a2f 100644 --- a/packages/typespec-azure-resource-manager/lib/extension/operations.tsp +++ b/packages/typespec-azure-resource-manager/lib/extension/operations.tsp @@ -16,7 +16,7 @@ using Azure.ResourceManager.Private; * @template Error Optional. The error response, if non-standard. */ @autoRoute -@doc("List {name} resources by subscription ID", ExtensionResource) +@doc("List {name} resources by scope", ExtensionResource) @listsResource(ExtensionResource) @segmentOf(ExtensionResource) @armResourceList(ExtensionResource) diff --git a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/interfaces.md b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/interfaces.md index 465a3732dc..6e847e35e8 100644 --- a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/interfaces.md +++ b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/interfaces.md @@ -1653,6 +1653,25 @@ op Azure.ResourceManager.Legacy.ExtensionOperations.Read(): Response | ErrorType | Response | Optional. The success response for a get operation. | | ErrorType | Optional. The error response, if non-standard. | +#### `ExtensionOperations.CheckExistence` {#Azure.ResourceManager.Legacy.ExtensionOperations.CheckExistence} + +Check a resource's existence via HEAD operation + +- + +```typespec +op Azure.ResourceManager.Legacy.ExtensionOperations.CheckExistence(): Response | ErrorType +``` + +##### Template Parameters + +| Name | Description | +| ---------- | ------------------------------------------------------------------------------------------------ | +| Resource | The resource being checked | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | Optional. The success response for a head operation (by default NoContent or NotFound response). | +| ErrorType | Optional. The error response, if non-standard. | + #### `ExtensionOperations.List` {#Azure.ResourceManager.Legacy.ExtensionOperations.List} List a resource @@ -1846,6 +1865,22 @@ op Azure.ResourceManager.Legacy.LegacyOperations.Read(): Response | ErrorType | Parameters | Optional. Additional parameters after the path parameters | | Response | Optional. The success response for a get operation. | +#### `LegacyOperations.CheckExistence` {#Azure.ResourceManager.Legacy.LegacyOperations.CheckExistence} + +Check a resource's existence via HEAD operation + +```typespec +op Azure.ResourceManager.Legacy.LegacyOperations.CheckExistence(): Response | ErrorType +``` + +##### Template Parameters + +| Name | Description | +| ---------- | ------------------------------------------------------------------------------------------------ | +| Resource | The resource being checked | +| Parameters | Optional. Additional parameters after the path parameters | +| Response | Optional. The success response for a head operation (by default NoContent or NotFound response). | + #### `LegacyOperations.List` {#Azure.ResourceManager.Legacy.LegacyOperations.List} List a resource @@ -1894,10 +1929,10 @@ op Azure.ResourceManager.Legacy.LegacyOperations.ActionAsync(body: Request): Res | ------------------- | ------------------------------------------------------------------------- | | Resource | The resource being acted upon | | Request | The request model for the action | -| Result | | +| Result | The result model for the action when the operation is successful | | LroHeaders | Optional. Allows overriding the headers returned in the Accepted response | | Parameters | Optional. Additional parameters after the path parameters | -| Response | The response model for the action | +| Response | The union of successful responses for the action | | OptionalRequestBody | Optional. Indicates whether the request body is optional | ### `Operations` {#Azure.ResourceManager.Legacy.Operations} From cc432ac7c24fded2ba0bb3a2e5f024614ed3fc0d Mon Sep 17 00:00:00 2001 From: Mark Cowlishaw Date: Tue, 24 Jun 2025 19:17:29 -0700 Subject: [PATCH 11/16] Regenerate samples for doc change --- .../2021-10-01-preview/openapi.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/samples/test/output/azure/resource-manager/resource-types/specific-extension/@azure-tools/typespec-autorest/2021-10-01-preview/openapi.json b/packages/samples/test/output/azure/resource-manager/resource-types/specific-extension/@azure-tools/typespec-autorest/2021-10-01-preview/openapi.json index 9bfc6e1c84..1b9cb0fd9d 100644 --- a/packages/samples/test/output/azure/resource-manager/resource-types/specific-extension/@azure-tools/typespec-autorest/2021-10-01-preview/openapi.json +++ b/packages/samples/test/output/azure/resource-manager/resource-types/specific-extension/@azure-tools/typespec-autorest/2021-10-01-preview/openapi.json @@ -74,7 +74,7 @@ "tags": [ "Employees" ], - "description": "List Employee resources by subscription ID", + "description": "List Employee resources by scope", "parameters": [ { "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" @@ -390,7 +390,7 @@ "tags": [ "Tenants" ], - "description": "List Employee resources by subscription ID", + "description": "List Employee resources by scope", "parameters": [ { "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" @@ -689,7 +689,7 @@ "tags": [ "ManagementGroups" ], - "description": "List Employee resources by subscription ID", + "description": "List Employee resources by scope", "parameters": [ { "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" @@ -1005,7 +1005,7 @@ "tags": [ "Subscriptions" ], - "description": "List Employee resources by subscription ID", + "description": "List Employee resources by scope", "parameters": [ { "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" @@ -1719,7 +1719,7 @@ "tags": [ "ScaleSetVms" ], - "description": "List Employee resources by subscription ID", + "description": "List Employee resources by scope", "parameters": [ { "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" @@ -2119,7 +2119,7 @@ "tags": [ "VirtualMachines" ], - "description": "List Employee resources by subscription ID", + "description": "List Employee resources by scope", "parameters": [ { "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" @@ -2471,7 +2471,7 @@ "tags": [ "ResourceGroups" ], - "description": "List Employee resources by subscription ID", + "description": "List Employee resources by scope", "parameters": [ { "$ref": "../../../../../../../../../specs/resource-manager/common-types/v5/types.json#/parameters/ApiVersionParameter" From 7df5b382d4db4f17db77268e3f44679c0d6bf915 Mon Sep 17 00:00:00 2001 From: Mark Cowlishaw Date: Tue, 24 Jun 2025 19:47:39 -0700 Subject: [PATCH 12/16] Add resource manager test --- .../test/resource.test.ts | 141 +++++++++++++++++- 1 file changed, 139 insertions(+), 2 deletions(-) diff --git a/packages/typespec-azure-resource-manager/test/resource.test.ts b/packages/typespec-azure-resource-manager/test/resource.test.ts index 642cfb3f10..173241900f 100644 --- a/packages/typespec-azure-resource-manager/test/resource.test.ts +++ b/packages/typespec-azure-resource-manager/test/resource.test.ts @@ -1,10 +1,11 @@ -import { Model } from "@typespec/compiler"; +import { Interface, Model, Operation } from "@typespec/compiler"; import { expectDiagnosticEmpty, expectDiagnostics } from "@typespec/compiler/testing"; +import { getHttpOperation } from "@typespec/http"; import { ok, strictEqual } from "assert"; import { describe, expect, it } from "vitest"; import { ArmLifecycleOperationKind } from "../src/operations.js"; import { ArmResourceDetails, getArmResources } from "../src/resource.js"; -import { checkFor } from "./test-host.js"; +import { checkFor, compileAndDiagnose } from "./test-host.js"; function assertLifecycleOperation( resource: ArmResourceDetails, @@ -850,6 +851,142 @@ interface RestorePointOperations { expect(diskRestorePoint).toBeDefined(); }); + it("allows extension of foreign resources", async () => { + const { program, types, diagnostics } = await compileAndDiagnose(` +using Azure.Core; + +/** Contoso Resource Provider management API. */ +@armProviderNamespace +@service(#{ title: "ContosoProviderHubClient" }) +@useDependency(Azure.ResourceManager.Versions.v1_0_Preview_1) +@armCommonTypesVersion(Azure.ResourceManager.CommonTypes.Versions.v5) +namespace Microsoft.ContosoProviderHub; + +/** A ContosoProviderHub extension resource */ +model Employee is ExtensionResource { + ...ResourceNameParameter; +} + +/** Employee properties */ +model EmployeeProperties { + /** Age of employee */ + age?: int32; + + /** City of employee */ + city?: string; + + /** Profile of employee */ + @encode("base64url") + profile?: bytes; + + /** The status of the last operation. */ + @visibility(Lifecycle.Read) + provisioningState?: ProvisioningState; +} + +/** The provisioning state of a resource. */ +@lroStatus +union ProvisioningState { + ResourceProvisioningState, + + /** The resource is being provisioned */ + Provisioning: "Provisioning", + + /** The resource is updating */ + Updating: "Updating", + + /** The resource is being deleted */ + Deleting: "Deleting", + + /** The resource create request has been accepted */ + Accepted: "Accepted", + + string, +} + +interface Operations extends Azure.ResourceManager.Operations {} + +interface EmplOps { + get is Extension.Read; + + create is Extension.CreateOrReplaceAsync; + update is Extension.CustomPatchSync< + Scope, + Employee, + Azure.ResourceManager.Foundations.ResourceUpdateModel + >; + delete is Extension.DeleteWithoutOkAsync; + list is Extension.ListByTarget; + move is Extension.ActionSync; +} + +/** Virtual resource for a virtual machine */ +alias VirtualMachine = Extension.ExternalResource< + "Microsoft.Compute", + "virtualMachines", + "vmName", + NamePattern = "^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,80}$", + Description = "The name of the virtual machine" +>; + + +@test +@armResourceOperations +interface Employees extends EmplOps {} +@test +@armResourceOperations +interface ManagementGroups extends EmplOps {} +@test +@armResourceOperations +interface VirtualMachines extends EmplOps {} + + +/** Employee move request */ +model MoveRequest { + /** The moving from location */ + from: string; + + /** The moving to location */ + to: string; +} + +/** Employee move response */ +model MoveResponse { + /** The status of the move */ + movingStatus: string; +} + + `); + + expectDiagnosticEmpty(diagnostics); + const { Employees, ManagementGroups, VirtualMachines } = types as { + Employees: Interface; + ManagementGroups: Interface; + VirtualMachines: Interface; + }; + const employeesGet: Operation | undefined = Employees?.operations?.get("get"); + ok(employeesGet); + expect(employeesGet?.kind).toBe("Operation"); + const [emplGetHttp, _e] = getHttpOperation(program, employeesGet); + expect(emplGetHttp.path).toBe( + "/{scope}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}", + ); + const managementGet: Operation | undefined = ManagementGroups?.operations?.get("get"); + ok(managementGet); + expect(managementGet?.kind).toBe("Operation"); + const [managementGetHttp, _m] = getHttpOperation(program, managementGet); + expect(managementGetHttp.path).toBe( + "/providers/Microsoft.Management/managementGroups/{managementGroupName}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}", + ); + const virtualMachinesGet: Operation | undefined = VirtualMachines?.operations?.get("get"); + ok(virtualMachinesGet); + expect(virtualMachinesGet?.kind).toBe("Operation"); + const [vmGetHttp, _v] = getHttpOperation(program, virtualMachinesGet); + expect(vmGetHttp.path).toBe( + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/virtualMachines/{vmName}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}", + ); + }); + it("emits diagnostics for non ARM resources", async () => { const { diagnostics } = await checkFor(` @armProviderNamespace From f349c7f602539e8ff66146263d6c5c48d8dd7884 Mon Sep 17 00:00:00 2001 From: Mark Cowlishaw Date: Wed, 25 Jun 2025 12:42:53 -0700 Subject: [PATCH 13/16] Fix spelling issue in test --- .../typespec-azure-resource-manager/test/resource.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/typespec-azure-resource-manager/test/resource.test.ts b/packages/typespec-azure-resource-manager/test/resource.test.ts index 173241900f..d796b1c703 100644 --- a/packages/typespec-azure-resource-manager/test/resource.test.ts +++ b/packages/typespec-azure-resource-manager/test/resource.test.ts @@ -967,8 +967,8 @@ model MoveResponse { const employeesGet: Operation | undefined = Employees?.operations?.get("get"); ok(employeesGet); expect(employeesGet?.kind).toBe("Operation"); - const [emplGetHttp, _e] = getHttpOperation(program, employeesGet); - expect(emplGetHttp.path).toBe( + const [employeeGetHttp, _e] = getHttpOperation(program, employeesGet); + expect(employeeGetHttp.path).toBe( "/{scope}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}", ); const managementGet: Operation | undefined = ManagementGroups?.operations?.get("get"); From 6b79d76c65d66ed11bf20e7864d77d11269ae406 Mon Sep 17 00:00:00 2001 From: Mark Cowlishaw Date: Wed, 25 Jun 2025 13:59:01 -0700 Subject: [PATCH 14/16] Fix namespace typo --- .../typespec-azure-resource-manager/lib/extension/extension.tsp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/typespec-azure-resource-manager/lib/extension/extension.tsp b/packages/typespec-azure-resource-manager/lib/extension/extension.tsp index 89caf0231e..03154858b5 100644 --- a/packages/typespec-azure-resource-manager/lib/extension/extension.tsp +++ b/packages/typespec-azure-resource-manager/lib/extension/extension.tsp @@ -3,4 +3,4 @@ import "./operations.tsp"; import "./parameters.tsp"; import "./private.decorators.tsp"; -namespace Azure.resourceManager.Extension; +namespace Azure.ResourceManager.Extension; From a2585c0102ee600d69329a14b6153c23c2b5d28c Mon Sep 17 00:00:00 2001 From: Mark Cowlishaw Date: Wed, 25 Jun 2025 15:01:24 -0700 Subject: [PATCH 15/16] And add the docs change --- .../docs/libraries/azure-resource-manager/reference/index.mdx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx index 33bc29a87f..af1b9120b8 100644 --- a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx +++ b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx @@ -30,8 +30,6 @@ npm install --save-peer @azure-tools/typespec-azure-resource-manager ## Azure -## Azure.resourceManager - ## Azure.ResourceManager ### Decorators @@ -240,8 +238,6 @@ npm install --save-peer @azure-tools/typespec-azure-resource-manager - [`UserAssignedIdentities`](./data-types.md#Azure.ResourceManager.CommonTypes.UserAssignedIdentities) - [`UserAssignedIdentity`](./data-types.md#Azure.ResourceManager.CommonTypes.UserAssignedIdentity) -## Azure.resourceManager.Extension - ## Azure.ResourceManager.Extension ### Operations From f79484329c3ddbb27676cfb361cb11e87d2e8dd5 Mon Sep 17 00:00:00 2001 From: Mark Cowlishaw Date: Thu, 26 Jun 2025 12:52:57 -0700 Subject: [PATCH 16/16] Update provider name behavior to preserve existing spec output --- .../Azure.ResourceManager.Private.ts | 13 + .../lib/Legacy/operations.tsp | 21 +- .../lib/extension/parameters.tsp | 8 +- .../lib/private.decorators.tsp | 5 + .../src/lib.ts | 6 + .../src/private.decorators.ts | 44 ++- .../test/resource.test.ts | 351 ++++++++++++++++++ .../reference/data-types.md | 82 ++-- .../reference/index.mdx | 1 + .../reference/interfaces.md | 34 +- 10 files changed, 508 insertions(+), 57 deletions(-) diff --git a/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.Private.ts b/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.Private.ts index 5ae026d27d..90d7c36219 100644 --- a/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.Private.ts +++ b/packages/typespec-azure-resource-manager/generated-defs/Azure.ResourceManager.Private.ts @@ -79,6 +79,18 @@ export type ArmUpdateProviderNamespaceDecorator = ( target: Operation, ) => void; +/** + * + * + * + * @param resource Resource model + */ +export type AssignUniqueProviderNameValueDecorator = ( + context: DecoratorContext, + target: ModelProperty, + resource: Model, +) => void; + /** * This decorator is used to identify Azure Resource Manager resource types and extract their * metadata. It is *not* meant to be used directly by a spec author, it instead @@ -170,6 +182,7 @@ export type AzureResourceManagerPrivateDecorators = { assignProviderNameValue: AssignProviderNameValueDecorator; azureResourceBase: AzureResourceBaseDecorator; armUpdateProviderNamespace: ArmUpdateProviderNamespaceDecorator; + assignUniqueProviderNameValue: AssignUniqueProviderNameValueDecorator; armResourceInternal: ArmResourceInternalDecorator; defaultResourceKeySegmentName: DefaultResourceKeySegmentNameDecorator; enforceConstraint: EnforceConstraintDecorator; diff --git a/packages/typespec-azure-resource-manager/lib/Legacy/operations.tsp b/packages/typespec-azure-resource-manager/lib/Legacy/operations.tsp index 216a8bc354..525a1cb0e7 100644 --- a/packages/typespec-azure-resource-manager/lib/Legacy/operations.tsp +++ b/packages/typespec-azure-resource-manager/lib/Legacy/operations.tsp @@ -32,6 +32,7 @@ interface LegacyOperations< @autoRoute @doc("Create a {name}", Resource) @armResourceCreateOrUpdate(Resource) + @Private.armUpdateProviderNamespace @Azure.Core.Foundations.Private.defaultFinalStateVia(#["location", "azure-async-operation"]) @put CreateOrUpdateAsync< @@ -62,6 +63,7 @@ interface LegacyOperations< @autoRoute @doc("Create a {name}", Resource) @armResourceCreateOrUpdate(Resource) + @Private.armUpdateProviderNamespace @put CreateOrUpdateSync< Resource extends Foundations.SimpleResource, @@ -87,6 +89,7 @@ interface LegacyOperations< @autoRoute @doc("Update a {name}", Resource) @armResourceUpdate(Resource) + @Private.armUpdateProviderNamespace @patch(#{ implicitOptionality: false }) CustomPatchAsync< Resource extends Foundations.SimpleResource, @@ -121,6 +124,7 @@ interface LegacyOperations< @autoRoute @doc("Update a {name}", Resource) @armResourceUpdate(Resource) + @Private.armUpdateProviderNamespace @patch(#{ implicitOptionality: false }) CustomPatchSync< Resource extends Foundations.SimpleResource, @@ -147,6 +151,7 @@ interface LegacyOperations< @doc("Delete a {name}", Resource) @delete @deletesResource(Resource) + @Private.armUpdateProviderNamespace @armResourceDelete(Resource) DeleteWithoutOkAsync< Resource extends Foundations.SimpleResource, @@ -168,6 +173,7 @@ interface LegacyOperations< @delete @deletesResource(Resource) @armResourceDelete(Resource) + @Private.armUpdateProviderNamespace DeleteSync< Resource extends Foundations.SimpleResource, Parameters extends {} = {}, @@ -185,6 +191,7 @@ interface LegacyOperations< @get @readsResource(Resource) @armResourceRead(Resource) + @Private.armUpdateProviderNamespace Read< Resource extends Foundations.SimpleResource, Parameters extends {} = {}, @@ -199,6 +206,7 @@ interface LegacyOperations< */ @autoRoute @doc("Check for the existence of a {name}", Resource) + @Private.armUpdateProviderNamespace @head CheckExistence< Resource extends Foundations.SimpleResource, @@ -222,6 +230,7 @@ interface LegacyOperations< @listsResource(Resource) @segmentOf(Resource) @armResourceList(Resource) + @Private.armUpdateProviderNamespace List< Resource extends Foundations.SimpleResource, Parameters extends {} = {}, @@ -241,6 +250,7 @@ interface LegacyOperations< @armResourceAction(Resource) @Private.enforceConstraint(Resource, Foundations.Resource) @post + @Private.armUpdateProviderNamespace @returnsDoc("Azure operation completed successfully.") ActionSync< Resource extends Foundations.SimpleResource, @@ -273,6 +283,7 @@ interface LegacyOperations< @autoRoute @armResourceAction(Resource) @Private.enforceConstraint(Resource, Foundations.Resource) + @Private.armUpdateProviderNamespace @post @returnsDoc("Azure operation completed successfully.") ActionAsync< @@ -302,13 +313,21 @@ interface LegacyOperations< ): Response | ErrorType; } /** - * @dev Get the provider namespace key-value pair + * @dev DEPRECATED: Use ProviderParameter instead. Get the provider namespace key-value pair * @template Resource Optional. The resource to get the provider namespace for. */ model Provider { ...ProviderNamespace; } +/** + * @dev Get the provider namespace key-value pair + * @template Resource The resource to get the provider namespace for. + */ +model ProviderParameter { + ...ProviderNamespace; +} + /** * A long-running resource update using a custom PATCH payload (Asynchronous) * @template Resource the resource being patched diff --git a/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp b/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp index 3e5d4ca428..22203df32a 100644 --- a/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp +++ b/packages/typespec-azure-resource-manager/lib/extension/parameters.tsp @@ -58,9 +58,9 @@ model TargetParameters { model ExtensionProviderNamespace { @path @segment("providers") - @assignProviderNameValue(Resource) + @assignUniqueProviderNameValue(Resource) @doc("The provider namespace for the resource.") - extensionProvider: "Microsoft.ThisWillBeReplaced"; + extensionProvider: "Microsoft.ExtensionProviderNamespace"; } /** The provider namespace (if any) for a target resource for an extension @@ -79,8 +79,8 @@ model TargetProviderNamespace { @path @segment("providers") @doc("The provider namespace for the resource.") - @assignProviderNameValue(Resource) - provider: "Microsoft.ThisWillBeReplaced"; + @assignUniqueProviderNameValue(Resource) + provider: "Microsoft.TargetProviderNamespace"; } /** The path parameters for an extension resource at the given target diff --git a/packages/typespec-azure-resource-manager/lib/private.decorators.tsp b/packages/typespec-azure-resource-manager/lib/private.decorators.tsp index b840c4df7b..c15f3297ff 100644 --- a/packages/typespec-azure-resource-manager/lib/private.decorators.tsp +++ b/packages/typespec-azure-resource-manager/lib/private.decorators.tsp @@ -14,6 +14,11 @@ extern dec armUpdateProviderNamespace(target: Reflection.Operation); */ extern dec assignProviderNameValue(target: ModelProperty, resource: Model); +/** + * @param resource Resource model + */ +extern dec assignUniqueProviderNameValue(target: ModelProperty, resource: Model); + /** * This decorator is used to identify Azure Resource Manager resource types and extract their * metadata. It is *not* meant to be used directly by a spec author, it instead diff --git a/packages/typespec-azure-resource-manager/src/lib.ts b/packages/typespec-azure-resource-manager/src/lib.ts index e823b7116c..ab0d8c5706 100644 --- a/packages/typespec-azure-resource-manager/src/lib.ts +++ b/packages/typespec-azure-resource-manager/src/lib.ts @@ -104,6 +104,12 @@ export const $lib = createTypeSpecLibrary({ default: "Resource types must have a property with '@path` and '@segment' decorators.", }, }, + "resource-without-provider-namespace": { + severity: "warning", + messages: { + default: paramMessage`The resource "${"resourceName"}" does not have a provider namespace. Please use a resource in a namespace marked with '@armProviderNamespace' or a virtual resource with a specific namespace`, + }, + }, "template-type-constraint-no-met": { severity: "error", messages: { diff --git a/packages/typespec-azure-resource-manager/src/private.decorators.ts b/packages/typespec-azure-resource-manager/src/private.decorators.ts index 873edfa631..cbadd05bf4 100644 --- a/packages/typespec-azure-resource-manager/src/private.decorators.ts +++ b/packages/typespec-azure-resource-manager/src/private.decorators.ts @@ -34,6 +34,7 @@ import { ArmResourcePropertiesOptionalityDecorator, ArmUpdateProviderNamespaceDecorator, AssignProviderNameValueDecorator, + AssignUniqueProviderNameValueDecorator, AzureResourceBaseDecorator, AzureResourceManagerPrivateDecorators, ConditionalClientFlattenDecorator, @@ -269,7 +270,42 @@ const $assignProviderNameValue: AssignProviderNameValueDecorator = ( ) => { const { program } = context; const armProviderNamespace = getArmProviderNamespace(program, resourceType as Model); - if (armProviderNamespace && target.type.kind === "String") { + if ( + armProviderNamespace && + target.type.kind === "String" && + target.type.value === "Microsoft.ThisWillBeReplaced" + ) { + target.type.value = armProviderNamespace; + } +}; + +/** + * This decorator allows setting a unique provider name value, for scenarios in which + * multiple providers are allowed. + * @param {DecoratorContext} context DecoratorContext + * @param {Type} target Target of this decorator. Must be a string `ModelProperty`. + * @param {Type} resourceType Must be a `Model`. + */ +const $assignUniqueProviderNameValue: AssignUniqueProviderNameValueDecorator = ( + context: DecoratorContext, + target: ModelProperty, + resourceType: Model, +) => { + const { program } = context; + const armProviderNamespace = getArmProviderNamespace(program, resourceType); + if (!armProviderNamespace && !isBuiltIn(getResourceBaseType(program, resourceType))) { + reportDiagnostic(program, { + code: "resource-without-provider-namespace", + format: { resourceName: resourceType.name }, + target: resourceType, + }); + return; + } + if ( + armProviderNamespace && + target.type.kind === "String" && + target.type.value !== armProviderNamespace + ) { target.type = $(program).literal.createString(armProviderNamespace); } }; @@ -302,8 +338,9 @@ const $armUpdateProviderNamespace: ArmUpdateProviderNamespaceDecorator = ( }); return; } - - providerParam.type.value = armProviderNamespace; + if (providerParam.type.value === "Microsoft.ThisWillBeReplaced") { + providerParam.type.value = armProviderNamespace; + } } } } @@ -544,6 +581,7 @@ export const $decorators = { azureResourceBase: $azureResourceBase, omitIfEmpty: $omitIfEmpty, conditionalClientFlatten: $conditionalClientFlatten, + assignUniqueProviderNameValue: $assignUniqueProviderNameValue, assignProviderNameValue: $assignProviderNameValue, armUpdateProviderNamespace: $armUpdateProviderNamespace, armResourceInternal: $armResourceInternal, diff --git a/packages/typespec-azure-resource-manager/test/resource.test.ts b/packages/typespec-azure-resource-manager/test/resource.test.ts index d796b1c703..2489cf8ce0 100644 --- a/packages/typespec-azure-resource-manager/test/resource.test.ts +++ b/packages/typespec-azure-resource-manager/test/resource.test.ts @@ -987,6 +987,313 @@ model MoveResponse { ); }); + it("overrides provider namespace in mixed legacy and resource operations", async () => { + const { program, types, diagnostics } = await compileAndDiagnose(` +using Azure.Core; + +#suppress "@azure-tools/typespec-azure-core/require-versioned" +#suppress "@azure-tools/typespec-azure-resource-manager/missing-operations-endpoint" +/** Contoso Resource Provider management API. */ +@armProviderNamespace +@service(#{ title: "ContosoProviderHubClient" }) +@armCommonTypesVersion(Azure.ResourceManager.CommonTypes.Versions.v5) +@useDependency(Azure.ResourceManager.Versions.v1_0_Preview_1) +namespace Microsoft.ContosoProviderHub; + +/** A ContosoProviderHub resource */ +model Employee is TrackedResource { + ...ResourceNameParameter; +} + +/** Employee properties */ +model EmployeeProperties { + /** Age of employee */ + age?: int32; + + /** City of employee */ + city?: string; + + /** Profile of employee */ + @encode("base64url") + profile?: bytes; + + /** The status of the last operation. */ + @visibility(Lifecycle.Read) + provisioningState?: ProvisioningState; +} + +/** The provisioning state of a resource. */ +@lroStatus +union ProvisioningState { + string, + + /** The resource create request has been accepted */ + Accepted: "Accepted", + + /** The resource is being provisioned */ + Provisioning: "Provisioning", + + /** The resource is updating */ + Updating: "Updating", + + /** Resource has been created. */ + Succeeded: "Succeeded", + + /** Resource creation failed. */ + Failed: "Failed", + + /** Resource creation was canceled. */ + Canceled: "Canceled", + + /** The resource is being deleted */ + Deleting: "Deleting", +} + +#suppress "@azure-tools/typespec-azure-resource-manager/arm-resource-interface-requires-decorator" +interface EmplOps extends Azure.ResourceManager.Legacy.LegacyOperations< +BaseParams & {...ParentKeysOf}, +{...KeysOf}> {} + +alias BaseParams = { + ...ApiVersionParameter; + ...SubscriptionIdParameter; + ...Azure.ResourceManager.Legacy.Provider; + }; + + +@armResourceOperations +interface Employees { + @test + get is EmplOps.Read; + + /** A sample HEAD operation to check resource existence */ + @test + checkExistence is Azure.ResourceManager.ArmResourceCheckExistence; +} + `); + + expectDiagnosticEmpty(diagnostics); + const { get, checkExistence } = types as { + get: Operation; + checkExistence: Operation; + }; + ok(get); + expect(get?.kind).toBe("Operation"); + const [employeeGetHttp, _e] = getHttpOperation(program, get); + expect(employeeGetHttp.path).toBe( + "/subscriptions/{subscriptionId}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}", + ); + + ok(checkExistence); + expect(checkExistence?.kind).toBe("Operation"); + const [existenceHttp, _m] = getHttpOperation(program, checkExistence); + expect(existenceHttp.path).toBe( + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}", + ); + }); + + it("overrides provider namespace in custom operations", async () => { + const { program, types, diagnostics } = await compileAndDiagnose(` +using Azure.Core; + +#suppress "@azure-tools/typespec-azure-core/require-versioned" +#suppress "@azure-tools/typespec-azure-resource-manager/missing-operations-endpoint" +/** Contoso Resource Provider management API. */ +@armProviderNamespace +@service(#{ title: "ContosoProviderHubClient" }) +@armCommonTypesVersion(Azure.ResourceManager.CommonTypes.Versions.v5) +@useDependency(Azure.ResourceManager.Versions.v1_0_Preview_1) +namespace Microsoft.ContosoProviderHub; + +/** A ContosoProviderHub resource */ +model Employee is TrackedResource { + ...ResourceNameParameter; +} + +/** Employee properties */ +model EmployeeProperties { + /** Age of employee */ + age?: int32; + + /** City of employee */ + city?: string; + + /** Profile of employee */ + @encode("base64url") + profile?: bytes; + + /** The status of the last operation. */ + @visibility(Lifecycle.Read) + provisioningState?: ProvisioningState; +} + +/** The provisioning state of a resource. */ +@lroStatus +union ProvisioningState { + string, + + /** The resource create request has been accepted */ + Accepted: "Accepted", + + /** The resource is being provisioned */ + Provisioning: "Provisioning", + + /** The resource is updating */ + Updating: "Updating", + + /** Resource has been created. */ + Succeeded: "Succeeded", + + /** Resource creation failed. */ + Failed: "Failed", + + /** Resource creation was canceled. */ + Canceled: "Canceled", + + /** The resource is being deleted */ + Deleting: "Deleting", +} + +#suppress "@azure-tools/typespec-azure-resource-manager/arm-resource-interface-requires-decorator" +interface EmplOps extends Azure.ResourceManager.Legacy.LegacyOperations< +BaseParams & {...ParentKeysOf}, +{...KeysOf}> {} + +alias BaseParams = { + ...ApiVersionParameter; + ...SubscriptionIdParameter; + ...Azure.ResourceManager.Legacy.Provider; + }; + + +@armResourceOperations +interface Employees { + @test + /** a simple get */ + @armResourceRead(Employee) + @get op get(...BaseParams, ...KeysOf): Employee; + + /** A sample HEAD operation to check resource existence */ + @test + checkExistence is Azure.ResourceManager.ArmResourceCheckExistence; +} + `); + + expectDiagnosticEmpty(diagnostics); + const { get, checkExistence } = types as { + get: Operation; + checkExistence: Operation; + }; + ok(get); + expect(get?.kind).toBe("Operation"); + const [employeeGetHttp, _e] = getHttpOperation(program, get); + expect(employeeGetHttp.path).toBe( + "/subscriptions/{subscriptionId}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}", + ); + + ok(checkExistence); + expect(checkExistence?.kind).toBe("Operation"); + const [existenceHttp, _m] = getHttpOperation(program, checkExistence); + expect(existenceHttp.path).toBe( + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}", + ); + }); + + it("overrides provider namespace in legacy operations", async () => { + const { program, types, diagnostics } = await compileAndDiagnose(` +using Azure.Core; + + +#suppress "@azure-tools/typespec-azure-core/require-versioned" +#suppress "@azure-tools/typespec-azure-resource-manager/missing-operations-endpoint" +/** Contoso Resource Provider management API. */ +@armProviderNamespace +@service(#{ title: "ContosoProviderHubClient" }) +@armCommonTypesVersion(Azure.ResourceManager.CommonTypes.Versions.v5) +@useDependency(Azure.ResourceManager.Versions.v1_0_Preview_1) +namespace Microsoft.ContosoProviderHub; + +/** A ContosoProviderHub resource */ +model Employee is TrackedResource { + ...ResourceNameParameter; +} + +/** Employee properties */ +model EmployeeProperties { + /** Age of employee */ + age?: int32; + + /** City of employee */ + city?: string; + + /** Profile of employee */ + @encode("base64url") + profile?: bytes; + + /** The status of the last operation. */ + @visibility(Lifecycle.Read) + provisioningState?: ProvisioningState; +} + +/** The provisioning state of a resource. */ +@lroStatus +union ProvisioningState { + string, + + /** The resource create request has been accepted */ + Accepted: "Accepted", + + /** The resource is being provisioned */ + Provisioning: "Provisioning", + + /** The resource is updating */ + Updating: "Updating", + + /** Resource has been created. */ + Succeeded: "Succeeded", + + /** Resource creation failed. */ + Failed: "Failed", + + /** Resource creation was canceled. */ + Canceled: "Canceled", + + /** The resource is being deleted */ + Deleting: "Deleting", +} + +#suppress "@azure-tools/typespec-azure-resource-manager/arm-resource-interface-requires-decorator" +interface EmplOps extends Azure.ResourceManager.Legacy.LegacyOperations< +BaseParams & {...ParentKeysOf}, +{...KeysOf}> {} + +alias BaseParams = { + ...ApiVersionParameter; + ...SubscriptionIdParameter; + ...Azure.ResourceManager.Legacy.Provider; + }; + + +@armResourceOperations +interface Employees { + @test + get is EmplOps.Read; +} + `); + + expectDiagnosticEmpty(diagnostics); + const { get } = types as { + get: Operation; + checkExistence: Operation; + }; + ok(get); + expect(get?.kind).toBe("Operation"); + const [employeeGetHttp, _] = getHttpOperation(program, get); + expect(employeeGetHttp.path).toBe( + "/subscriptions/{subscriptionId}/providers/Microsoft.ContosoProviderHub/employees/{employeeName}", + ); + }); + it("emits diagnostics for non ARM resources", async () => { const { diagnostics } = await checkFor(` @armProviderNamespace @@ -1225,4 +1532,48 @@ describe("typespec-azure-resource-manager: identifiers decorator", () => { }, ]); }); + + it("emits diagnostics when a provider cannot be updated", async () => { + const { diagnostics } = await checkFor(` + using Azure.Core; +#suppress "@azure-tools/typespec-azure-core/require-versioned" +#suppress "@azure-tools/typespec-azure-resource-manager/missing-operations-endpoint" +/** Contoso Resource Provider management API. */ +@armProviderNamespace +@service(#{ title: "ContosoProviderHubClient" }) +@useDependency(Azure.ResourceManager.Versions.v1_0_Preview_1) +@armCommonTypesVersion(Azure.ResourceManager.CommonTypes.Versions.v5) +namespace Microsoft.ContosoProviderHub { + + @armResourceOperations + interface VirtualMachines { + @armResourceRead(Azure.ResourceManager.Extension.VirtualMachine) + @get op read( + ...ApiVersionParameter; + ...Extension.TargetProviderNamespace; + ...KeysOf): void; + } + +} + +namespace Azure.ResourceManager.Extension { + model VirtualMachine { + /** The vm Name */ + @visibility(Lifecycle.Read) @path @key @segment("virtualMachines") vmName: string; + } +} + +`); + + expectDiagnostics(diagnostics, [ + { + code: "@azure-tools/typespec-azure-resource-manager/resource-without-provider-namespace", + message: `The resource "VirtualMachine" does not have a provider namespace. Please use a resource in a namespace marked with '@armProviderNamespace' or a virtual resource with a specific namespace`, + }, + { + code: "@azure-tools/typespec-azure-resource-manager/resource-without-provider-namespace", + message: `The resource "VirtualMachine" does not have a provider namespace. Please use a resource in a namespace marked with '@armProviderNamespace' or a virtual resource with a specific namespace`, + }, + ]); + }); }); diff --git a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/data-types.md b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/data-types.md index 17fea390fe..9f0c170ebe 100644 --- a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/data-types.md +++ b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/data-types.md @@ -2647,13 +2647,13 @@ model Azure.ResourceManager.Extension.ExtensionInstanceParameters #### Properties -| Name | Type | Description | -| ----------------- | -------------------------------- | ----------- | -| extensionProvider | `"Microsoft.ThisWillBeReplaced"` | | +| Name | Type | Description | +| ----------------- | ---------------------------------------- | ----------- | +| extensionProvider | `"Microsoft.ExtensionProviderNamespace"` | | ### `ExternalChildResource` {#Azure.ResourceManager.Extension.ExternalChildResource} @@ -2872,12 +2872,12 @@ model Azure.ResourceManager.Extension.TargetBaseParameters #### Properties -| Name | Type | Description | -| ----------------- | -------------------------------- | ------------------------------------------------------------- | -| apiVersion | `string` | The API version to use for this operation. | -| subscriptionId | `Core.uuid` | The ID of the target subscription. The value must be an UUID. | -| resourceGroupName | `string` | The name of the resource group. The name is case insensitive. | -| provider | `"Microsoft.ThisWillBeReplaced"` | | +| Name | Type | Description | +| ----------------- | ------------------------------------- | ------------------------------------------------------------- | +| apiVersion | `string` | The API version to use for this operation. | +| subscriptionId | `Core.uuid` | The ID of the target subscription. The value must be an UUID. | +| resourceGroupName | `string` | The name of the resource group. The name is case insensitive. | +| provider | `"Microsoft.TargetProviderNamespace"` | | ### `TargetParameters` {#Azure.ResourceManager.Extension.TargetParameters} @@ -2895,12 +2895,12 @@ model Azure.ResourceManager.Extension.TargetParameters #### Properties -| Name | Type | Description | -| ----------------- | -------------------------------- | ------------------------------------------------------------- | -| apiVersion | `string` | The API version to use for this operation. | -| subscriptionId | `Core.uuid` | The ID of the target subscription. The value must be an UUID. | -| resourceGroupName | `string` | The name of the resource group. The name is case insensitive. | -| provider | `"Microsoft.ThisWillBeReplaced"` | | +| Name | Type | Description | +| ----------------- | ------------------------------------- | ------------------------------------------------------------- | +| apiVersion | `string` | The API version to use for this operation. | +| subscriptionId | `Core.uuid` | The ID of the target subscription. The value must be an UUID. | +| resourceGroupName | `string` | The name of the resource group. The name is case insensitive. | +| provider | `"Microsoft.TargetProviderNamespace"` | | ### `TargetProviderNamespace` {#Azure.ResourceManager.Extension.TargetProviderNamespace} @@ -2918,9 +2918,9 @@ model Azure.ResourceManager.Extension.TargetProviderNamespace #### Properties -| Name | Type | Description | -| -------- | -------------------------------- | ----------- | -| provider | `"Microsoft.ThisWillBeReplaced"` | | +| Name | Type | Description | +| -------- | ------------------------------------- | ----------- | +| provider | `"Microsoft.TargetProviderNamespace"` | | ### `Tenant` {#Azure.ResourceManager.Extension.Tenant} @@ -3332,6 +3332,24 @@ model Azure.ResourceManager.Legacy.Provider | -------- | -------------------------------- | ----------- | | provider | `"Microsoft.ThisWillBeReplaced"` | | +### `ProviderParameter` {#Azure.ResourceManager.Legacy.ProviderParameter} + +```typespec +model Azure.ResourceManager.Legacy.ProviderParameter +``` + +#### Template Parameters + +| Name | Description | +| -------- | ----------------------------------------------- | +| Resource | The resource to get the provider namespace for. | + +#### Properties + +| Name | Type | Description | +| -------- | -------------------------------- | ----------- | +| provider | `"Microsoft.ThisWillBeReplaced"` | | + ### `ManagedServiceIdentityType` {#Azure.ResourceManager.Legacy.ManagedServiceIdentityType} Type of managed service identity (where both SystemAssigned and UserAssigned types are allowed). diff --git a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx index af1b9120b8..9448fcd4c2 100644 --- a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx +++ b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/index.mdx @@ -329,3 +329,4 @@ npm install --save-peer @azure-tools/typespec-azure-resource-manager - [`ManagedServiceIdentityV4`](./data-types.md#Azure.ResourceManager.Legacy.ManagedServiceIdentityV4) - [`ManagedServiceIdentityV4Property`](./data-types.md#Azure.ResourceManager.Legacy.ManagedServiceIdentityV4Property) - [`Provider`](./data-types.md#Azure.ResourceManager.Legacy.Provider) +- [`ProviderParameter`](./data-types.md#Azure.ResourceManager.Legacy.ProviderParameter) diff --git a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/interfaces.md b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/interfaces.md index 6e847e35e8..75f649ad19 100644 --- a/website/src/content/docs/docs/libraries/azure-resource-manager/reference/interfaces.md +++ b/website/src/content/docs/docs/libraries/azure-resource-manager/reference/interfaces.md @@ -1132,7 +1132,7 @@ op Azure.ResourceManager.checkLocalNameAvailability(apiVersion: string, subscrip ### `ActionAsync` {#Azure.ResourceManager.Extension.ActionAsync} ```typespec -op Azure.ResourceManager.Extension.ActionAsync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced", body: Request): Azure.ResourceManager.ArmAcceptedLroResponse | Response | Error +op Azure.ResourceManager.Extension.ActionAsync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.TargetProviderNamespace", extensionProvider: "Microsoft.ExtensionProviderNamespace", body: Request): Azure.ResourceManager.ArmAcceptedLroResponse | Response | Error ``` #### Template Parameters @@ -1153,7 +1153,7 @@ op Azure.ResourceManager.Extension.ActionAsync(apiVersion: string, subscriptionI A long-running resource action. ```typespec -op Azure.ResourceManager.Extension.ActionAsyncBase(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced", body: Request): Response | Error +op Azure.ResourceManager.Extension.ActionAsyncBase(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.TargetProviderNamespace", extensionProvider: "Microsoft.ExtensionProviderNamespace", body: Request): Response | Error ``` #### Template Parameters @@ -1173,7 +1173,7 @@ op Azure.ResourceManager.Extension.ActionAsyncBase(apiVersion: string, subscript A synchronous resource action that returns no content. ```typespec -op Azure.ResourceManager.Extension.ActionNoContentSync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced", body: Request): Azure.ResourceManager.ArmNoContentResponse<"Action completed successfully."> | Error +op Azure.ResourceManager.Extension.ActionNoContentSync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.TargetProviderNamespace", extensionProvider: "Microsoft.ExtensionProviderNamespace", body: Request): Azure.ResourceManager.ArmNoContentResponse<"Action completed successfully."> | Error ``` #### Template Parameters @@ -1190,7 +1190,7 @@ op Azure.ResourceManager.Extension.ActionNoContentSync(apiVersion: string, subsc ### `ActionNoResponseContentAsync` {#Azure.ResourceManager.Extension.ActionNoResponseContentAsync} ```typespec -op Azure.ResourceManager.Extension.ActionNoResponseContentAsync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced", body: Request): Azure.ResourceManager.ArmAcceptedLroResponse | Error +op Azure.ResourceManager.Extension.ActionNoResponseContentAsync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.TargetProviderNamespace", extensionProvider: "Microsoft.ExtensionProviderNamespace", body: Request): Azure.ResourceManager.ArmAcceptedLroResponse | Error ``` #### Template Parameters @@ -1210,7 +1210,7 @@ op Azure.ResourceManager.Extension.ActionNoResponseContentAsync(apiVersion: stri A synchronous resource action. ```typespec -op Azure.ResourceManager.Extension.ActionSync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced", body: Request): Response | Error +op Azure.ResourceManager.Extension.ActionSync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.TargetProviderNamespace", extensionProvider: "Microsoft.ExtensionProviderNamespace", body: Request): Response | Error ``` #### Template Parameters @@ -1230,7 +1230,7 @@ op Azure.ResourceManager.Extension.ActionSync(apiVersion: string, subscriptionId Check a resource's existence via HEAD operation ```typespec -op Azure.ResourceManager.Extension.CheckExistence(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced"): Response | Error +op Azure.ResourceManager.Extension.CheckExistence(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.TargetProviderNamespace", extensionProvider: "Microsoft.ExtensionProviderNamespace"): Response | Error ``` #### Template Parameters @@ -1246,7 +1246,7 @@ op Azure.ResourceManager.Extension.CheckExistence(apiVersion: string, subscripti ### `CreateOrReplaceAsync` {#Azure.ResourceManager.Extension.CreateOrReplaceAsync} ```typespec -op Azure.ResourceManager.Extension.CreateOrReplaceAsync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced", resource: ExtensionResource): Response | Error +op Azure.ResourceManager.Extension.CreateOrReplaceAsync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.TargetProviderNamespace", extensionProvider: "Microsoft.ExtensionProviderNamespace", resource: ExtensionResource): Response | Error ``` #### Template Parameters @@ -1265,7 +1265,7 @@ op Azure.ResourceManager.Extension.CreateOrReplaceAsync(apiVersion: string, subs Synchronous PUT operation for Azure Resource Manager resources ```typespec -op Azure.ResourceManager.Extension.CreateOrReplaceSync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced", resource: ExtensionResource): Response | Error +op Azure.ResourceManager.Extension.CreateOrReplaceSync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.TargetProviderNamespace", extensionProvider: "Microsoft.ExtensionProviderNamespace", resource: ExtensionResource): Response | Error ``` #### Template Parameters @@ -1283,7 +1283,7 @@ op Azure.ResourceManager.Extension.CreateOrReplaceSync(apiVersion: string, subsc A long-running resource CreateOrUpdate (PUT) ```typespec -op Azure.ResourceManager.Extension.CreateOrUpdateAsync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced", resource: ExtensionResource): Response | Error +op Azure.ResourceManager.Extension.CreateOrUpdateAsync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.TargetProviderNamespace", extensionProvider: "Microsoft.ExtensionProviderNamespace", resource: ExtensionResource): Response | Error ``` #### Template Parameters @@ -1302,7 +1302,7 @@ op Azure.ResourceManager.Extension.CreateOrUpdateAsync(apiVersion: string, subsc A long-running resource update using a custom PATCH payload (Asynchronous) ```typespec -op Azure.ResourceManager.Extension.CustomPatchAsync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced", properties: PatchModel): Response | Error +op Azure.ResourceManager.Extension.CustomPatchAsync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.TargetProviderNamespace", extensionProvider: "Microsoft.ExtensionProviderNamespace", properties: PatchModel): Response | Error ``` #### Template Parameters @@ -1322,7 +1322,7 @@ op Azure.ResourceManager.Extension.CustomPatchAsync(apiVersion: string, subscrip A resource update using a custom PATCH payload (synchronous) ```typespec -op Azure.ResourceManager.Extension.CustomPatchSync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced", properties: PatchModel): Response | Error +op Azure.ResourceManager.Extension.CustomPatchSync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.TargetProviderNamespace", extensionProvider: "Microsoft.ExtensionProviderNamespace", properties: PatchModel): Response | Error ``` #### Template Parameters @@ -1343,7 +1343,7 @@ op Azure.ResourceManager.Extension.CustomPatchSync(apiVersion: string, subscript ::: ```typespec -op Azure.ResourceManager.Extension.DeleteAsync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced"): Response | Error +op Azure.ResourceManager.Extension.DeleteAsync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.TargetProviderNamespace", extensionProvider: "Microsoft.ExtensionProviderNamespace"): Response | Error ``` #### Template Parameters @@ -1360,7 +1360,7 @@ op Azure.ResourceManager.Extension.DeleteAsync(apiVersion: string, subscriptionI ### `DeleteAsyncBase` {#Azure.ResourceManager.Extension.DeleteAsyncBase} ```typespec -op Azure.ResourceManager.Extension.DeleteAsyncBase(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced"): Response | Error +op Azure.ResourceManager.Extension.DeleteAsyncBase(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.TargetProviderNamespace", extensionProvider: "Microsoft.ExtensionProviderNamespace"): Response | Error ``` #### Template Parameters @@ -1378,7 +1378,7 @@ op Azure.ResourceManager.Extension.DeleteAsyncBase(apiVersion: string, subscript Delete a resource synchronously ```typespec -op Azure.ResourceManager.Extension.DeleteSync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced"): Response | Error +op Azure.ResourceManager.Extension.DeleteSync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.TargetProviderNamespace", extensionProvider: "Microsoft.ExtensionProviderNamespace"): Response | Error ``` #### Template Parameters @@ -1394,7 +1394,7 @@ op Azure.ResourceManager.Extension.DeleteSync(apiVersion: string, subscriptionId ### `DeleteWithoutOkAsync` {#Azure.ResourceManager.Extension.DeleteWithoutOkAsync} ```typespec -op Azure.ResourceManager.Extension.DeleteWithoutOkAsync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced"): Response | Error +op Azure.ResourceManager.Extension.DeleteWithoutOkAsync(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.TargetProviderNamespace", extensionProvider: "Microsoft.ExtensionProviderNamespace"): Response | Error ``` #### Template Parameters @@ -1413,7 +1413,7 @@ op Azure.ResourceManager.Extension.DeleteWithoutOkAsync(apiVersion: string, subs List an extension resource at the given target scope ```typespec -op Azure.ResourceManager.Extension.ListByTarget(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced"): Response | Error +op Azure.ResourceManager.Extension.ListByTarget(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.TargetProviderNamespace", extensionProvider: "Microsoft.ExtensionProviderNamespace"): Response | Error ``` #### Template Parameters @@ -1431,7 +1431,7 @@ op Azure.ResourceManager.Extension.ListByTarget(apiVersion: string, subscription A resource GET operation ```typespec -op Azure.ResourceManager.Extension.Read(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.ThisWillBeReplaced", extensionProvider: "Microsoft.ThisWillBeReplaced"): Response | Error +op Azure.ResourceManager.Extension.Read(apiVersion: string, subscriptionId: Azure.Core.uuid, resourceGroupName: string, provider: "Microsoft.TargetProviderNamespace", extensionProvider: "Microsoft.ExtensionProviderNamespace"): Response | Error ``` #### Template Parameters