Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate type definitions for readonly resources #780

Closed
wants to merge 16 commits into from

Conversation

jeskew
Copy link
Contributor

@jeskew jeskew commented May 2, 2022

As a first step towards resolving Azure/bicep#1398, this PR adds a Flags property to the serialized bicep resource type to inform the compiler whether resources are read-only, write-only, or support both reading and writing. This will allow the compiler to handle existing resources for read-only types while disallowing their use as regular resource types.

Because the aforementioned change surfaced a few write-only resources, additional flags were added to object properties to allow the compiler to know what could be read off of a PUT response vs off of a GET response. Per this comment, PUT responses are not used for resources that are provisioned asynchronously, so an Async flag was added to resources whose PUT operation has the x-ms-long-running-operation swagger extension set to a truthy value.

For backwards compatibility, flags only indicate deviations from the norm, so ResourceFlags.None represents a resource that is both readable and writable. The Bicep.Types library, even with this change, will treat existing serialized resources as having a flag of ResourceFlags.None, so there's no need to coordinate a release of that library with one of the k8s types.

jeskew added 4 commits May 1, 2022 15:16
The initial set of flags only includes two markers, one of which indicates that a resource can be read via an RP API, the other of which indicates that the resource can be written.

This change was made in order to support read-only resources (which are currently excluded from Bicep type files) as "existing" resources in bicep files.

Additional flags may be added in the future to support special treatment by the bicep compiler (e.g., for singleton or immutable resources).
@jeskew jeskew requested a review from a team May 2, 2022 16:47
@codecov-commenter
Copy link

codecov-commenter commented May 2, 2022

Codecov Report

Merging #780 (55b278d) into main (1f7f2b8) will increase coverage by 0.24%.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #780      +/-   ##
==========================================
+ Coverage   95.57%   95.81%   +0.24%     
==========================================
  Files          18       18              
  Lines         294      311      +17     
==========================================
+ Hits          281      298      +17     
  Misses         13       13              
Flag Coverage Δ
dotnet 95.81% <ø> (+0.24%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
src/Bicep.Types/Concrete/ObjectType.cs 100.00% <0.00%> (ø)
src/Bicep.Types/Concrete/ResourceType.cs 100.00% <0.00%> (ø)
src/Bicep.Types.UnitTests/TypeSerializerTests.cs 100.00% <0.00%> (ø)

@jeskew jeskew enabled auto-merge (squash) May 2, 2022 18:21
* **Valid Scope(s)**: Subscription, ResourceGroup
### Properties
* **apiVersion**: '2020-01-01' (ReadOnly, DeployTimeConstant): The resource api version
* **id**: string (ReadOnly, DeployTimeConstant): The resource id
* **name**: 'default' (Required, DeployTimeConstant): The resource name
* **properties**: [ConfigDataProperties](#configdataproperties): Configuration data properties
* **properties**: [ConfigDataProperties](#configdataproperties) (WriteOnly): Configuration data properties
Copy link
Contributor Author

@jeskew jeskew May 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This resource is being flagged correctly as WriteOnly (the singular configurations endpoint only defines a PUT operation and no GET operation), but I don't think that WriteOnly status should be propagated down to individual properties. This particular property is part of the response the RP returns on resource creation, so it should be something that can be dereferenced off the resource elsewhere in a template. The test that currently determines whether a property is WriteOnly is a check to see whether the property defined on the resource's PUT request is also defined on the resource's GET request, but there are properties that can be specified on a PUT that the RP will not echo back in the response, e.g., the certificates provided as part of the creation of an Microsoft.Attestation/attestationProviders resource. I believe the latter is what is actually meant by WriteOnly, but updating the generator to reflect that meaning is potentially a breaking change (and in any case should happen in a separate PR).

/cc @shenglol

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is that if a property is write-only if it can set in PUT requests but is not returned in GET responses. When a resource's property is referenced in a Bicep file, once compiled, it will be transformed into an ARM template expression containing a reference function call. To resolve the reference function, the ARM deployment engine will not read the resource PUT response, but it will send a GET request to get the resource body.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's a bit more complexity to untangle here, but I don't think this PR is the place to do it. JSON ARM templates will permit reading from a Microsoft.Advisor/configurations resource that was created in the same template iff the resource is referenced by name rather than resource ID:

image
deref_without_get

When the same template is altered to use a resource ID rather than a resource name, the deployment fails:

image
deref_by_resource_id

To account for this in the Bicep compiler, properties would need to carry more metadata, and the compiler would need to distinguish between existing vs owned resources when evaluating property access. The set of circumstances in which that level of distinction is necessary seems fairly uncommon, since there are only a handful of write-only resources, and I believe most RP APIs return the same structure for both GET and PUT operations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good find! Totally agree that this is a complex problem, and it should be out of the scope of this PR. I think I was not entirely correct about how reference functions are evaluated. After checking the deployment engine code again, it seems that the deployment engine will always send a GET request if the API version parameter is provided for a reference function. Otherwise, it reads the job metadata which contains a resource definition once a resource deployment job is complete. However, whether the resource definition is from a PUT or GET response depends on if the resource type supports asynchronous PUT operations...which we cannot tell from the resource type's Swagger definition.

@jorgecotillo as FYI (and please correct me if I'm wrong).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, whether the resource definition is from a PUT or GET response depends on if the resource type supports asynchronous PUT operations...which we cannot tell from the resource type's Swagger definition.

Can this be inferred from the presence of a x-ms-long-running-operation extension? Or is the GET flow only used for resources that use the Azure-AsyncOperation header (which wouldn't be encoded in the Swagger definition)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh yes the x-ms-long-running-operation extension can be used (thanks for reminding me!). It needs to be set as long as a resource operation is asynchronous regardless of the use of the Azure-AsyncOperation header. The only minor issue might be that there exists RPs who forgot to set the extension for their resource types (e.g., Blueprint...which is our team 😅), and they won't be fixed since that will cause breaking changes in the generated SDKs, but I think we just can treat them as provider errors.

@jeskew jeskew disabled auto-merge May 9, 2022 20:16
@jeskew jeskew marked this pull request as draft May 9, 2022 20:17
@jeskew
Copy link
Contributor Author

jeskew commented May 26, 2022

Closing in favor of #805

@jeskew jeskew closed this May 26, 2022
@jeskew jeskew deleted the jeskew/generate-readonly-resources branch May 26, 2022 17:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants