Skip to content

Add Parameterize to generate an SDK for a specific API version#4010

Merged
thomas11 merged 14 commits into
masterfrom
tkappler/parametrize
Mar 14, 2025
Merged

Add Parameterize to generate an SDK for a specific API version#4010
thomas11 merged 14 commits into
masterfrom
tkappler/parametrize

Conversation

@thomas11

@thomas11 thomas11 commented Mar 5, 2025

Copy link
Copy Markdown
Contributor
> PULUMI_DEBUG_PROVIDERS="azure-native:60383" pulumi package add azure-native storage v20240101
Successfully generated a Nodejs SDK for the azure-native_storage_v20240101 package at /Users/tkappler/pulumi/repro/azn-param/sdks/azure-native_storage_v20240101

> head -3 index.ts
import * as resources from "@pulumi/azure-native/resources";
import * as storage_v20240101 from "@pulumi/azure-native_storage_v20240101";

> rg _storage package.json
10:        "@pulumi/azure-native_storage_v20240101": "file:sdks/azure-native_storage_v20240101",

> PULUMI_DEBUG_PROVIDERS="azure-native:60383" pulumi up
...
 +   └─ azure-native_storage_v20240101:storage/v20240101:StorageAccount  sa             created (27s) 

I picked an approach that's, I hope, pragmatic rather than elegant, in that I assume we can keep the full schema and metadata available for the provider and generate dedicated versioned schemas simply by picking the required parts from the full schema. This avoids having to publish and download or clone data at generation time. A more dynamic approach is equally possible, of course, and could be swapped in without changing the interface.

To understand the PR you should be familiar with these docs.

The input and behavior of Parameterize is the same in the initial "args" call of Parameterize and in the subsequent "serialized parameters" calls: a pair of (Azure module, API version). The existing full schema and metadata are narrowed down to members belonging to the given module at the given version.

Implementation note on resources.PartialAzureAPIMetadata and resources.APIMetadata: the provider used to store metadata in a PartialAzureAPIMetadata. During Parameterize, we couldn't replace this metadata with the new one which was of type AzureAPIMetadata. Using the new APIMetadata we can accomodate both because it uses MapLike which can be a full or a partial map. It turned out that this change also simplified some other code using these types.

Related to #2467

@thomas11 thomas11 self-assigned this Mar 5, 2025
@thomas11 thomas11 requested review from a team and danielrbradley March 5, 2025 17:07
@github-actions

github-actions Bot commented Mar 5, 2025

Copy link
Copy Markdown
Contributor

Does the PR have any schema changes?

Looking good! No breaking changes found.
No new resources/functions.

Comment thread provider/pkg/provider/provider_parameterize.go Outdated
Comment thread provider/pkg/provider/provider.go Outdated
@codecov

codecov Bot commented Mar 6, 2025

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 69.91150% with 68 lines in your changes missing coverage. Please review.

Project coverage is 57.84%. Comparing base (aefacb4) to head (2d29cbb).
Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
provider/pkg/provider/provider_parameterize.go 67.77% 47 Missing and 21 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4010      +/-   ##
==========================================
+ Coverage   57.67%   57.84%   +0.16%     
==========================================
  Files          82       83       +1     
  Lines       13156    13369     +213     
==========================================
+ Hits         7588     7733     +145     
- Misses       4991     5037      +46     
- Partials      577      599      +22     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@thomas11 thomas11 force-pushed the tkappler/parametrize branch from f2266e3 to f1feb3d Compare March 11, 2025 07:56
@thomas11 thomas11 changed the title First working attempt at Parameterize to generate an SDK for a specific API version Add Parameterize to generate an SDK for a specific API version Mar 11, 2025

@danielrbradley danielrbradley left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks great!

}
return &parameterizeArgs{
Module: args[0],
Version: args[1], // TODO be more accepting of version format and convert

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The version is definitely worth validating a little more up front to only the formats we accept. Though it will fail later when we try to find the spec, it would probably have a nicer error from here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm planning to accept a few formats and then convert them to the v20xxxxxx we need for lookups.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Pushed

//
// To separate concerns, the `Parameterization` of the new schema is NOT populated yet, the caller is responsible for
// doing that.
func createSchema(p *azureNativeProvider, schema pschema.PackageSpec, targetModule, targetApiVersion string) (*pschema.PackageSpec, *resources.APIMetadata, error) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

A general thought here .. we should measure how fast this step is and how much memory the schema consumes in memory. I'd guess it's not too much, but if we wanted to make this a little more efficient, we could just generate the metadata and delay doing the schema until we call GetSchema. Might not be worth the effort though if this is only taking a fraction of a second.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good call.

I added runtime.GC() at the top and pprof.Lookup("heap") at the end of Parameterize. From go tool pprof:

(pprof) focus=github.com/pulumi/pulumi-azure-native/v2/provider/pkg/provider.TestParameterizeCreatesSchemaAndMetadata

(pprof) top10
Active filters:
   focus=github.com/pulumi/pulumi-azure-native/v2/provider/pkg/provider.TestParamet…
Showing nodes accounting for 160.35MB, 40.29% of 398.03MB total
      flat  flat%   sum%        cum   cum%
  159.20MB 40.00% 40.00%   159.20MB 40.00%  os.readFileContents
    1.16MB  0.29% 40.29%     1.16MB  0.29%  runtime/pprof.StartCPUProfile
         0     0% 40.29%     1.16MB  0.29%  github.com/pulumi/pulumi-azure-native/v2/provider/pkg/provider.(*azureNativeProvider).Parameterize
         0     0% 40.29%   160.35MB 40.29%  github.com/pulumi/pulumi-azure-native/v2/provider/pkg/provider.TestParameterizeCreatesSchemaAndMetadata

Looks like Parameterize itself only uses 1.16MB, the rest is reading the full schema in the test. (Please double-check my reasoning.)

For CPU, I used StartCPUProfile/StopCPUProfile. From go tool pprof:

0     0% 28.97%      0.62s 28.97%  github.com/pulumi/pulumi-azure-native/v2/provider/pkg/provider.(*azureNativeProvider).Parameterize

Looks harmless to me although I'm not exactly a pprof expert.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Coolio, yeah that looks fine .. can always dig into optimisations later .. e.g. if we find people wanting to use 20 different parameterizations or something and running out of memory - perhaps we can purge the old schema and metadata.

@thomas11 thomas11 enabled auto-merge (squash) March 14, 2025 11:11
v := strings.TrimSpace(version)
v = strings.TrimLeft(v, "vV")

isApiVersion, err := regexp.MatchString(`^20\d{2}-[01]\d-[0-3]\d$`, v)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sidethought: this would probably be a useful function to live in the openapi module

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Oh, does this handle all the preview/private-preview variations?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It does now :)

Would be cool to move this to the openapi package but there are some other concerns there, like handling * wildcards and the empty string meaning the default version. Punting.

@pulumi-bot

Copy link
Copy Markdown
Contributor

This PR has been shipped in release v2.89.2.

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.

Consider using parameterization to generate SDKs for services at explicit API versions

6 participants