diff --git a/Makefile b/Makefile index 915121f8fa58..b409b5875995 100644 --- a/Makefile +++ b/Makefile @@ -231,7 +231,7 @@ bin/$(CODEGEN): .make/prebuild .make/provider_mod_download provider/cmd/$(CODEGE # Writes schema-full.json and metadata-compact.json to bin/ # Also re-calculates files in versions/ at same time -bin/schema-full.json bin/metadata-compact.json &: bin/$(CODEGEN) $(SPECS) versions/az-provider-list.json versions/v${PREVIOUS_MAJOR_VERSION}-lock.json versions/v${MAJOR_VERSION}-config.yaml versions/v${MAJOR_VERSION}-spec.yaml versions/v${MAJOR_VERSION}-removed-resources.json versions/v${NEXT_MAJOR_VERSION}-removed-resources.json +bin/schema-full.json bin/metadata-compact.json &: bin/$(CODEGEN) $(SPECS) versions/az-provider-list.json versions/v${PREVIOUS_MAJOR_VERSION}-lock.json versions/v${MAJOR_VERSION}-config.yaml versions/v${MAJOR_VERSION}-spec.yaml versions/v${MAJOR_VERSION}-removed.json versions/v${MAJOR_VERSION}-removed-resources.json versions/v${NEXT_MAJOR_VERSION}-removed-resources.json bin/$(CODEGEN) schema $(PROVIDER_VERSION) # Docs schema - treat as phony becasuse it's committed so we always need to rebuild it. diff --git a/provider/pkg/gen/gen_aliases_test.go b/provider/pkg/gen/gen_aliases_test.go index f7ac8a06cc6c..c7e172cb67d3 100644 --- a/provider/pkg/gen/gen_aliases_test.go +++ b/provider/pkg/gen/gen_aliases_test.go @@ -5,6 +5,7 @@ import ( "path" "testing" + "github.com/blang/semver" "github.com/gkampitakis/go-snaps/snaps" "github.com/pulumi/pulumi-azure-native/v2/provider/pkg/openapi" ) @@ -30,7 +31,7 @@ func TestAliasesGen(t *testing.T) { } t.Run("v2", func(t *testing.T) { - generationResult, err := PulumiSchema(rootDir, providers, versioningStub{}, 2) + generationResult, err := PulumiSchema(rootDir, providers, versioningStub{}, semver.MustParse("2.0.0")) if err != nil { t.Fatal(err) } @@ -40,7 +41,7 @@ func TestAliasesGen(t *testing.T) { }) t.Run("v3", func(t *testing.T) { - generationResult, err := PulumiSchema(rootDir, providers, versioningStub{}, 3) + generationResult, err := PulumiSchema(rootDir, providers, versioningStub{}, semver.MustParse("3.0.0")) if err != nil { t.Fatal(err) } diff --git a/provider/pkg/gen/gen_dashboard_test.go b/provider/pkg/gen/gen_dashboard_test.go index b9383a0b5a1b..29bd10217f42 100644 --- a/provider/pkg/gen/gen_dashboard_test.go +++ b/provider/pkg/gen/gen_dashboard_test.go @@ -5,6 +5,7 @@ import ( "path" "testing" + "github.com/blang/semver" "github.com/gkampitakis/go-snaps/snaps" "github.com/pulumi/pulumi-azure-native/v2/provider/pkg/openapi" "github.com/stretchr/testify/assert" @@ -33,7 +34,7 @@ func TestPortalDashboardGen(t *testing.T) { "Dashboard": "2020-09-01-preview", }, }, openapi.DefaultVersionLock{}, nil, nil) - generationResult, err := PulumiSchema(rootDir, providers, versioningStub{}, 2) + generationResult, err := PulumiSchema(rootDir, providers, versioningStub{}, semver.MustParse("3.0.0")) if err != nil { t.Fatal(err) } diff --git a/provider/pkg/gen/gen_vnet_test.go b/provider/pkg/gen/gen_vnet_test.go index 33c0717e86b1..368a8f092ac0 100644 --- a/provider/pkg/gen/gen_vnet_test.go +++ b/provider/pkg/gen/gen_vnet_test.go @@ -5,6 +5,7 @@ import ( "path" "testing" + "github.com/blang/semver" "github.com/gkampitakis/go-snaps/snaps" "github.com/pulumi/pulumi-azure-native/v2/provider/pkg/openapi" ) @@ -25,7 +26,7 @@ func TestVnetGen(t *testing.T) { if err != nil { t.Fatal(err) } - generationResult, err := PulumiSchema(rootDir, providers, versioningStub{}, 2) + generationResult, err := PulumiSchema(rootDir, providers, versioningStub{}, semver.MustParse("2.0.0")) if err != nil { t.Fatal(err) } diff --git a/provider/pkg/gen/schema.go b/provider/pkg/gen/schema.go index 220225d1efb2..a27434fe1cb3 100644 --- a/provider/pkg/gen/schema.go +++ b/provider/pkg/gen/schema.go @@ -32,6 +32,7 @@ import ( "github.com/pkg/errors" "github.com/pulumi/pulumi-azure-native/v2/provider/pkg/openapi" + "github.com/pulumi/pulumi-azure-native/v2/provider/pkg/openapi/paths" "github.com/pulumi/pulumi-azure-native/v2/provider/pkg/resources" "github.com/pulumi/pulumi-azure-native/v2/provider/pkg/resources/customresources" "github.com/pulumi/pulumi/pkg/v3/codegen" @@ -64,10 +65,13 @@ type GenerationResult struct { ForceNewTypes []ForceNewType TypeCaseConflicts CaseConflicts FlattenedPropertyConflicts map[string]map[string]struct{} + // A map of provider -> resource -> set of paths, to record resources that have conflicts where the same resource + // maps to more than one API path. + PathConflicts map[openapi.ProviderName]map[openapi.ResourceName]map[string][]openapi.ApiVersion } // PulumiSchema will generate a Pulumi schema for the given Azure providers and resources map. -func PulumiSchema(rootDir string, providerMap openapi.AzureProviders, versioning Versioning, majorVersion int) (*GenerationResult, error) { +func PulumiSchema(rootDir string, providerMap openapi.AzureProviders, versioning Versioning, providerVersion semver.Version) (*GenerationResult, error) { pkg := pschema.PackageSpec{ Name: "azure-native", Description: "A native Pulumi package for creating and managing Azure resources.", @@ -282,6 +286,7 @@ func PulumiSchema(rootDir string, providerMap openapi.AzureProviders, versioning caseSensitiveTypes := newCaseSensitiveTokens() flattenedPropertyConflicts := map[string]map[string]struct{}{} exampleMap := make(map[string][]resources.AzureAPIExample) + resourcesPathTracker := newResourcesPathConflictsTracker() for _, providerName := range providers { versionMap := providerMap[providerName] @@ -291,6 +296,8 @@ func PulumiSchema(rootDir string, providerMap openapi.AzureProviders, versioning } slices.Sort(versions) + resourcePaths := map[openapi.ResourceName]map[string][]openapi.ApiVersion{} + for _, sdkVersion := range versions { // Attempt to convert back to an API version for use elsewhere var apiVersion *openapi.ApiVersion @@ -301,6 +308,7 @@ func PulumiSchema(rootDir string, providerMap openapi.AzureProviders, versioning } apiVersion = &apiVersionConverted } + gen := packageGenerator{ pkg: &pkg, metadata: &metadata, @@ -313,7 +321,8 @@ func PulumiSchema(rootDir string, providerMap openapi.AzureProviders, versioning caseSensitiveTypes: caseSensitiveTypes, rootDir: rootDir, flattenedPropertyConflicts: flattenedPropertyConflicts, - majorVersion: majorVersion, + majorVersion: int(providerVersion.Major), + resourcePaths: map[openapi.ResourceName]map[string]openapi.ApiVersion{}, } // Populate C#, Java, Python and Go module mapping. @@ -347,8 +356,18 @@ func PulumiSchema(rootDir string, providerMap openapi.AzureProviders, versioning // Populate invokes. gen.genInvokes(items.Invokes) + forceNewTypes = append(forceNewTypes, gen.forceNewTypes...) + gen.mergeResourcePathsInto(resourcePaths) } + + resourcesPathTracker.addPathConflictsForProvider(providerName, resourcePaths) + } + + // When a resource maps to more than one API path, it's a conflict and we need to detect and report it. #2495 + isReleaseBuild := len(providerVersion.Build) == 0 + if providerVersion.Major >= 3 && isReleaseBuild && resourcesPathTracker.hasConflicts() { + return nil, fmt.Errorf("path conflicts detected. You probably need to add a case to schema.go/dedupResourceNameByPath.\n%+v", resourcesPathTracker.pathConflicts) } err := genMixins(&pkg, &metadata) @@ -410,9 +429,35 @@ version using infrastructure as code, which Pulumi then uses to drive the ARM AP ForceNewTypes: forceNewTypes, TypeCaseConflicts: caseSensitiveTypes.findCaseConflicts(), FlattenedPropertyConflicts: flattenedPropertyConflicts, + PathConflicts: resourcesPathTracker.pathConflicts, }, nil } +// resourcesPathConflictsTracker tracks resource path conflicts by provider/module. Use newResourcesPathTracker to instantiate. +type resourcesPathConflictsTracker struct { + pathConflicts map[openapi.ProviderName]map[openapi.ResourceName]map[string][]openapi.ApiVersion +} + +func newResourcesPathConflictsTracker() *resourcesPathConflictsTracker { + return &resourcesPathConflictsTracker{pathConflicts: map[openapi.ProviderName]map[openapi.ResourceName]map[string][]openapi.ApiVersion{}} +} + +func (rpt *resourcesPathConflictsTracker) addPathConflictsForProvider(providerName openapi.ProviderName, resourcePaths map[openapi.ResourceName]map[string][]openapi.ApiVersion) { + providerPathConflicts := map[openapi.ResourceName]map[string][]openapi.ApiVersion{} + for resource, paths := range resourcePaths { + if len(paths) > 1 { + providerPathConflicts[resource] = paths + } + } + if len(providerPathConflicts) > 0 { + rpt.pathConflicts[providerName] = providerPathConflicts + } +} + +func (rpt *resourcesPathConflictsTracker) hasConflicts() bool { + return len(rpt.pathConflicts) > 0 +} + func (g *packageGenerator) genInvokes(invokes map[string]*openapi.ResourceSpec) { var invokeNames []string for invokeName := range invokes { @@ -643,6 +688,9 @@ type packageGenerator struct { forceNewTypes []ForceNewType flattenedPropertyConflicts map[string]map[string]struct{} majorVersion int + // A resource -> path -> API version map to record API paths per resource and later detect conflicts. + // Each packageGenerator instance is only used for a single API version, so there won't be conflicting paths here. + resourcePaths map[openapi.ResourceName]map[string]openapi.ApiVersion } func (g *packageGenerator) genResources(typeName string, resource *openapi.ResourceSpec, nestedResourceBodyRefs []string) error { @@ -775,16 +823,134 @@ func (g *packageGenerator) findResourceVariants(resource *openapi.ResourceSpec) return result, nil } +// dedupResourceNameByPath returns a modified resource name (`typeName`) if the resource is mapped to multiple API +// paths. For instance, the deprecated "single server" resources in `dbformysql` and `dbforpostgresql` are renamed +// to `SingleServerResource`. +// TODO,tkappler check each one if we can just get rid of an old API version instead of doing this. +func dedupResourceNameByPath(provider, typeName, canonPath string) string { + result := typeName + + prefix := func(prefix string) string { + if !strings.HasPrefix(typeName, prefix) { + return prefix + typeName + } + return typeName + } + + switch strings.ToLower(provider) { + case "cache": + if strings.Contains(canonPath, "/redis/") { + result = prefix("Redis") + } else if strings.Contains(canonPath, "/redisenterprise/") { + result = prefix("RedisEnterprise") + } + // $ rg --only-matching --no-filename --glob '!examples' 'providers/Microsoft.DBforMySQL/.+?/' azure-rest-api-specs/specification/ | sort | uniq + // providers/Microsoft.DBforMySQL/flexibleServers/ + // providers/Microsoft.DBforMySQL/servers/ + case "dbformysql": + if strings.Contains(canonPath, "/servers/") { + result = prefix("SingleServer") + } + // $ rg --only-matching --no-filename --glob '!examples' 'providers/Microsoft.DBforPostgreSQL/.+?/' azure-rest-api-specs/specification/ | sort | uniq + // providers/Microsoft.DBforPostgreSQL/flexibleServers/ + // providers/Microsoft.DBforPostgreSQL/serverGroupsv2/ + // providers/Microsoft.DBforPostgreSQL/servers/ + case "dbforpostgresql": + if strings.Contains(canonPath, "/servers/") { + result = prefix("SingleServer") + } else if strings.Contains(canonPath, "/servergroupsv2/") { + result = prefix("ServerGroup") + } + case "documentdb": + if strings.Contains(canonPath, "/mongoclusters/") { + prefix("MongoCluster") + } + case "hdinsight": + if strings.Contains(canonPath, "/clusterpools/") { + result = prefix("ClusterPool") + } + case "hybridcontainerservice": + if strings.Contains(canonPath, "/provisionedclusterinstances/") { + result = prefix("ClusterInstance") + } + case "labservices": + // /labaccounts is an old API that only occurs in 2018 but we support it in v2 + if strings.Contains(canonPath, "/labaccounts/") { + result = prefix("LabAccount") + } + case "migrate": + if strings.Contains(canonPath, "/assessmentprojects/") { + result = prefix("AssessmentProjects") + } + case "mobilenetwork": + if strings.Contains(canonPath, "/simgroups/") { + result = prefix("SimGroup") + } + case "netapp": + if strings.Contains(canonPath, "/backupvaults/") { + result = prefix("BackupVault") + } else if strings.Contains(canonPath, "/capacitypools/") { + result = prefix("CapacityPool") + } + } + + return result +} + +// recordPath adds path to keep track of all API paths a resource is mapped to. +func (g *packageGenerator) recordPath(typeName openapi.ResourceName, canonPath string, apiVersion openapi.ApiVersion) { + // Some resources have a /default path, e.g., azure-native:azurestackhci:GuestAgent has conflicting paths + // /subscriptions/{}/resourcegroups/{}/providers/microsoft.azurestackhci/virtualmachines/{}/guestagents/{}, + // /{}/providers/microsoft.azurestackhci/virtualmachineinstances/default/guestagents/default, + // also azure-native:hybridcontainerservice:HybridIdentityMetadatum + if strings.HasSuffix(canonPath, "/default") { + return + } + + // We use the map here only as a tuple of (path, apiVersion), it will only have a single key. + g.resourcePaths[typeName] = map[string]openapi.ApiVersion{canonPath: apiVersion} +} + +// mergeResourcePathsInto merges this packageGenerator's resource paths into the given map. This happens for each API +// version, so that in the end `resourcePaths` contains all paths for each resource and API version. +func (g *packageGenerator) mergeResourcePathsInto(resourcePaths map[openapi.ResourceName]map[string][]openapi.ApiVersion) { + for resource, path := range g.resourcePaths { + if _, ok := resourcePaths[resource]; !ok { + resourcePaths[resource] = map[string][]openapi.ApiVersion{} + } + for path, apiVersion := range path { + if _, ok := resourcePaths[resource][path]; !ok { + resourcePaths[resource][path] = []openapi.ApiVersion{} + } + apiVersions := append(resourcePaths[resource][path], apiVersion) + slices.Sort(apiVersions) + resourcePaths[resource][path] = apiVersions + } + } +} + func (g *packageGenerator) genResourceVariant(apiSpec *openapi.ResourceSpec, resource *resourceVariant, nestedResourceBodyRefs []string, typeNameAliases ...string) error { module := g.moduleName() swagger := resource.Swagger path := resource.PathItem + canonPath := paths.NormalizePath(resource.Path) + + typeName := resource.typeName + if g.majorVersion > 3 { + typeName = dedupResourceNameByPath(g.provider, resource.typeName, canonPath) + } - resourceTok := fmt.Sprintf(`%s:%s:%s`, g.pkg.Name, module, resource.typeName) - if !g.versioning.ShouldInclude(g.provider, g.apiVersion, resource.typeName, resourceTok) { + resourceTok := generateTok(g.provider, typeName, g.sdkVersion) + if !g.versioning.ShouldInclude(g.provider, g.apiVersion, typeName, resourceTok) { return nil } + apiVersion := openapi.ApiVersion("default") + if g.apiVersion != nil { + apiVersion = *g.apiVersion + } + g.recordPath(typeName, canonPath, apiVersion) + // Generate the resource. gen := moduleGenerator{ pkg: g.pkg, diff --git a/provider/pkg/gen/schema_test.go b/provider/pkg/gen/schema_test.go index 5fe1e6659e2f..c05c2975dd11 100644 --- a/provider/pkg/gen/schema_test.go +++ b/provider/pkg/gen/schema_test.go @@ -359,3 +359,74 @@ func TestGoModuleName(t *testing.T) { assert.Equal(t, "github.com/pulumi/pulumi-azure-native-sdk/network/v2", goModuleName("Network", "")) }) } + +func TestDedupResourceNameByPath(t *testing.T) { + t.Run("no change", func(t *testing.T) { + assert.Equal(t, "Resource", dedupResourceNameByPath("compute", "Resource", "/subscriptions/{}/resourceGroups/{}/providers/Microsoft.Compute/virtualmachines/{}")) + }) + + t.Run("dbformysql single server", func(t *testing.T) { + assert.Equal(t, "SingleServerResource", dedupResourceNameByPath("dbformysql", "Resource", "/subscriptions/{}/resourcegroups/{}/providers/Microsoft.DBforMySQL/servers/{}")) + }) + + t.Run("dbformysql flexible server", func(t *testing.T) { + assert.Equal(t, "Resource", dedupResourceNameByPath("dbformysql", "Resource", "/subscriptions/{}/resourcegroups/{}/providers/Microsoft.DBforMySQL/flexibleservers/{}")) + }) + + t.Run("dbforpostgresql single server", func(t *testing.T) { + assert.Equal(t, "SingleServerResource", dedupResourceNameByPath("dbforpostgresql", "Resource", "/subscriptions/{}/resourcegroups/{}/providers/Microsoft.DBforPostgreSQL/servers/{}")) + }) + + t.Run("dbforpostgresql flexible server", func(t *testing.T) { + assert.Equal(t, "Resource", dedupResourceNameByPath("dbforpostgresql", "Resource", "/subscriptions/{}/resourcegroups/{}/providers/Microsoft.DBforPostgreSQL/flexibleservers/{}")) + }) +} + +func TestResourcePathTracker(t *testing.T) { + t.Run("no conflicts, one provider", func(t *testing.T) { + tracker := newResourcesPathConflictsTracker() + tracker.addPathConflictsForProvider("compute", map[openapi.ResourceName]map[string][]openapi.ApiVersion{ + "VirtualMachine": {"/subscriptions/{}/resourceGroups/{}/providers/Microsoft.Compute/virtualMachines/{}": {openapi.ApiVersion("2022-02-22")}}, + }) + assert.False(t, tracker.hasConflicts()) + }) + + t.Run("conflicts, one provider", func(t *testing.T) { + tracker := newResourcesPathConflictsTracker() + tracker.addPathConflictsForProvider("compute", map[openapi.ResourceName]map[string][]openapi.ApiVersion{ + "VirtualMachine": { + "/subscriptions/{}/resourceGroups/{}/providers/Microsoft.Compute/virtualMachines/{}": {openapi.ApiVersion("2022-02-22")}, + "/subscriptions/{}/resourceGroups/{}/providers/Microsoft.Compute/virtualMachinesFoo/{}": {openapi.ApiVersion("2024-04-22")}, + }, + }) + assert.True(t, tracker.hasConflicts()) + }) + + t.Run("no conflicts, multiple providers", func(t *testing.T) { + tracker := newResourcesPathConflictsTracker() + tracker.addPathConflictsForProvider("compute", map[openapi.ResourceName]map[string][]openapi.ApiVersion{ + "VirtualMachine": {"/subscriptions/{}/resourceGroups/{}/providers/Microsoft.Compute/virtualMachines/{}": {openapi.ApiVersion("2022-02-22")}}, + }) + tracker.addPathConflictsForProvider("storage", map[openapi.ResourceName]map[string][]openapi.ApiVersion{ + "StorageAccount": {"/subscriptions/{}/resourceGroups/{}/providers/Microsoft.Storage/storageAccounts/{}": {openapi.ApiVersion("2022-02-22")}}, + }) + assert.False(t, tracker.hasConflicts()) + }) + + t.Run("conflicts, multiple providers", func(t *testing.T) { + tracker := newResourcesPathConflictsTracker() + tracker.addPathConflictsForProvider("storage", map[openapi.ResourceName]map[string][]openapi.ApiVersion{ + "StorageAccount": {"/subscriptions/{}/resourceGroups/{}/providers/Microsoft.Storage/storageAccounts/{}": {openapi.ApiVersion("2022-02-22")}}, + }) + tracker.addPathConflictsForProvider("compute", map[openapi.ResourceName]map[string][]openapi.ApiVersion{ + "VirtualMachine": { + "/subscriptions/{}/resourceGroups/{}/providers/Microsoft.Compute/virtualMachines/{}": {openapi.ApiVersion("2022-02-22")}, + "/subscriptions/{}/resourceGroups/{}/providers/Microsoft.Compute/virtualMachinesFoo/{}": {openapi.ApiVersion("2024-04-22")}, + }, + }) + tracker.addPathConflictsForProvider("migrate", map[openapi.ResourceName]map[string][]openapi.ApiVersion{ + "AssessmentProject": {"/subscriptions/{}/resourceGroups/{}/providers/Microsoft.Migrate/assessmentProjects/{}": {openapi.ApiVersion("2022-02-22")}}, + }) + assert.True(t, tracker.hasConflicts()) + }) +} diff --git a/provider/pkg/versioning/build_schema.go b/provider/pkg/versioning/build_schema.go index 18ce03033328..e956384562ff 100644 --- a/provider/pkg/versioning/build_schema.go +++ b/provider/pkg/versioning/build_schema.go @@ -3,9 +3,8 @@ package versioning import ( "path" "sort" - "strconv" - "strings" + "github.com/blang/semver" "github.com/pulumi/pulumi-azure-native/v2/provider/pkg/gen" "github.com/pulumi/pulumi-azure-native/v2/provider/pkg/openapi" "github.com/pulumi/pulumi-azure-native/v2/provider/pkg/openapi/paths" @@ -33,6 +32,8 @@ type BuildSchemaArgs struct { type BuildSchemaReports struct { PathChangesResult + // providerName -> resourceName -> set of paths, to record resources that have conflicting paths. + PathConflicts map[openapi.ProviderName]map[openapi.ResourceName]map[string][]openapi.ApiVersion AllResourcesByVersion ProvidersVersionResources AllResourceVersionsByResource ProviderResourceVersions Pending openapi.ProviderVersionList @@ -49,19 +50,20 @@ type BuildSchemaReports struct { func (r BuildSchemaReports) WriteTo(outputDir string) ([]string, error) { return gen.EmitFiles(outputDir, gen.FileMap{ - "pathChanges.json": r.PathChangesResult, + "allEndpoints.json": r.AllEndpoints, "allResourcesByVersion.json": r.AllResourcesByVersion, "allResourceVersionsByResource.json": r.AllResourceVersionsByResource, - "pending.json": r.Pending, "curationViolations.json": r.CurationViolations, + "flattenedPropertyConflicts.json": r.FlattenedPropertyConflicts, + "forceNewTypes.json": r.ForceNewTypes, + "inactiveDefaultVersions.json": r.InactiveDefaultVersions, "namingDisambiguations.json": r.NamingDisambiguations, - "skippedPOSTEndpoints.json": r.SkippedPOSTEndpoints, + "pathChanges.json": r.PathChangesResult, + "pathConflicts.json": r.PathConflicts, + "pending.json": r.Pending, "providerNameErrors.json": r.ProviderNameErrors, - "forceNewTypes.json": r.ForceNewTypes, + "skippedPOSTEndpoints.json": r.SkippedPOSTEndpoints, "typeCaseConflicts.json": r.TypeCaseConflicts, - "flattenedPropertyConflicts.json": r.FlattenedPropertyConflicts, - "allEndpoints.json": r.AllEndpoints, - "inactiveDefaultVersions.json": r.InactiveDefaultVersions, }) } @@ -83,7 +85,7 @@ func BuildSchema(args BuildSchemaArgs) (*BuildSchemaResult, error) { return nil, err } - majorVersion, err := strconv.ParseInt(strings.Split(args.Version, ".")[0], 10, 64) + providerVersion, err := semver.Parse(args.Version) if err != nil { return nil, err } @@ -92,7 +94,7 @@ func BuildSchema(args BuildSchemaArgs) (*BuildSchemaResult, error) { if args.OnlyExplicitVersions { versionMetadata = VersionMetadata{} } else { - versionMetadata, err = LoadVersionMetadata(args.RootDir, providers, int(majorVersion)) + versionMetadata, err = LoadVersionMetadata(args.RootDir, providers, int(providerVersion.Major)) if err != nil { return nil, err } @@ -121,7 +123,7 @@ func BuildSchema(args BuildSchemaArgs) (*BuildSchemaResult, error) { InactiveDefaultVersions: versionMetadata.InactiveDefaultVersions, } - generationResult, err := gen.PulumiSchema(args.RootDir, providers, versionMetadata, int(majorVersion)) + generationResult, err := gen.PulumiSchema(args.RootDir, providers, versionMetadata, providerVersion) if err != nil { return &BuildSchemaResult{ @@ -135,6 +137,7 @@ func BuildSchema(args BuildSchemaArgs) (*BuildSchemaResult, error) { buildSchemaReports.ForceNewTypes = generationResult.ForceNewTypes buildSchemaReports.TypeCaseConflicts = generationResult.TypeCaseConflicts buildSchemaReports.FlattenedPropertyConflicts = generationResult.FlattenedPropertyConflicts + buildSchemaReports.PathConflicts = generationResult.PathConflicts pkgSpec := generationResult.Schema metadata := generationResult.Metadata diff --git a/provider/pkg/versioning/gen_bench_test.go b/provider/pkg/versioning/gen_bench_test.go index 220902ee4f95..69857123d52c 100644 --- a/provider/pkg/versioning/gen_bench_test.go +++ b/provider/pkg/versioning/gen_bench_test.go @@ -4,6 +4,7 @@ import ( "path" "testing" + "github.com/blang/semver" "github.com/pulumi/pulumi-azure-native/v2/provider/pkg/gen" "github.com/pulumi/pulumi-azure-native/v2/provider/pkg/openapi" ) @@ -35,5 +36,5 @@ func BenchmarkGen(b *testing.B) { specs = openapi.ApplyProvidersTransformations(specs, versionMetadata.Lock, nil, versionSources.RemovedVersions, nil) - gen.PulumiSchema(rootDir, specs, versionMetadata, 2) + gen.PulumiSchema(rootDir, specs, versionMetadata, semver.MustParse("2.0.0")) } diff --git a/reports/pathConflicts.json b/reports/pathConflicts.json new file mode 100644 index 000000000000..4ea92133f6bf --- /dev/null +++ b/reports/pathConflicts.json @@ -0,0 +1,375 @@ +{ + "ApiManagement": { + "ApiPolicy": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.apimanagement/service/{}/apis/{}/policies/{}": [ + "2018-06-01-preview", + "2022-08-01", + "2022-09-01-preview", + "2023-03-01-preview", + "2023-05-01-preview", + "2023-09-01-preview", + "2024-05-01", + "2024-06-01-preview", + "default" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.apimanagement/service/{}/apis/{}/policy": [ + "2016-10-10" + ] + }, + "ProductPolicy": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.apimanagement/service/{}/products/{}/policies/{}": [ + "2018-06-01-preview", + "2022-08-01", + "2022-09-01-preview", + "2023-03-01-preview", + "2023-05-01-preview", + "2023-09-01-preview", + "2024-05-01", + "2024-06-01-preview", + "default" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.apimanagement/service/{}/products/{}/policy": [ + "2016-10-10" + ] + } + }, + "Cache": { + "AccessPolicyAssignment": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.cache/redis/{}/accesspolicyassignments/{}": [ + "2023-05-01-preview", + "2023-08-01", + "2024-03-01", + "2024-04-01-preview", + "2024-11-01", + "default" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.cache/redisenterprise/{}/databases/{}/accesspolicyassignments/{}": [ + "2024-09-01-preview" + ] + } + }, + "DBforMySQL": { + "Configuration": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbformysql/flexibleservers/{}/configurations/{}": [ + "2020-07-01-privatepreview", + "2022-01-01", + "2023-06-01-preview", + "2023-06-30", + "2023-12-30", + "default" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbformysql/servers/{}/configurations/{}": [ + "2017-12-01" + ] + }, + "Database": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbformysql/flexibleservers/{}/databases/{}": [ + "2022-01-01", + "2023-06-01-preview", + "2023-06-30", + "2023-12-30", + "default" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbformysql/servers/{}/databases/{}": [ + "2017-12-01" + ] + }, + "FirewallRule": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbformysql/flexibleservers/{}/firewallrules/{}": [ + "2022-01-01", + "2023-06-01-preview", + "2023-06-30", + "2023-12-30", + "default" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbformysql/servers/{}/firewallrules/{}": [ + "2017-12-01" + ] + }, + "PrivateEndpointConnection": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbformysql/flexibleservers/{}/privateendpointconnections/{}": [ + "2022-09-30-preview", + "2023-06-30", + "default" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbformysql/servers/{}/privateendpointconnections/{}": [ + "2018-06-01-privatepreview" + ] + }, + "Server": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbformysql/flexibleservers/{}": [ + "2020-07-01-preview", + "2020-07-01-privatepreview", + "2022-01-01", + "2022-09-30-preview", + "2023-06-01-preview", + "2023-06-30", + "2023-10-01-preview", + "2023-12-01-preview", + "2023-12-30", + "2024-02-01-preview", + "2024-06-01-preview", + "2024-10-01-preview", + "default" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbformysql/servers/{}": [ + "2017-12-01", + "2018-06-01-privatepreview" + ] + } + }, + "DBforPostgreSQL": { + "Configuration": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbforpostgresql/flexibleservers/{}/configurations/{}": [ + "2022-12-01", + "2023-03-01-preview", + "2023-06-01-preview", + "2023-12-01-preview", + "2024-03-01-preview", + "2024-08-01", + "2024-11-01-preview", + "default" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbforpostgresql/servers/{}/configurations/{}": [ + "2017-12-01" + ] + }, + "Database": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbforpostgresql/flexibleservers/{}/databases/{}": [ + "2022-12-01", + "2023-03-01-preview", + "2023-06-01-preview", + "2023-12-01-preview", + "2024-03-01-preview", + "2024-08-01", + "2024-11-01-preview", + "default" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbforpostgresql/servers/{}/databases/{}": [ + "2017-12-01" + ] + }, + "FirewallRule": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbforpostgresql/flexibleservers/{}/firewallrules/{}": [ + "2022-12-01", + "2023-03-01-preview", + "2023-06-01-preview", + "2023-12-01-preview", + "2024-03-01-preview", + "2024-08-01", + "2024-11-01-preview", + "default" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbforpostgresql/servergroupsv2/{}/firewallrules/{}": [ + "2020-10-05-privatepreview", + "2022-11-08", + "2023-03-02-preview" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbforpostgresql/servers/{}/firewallrules/{}": [ + "2017-12-01" + ] + }, + "PrivateEndpointConnection": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbforpostgresql/flexibleservers/{}/privateendpointconnections/{}": [ + "2023-06-01-preview", + "2023-12-01-preview", + "2024-03-01-preview", + "2024-08-01", + "2024-11-01-preview" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbforpostgresql/servergroupsv2/{}/privateendpointconnections/{}": [ + "2022-11-08", + "2023-03-02-preview", + "default" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbforpostgresql/servers/{}/privateendpointconnections/{}": [ + "2018-06-01-privatepreview" + ] + }, + "Server": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbforpostgresql/flexibleservers/{}": [ + "2020-02-14-preview", + "2021-04-10-privatepreview", + "2021-06-15-privatepreview", + "2022-03-08-preview", + "2022-12-01", + "2023-03-01-preview", + "2023-06-01-preview", + "2023-12-01-preview", + "2024-03-01-preview", + "2024-08-01", + "2024-11-01-preview", + "default" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.dbforpostgresql/servers/{}": [ + "2017-12-01", + "2017-12-01-preview" + ] + } + }, + "DocumentDB": { + "PrivateEndpointConnection": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.documentdb/databaseaccounts/{}/privateendpointconnections/{}": [ + "2023-04-15", + "2023-09-15", + "2023-09-15-preview", + "2023-11-15", + "2023-11-15-preview", + "2024-02-15-preview", + "2024-05-15", + "2024-05-15-preview", + "2024-08-15", + "2024-09-01-preview", + "2024-11-15", + "2024-12-01-preview", + "default" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.documentdb/mongoclusters/{}/privateendpointconnections/{}": [ + "2024-03-01-preview", + "2024-06-01-preview", + "2024-07-01", + "2024-10-01-preview" + ] + } + }, + "HDInsight": { + "Cluster": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.hdinsight/clusterpools/{}/clusters/{}": [ + "2023-06-01-preview", + "2023-11-01-preview", + "2024-05-01-preview" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.hdinsight/clusters/{}": [ + "2021-06-01", + "2023-04-15-preview", + "2023-08-15-preview", + "2024-08-01-preview", + "default" + ] + } + }, + "HybridContainerService": { + "AgentPool": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.hybridcontainerservice/provisionedclusters/{}/agentpools/{}": [ + "2022-05-01-preview", + "2022-09-01-preview", + "default" + ], + "/{}/providers/microsoft.hybridcontainerservice/provisionedclusterinstances/default/agentpools/{}": [ + "2023-11-15-preview", + "2024-01-01" + ] + } + }, + "LabServices": { + "Lab": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.labservices/labaccounts/{}/labs/{}": [ + "2018-10-15" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.labservices/labs/{}": [ + "2022-08-01", + "2023-06-07", + "default" + ] + }, + "User": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.labservices/labaccounts/{}/labs/{}/users/{}": [ + "2018-10-15" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.labservices/labs/{}/users/{}": [ + "2022-08-01", + "2023-06-07", + "default" + ] + } + }, + "MachineLearningServices": { + "ConnectionRaiBlocklist": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.machinelearningservices/workspaces/{}/connections/{}/raiblocklists/{}": [ + "2024-07-01-preview", + "2024-10-01-preview" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.machinelearningservices/workspaces/{}/connections/{}/raiblocklists/{}/raiblocklistitems/{}": [ + "2024-04-01-preview", + "default" + ] + }, + "ConnectionRaiBlocklistItem": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.machinelearningservices/workspaces/{}/connections/{}/raiblocklists/{}": [ + "2024-04-01-preview", + "default" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.machinelearningservices/workspaces/{}/connections/{}/raiblocklists/{}/raiblocklistitems/{}": [ + "2024-07-01-preview", + "2024-10-01-preview" + ] + } + }, + "Migrate": { + "Assessment": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.migrate/assessmentprojects/{}/groups/{}/assessments/{}": [ + "2019-10-01", + "default" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.migrate/projects/{}/groups/{}/assessments/{}": [ + "2018-02-02" + ] + }, + "Group": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.migrate/assessmentprojects/{}/groups/{}": [ + "2019-10-01", + "default" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.migrate/projects/{}/groups/{}": [ + "2018-02-02" + ] + }, + "Project": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.migrate/assessmentprojects/{}": [ + "2019-10-01", + "default" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.migrate/projects/{}": [ + "2018-02-02" + ] + } + }, + "MobileNetwork": { + "Sim": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.mobilenetwork/simgroups/{}/sims/{}": [ + "2022-04-01-preview", + "2022-11-01", + "2023-06-01", + "2023-09-01", + "2024-02-01", + "2024-04-01", + "default" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.mobilenetwork/sims/{}": [ + "2022-03-01-preview" + ] + } + }, + "NetApp": { + "Backup": { + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.netapp/netappaccounts/{}/backupvaults/{}/backups/{}": [ + "2022-11-01-preview", + "2023-05-01-preview", + "2023-07-01-preview", + "2023-11-01", + "2023-11-01-preview", + "2024-01-01", + "2024-03-01", + "2024-03-01-preview", + "2024-05-01", + "2024-05-01-preview", + "2024-07-01", + "2024-07-01-preview" + ], + "/subscriptions/{}/resourcegroups/{}/providers/microsoft.netapp/netappaccounts/{}/capacitypools/{}/volumes/{}/backups/{}": [ + "2022-11-01", + "default" + ] + } + } +} \ No newline at end of file diff --git a/versions/v3-removed.json b/versions/v3-removed.json index e87a80e8f08f..44d39300a1a0 100644 --- a/versions/v3-removed.json +++ b/versions/v3-removed.json @@ -25,7 +25,8 @@ "2017-07-14" ], "ApiManagement": [ - "2016-07-07" + "2016-07-07", + "2016-10-10" ], "App": [], "AppComplianceAutomation": [], @@ -382,7 +383,9 @@ "Kusto": [ "2017-09-07-privatepreview" ], - "LabServices": [], + "LabServices": [ + "2018-10-15" + ], "LoadTestService": [], "Logic": [], "Logz": [], @@ -430,7 +433,8 @@ "MarketplaceOrdering": [], "Media": [], "Migrate": [ - "2017-11-11-preview" + "2017-11-11-preview", + "2018-02-02" ], "MixedReality": [ "2019-02-28-preview", @@ -479,7 +483,8 @@ "2018-02-01", "2018-03-01", "2018-03-01-preview", - "2018-04-01" + "2018-04-01", + "2021-05-01-preview" ], "NetworkCloud": [], "NetworkFunction": [], @@ -585,6 +590,9 @@ "2018-03-01-preview", "2018-10-01" ], + "Sim": [ + "2022-03-01-preview" + ], "SoftwarePlan": [], "Solutions": [ "2016-09-01-preview",