-
Notifications
You must be signed in to change notification settings - Fork 268
Filter location prompts by resource provider availability #6502
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
base: main
Are you sure you want to change the base?
Conversation
Co-authored-by: spboyer <7681382+spboyer@users.noreply.github.com>
Co-authored-by: spboyer <7681382+spboyer@users.noreply.github.com>
Co-authored-by: spboyer <7681382+spboyer@users.noreply.github.com>
Co-authored-by: spboyer <7681382+spboyer@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements location filtering based on Azure resource provider availability to prevent provisioning failures when users select regions where required services are unavailable. The implementation extracts resource types from compiled ARM templates and filters location prompts to only show regions that support all required resource types.
Changes:
- Adds ARM template parsing to extract resource types from compiled Bicep templates
- Implements Azure Provider API integration to check resource type availability per location
- Updates location prompting flow to filter by resource availability alongside existing quota filtering
- Maintains backward compatibility by only applying filters when resource types are provided
Reviewed changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
cli/azd/pkg/azure/arm_template.go |
Adds ExtractResourceTypes function to parse ARM templates and extract unique resource types |
cli/azd/pkg/azure/arm_template_test.go |
Comprehensive unit tests for ARM template resource type extraction with various scenarios |
cli/azd/pkg/account/subscriptions.go |
Implements resource type availability checking via Azure Provider APIs with location filtering |
cli/azd/pkg/account/subscriptions_manager.go |
Adds ListLocationsWithFilter method to manager layer |
cli/azd/pkg/account/manager.go |
Extends Manager interface with GetLocationsWithFilter method |
cli/azd/pkg/infra/provisioning/manager.go |
Adds ResourceTypes field to options and integrates filtered location prompting |
cli/azd/pkg/infra/provisioning/bicep/bicep_provider.go |
Extracts resource types during EnsureEnv and stores for parameter prompting |
cli/azd/pkg/infra/provisioning/bicep/prompt.go |
Updates location prompts to use resource type filtering |
cli/azd/pkg/prompt/prompter.go |
Adds PromptLocationWithResourceTypes method to Prompter interface |
cli/azd/pkg/azureutil/location.go |
Implements PromptLocationWithResourceTypeFilter with internal routing logic |
cli/azd/test/mocks/mockaccount/mock_manager.go |
Updates mock to implement new GetLocationsWithFilter method |
cli/azd/extensions/azure.ai.finetune/internal/utils/environment.go |
Minor whitespace formatting fix |
cli/azd/extensions/azure.ai.finetune/go.mod |
Moves github.com/sethvargo/go-retry from indirect to direct dependency |
Comments suppressed due to low confidence (2)
cli/azd/pkg/infra/provisioning/bicep/bicep_provider.go:148
- In bicepparam mode, location prompting happens before compilation (line 144-147), but resource types are only extracted after compilation (line 156-162). This means bicepparam mode users won't benefit from resource type filtering since
p.extractedResourceTypeswill be empty whenEnsureSubscriptionAndLocationis called. The PR description notes this limitation, but the implementation should either: 1) Passp.extractedResourceTypestoEnsureSubscriptionAndLocationoptions for bicepparam mode (it will be empty but makes intent clear), or 2) Add a TODO comment explaining why bicepparam mode doesn't get filtering.
if p.mode == bicepparamMode {
if err := provisioning.EnsureSubscriptionAndLocation(
ctx, p.envManager, p.env, p.prompters, provisioning.EnsureSubscriptionAndLocationOptions{}); err != nil {
return err
}
}
cli/azd/pkg/account/subscriptions.go:214
- Direct
fmt.Printfcalls bypass the structured logging system. Use thelogpackage or a structured logger instead. This is inconsistent with the telemetry and logging infrastructure used elsewhere in azd.
fmt.Printf(
"warning: skipping invalid resource type format '%s' (expected 'Provider/Type')\n",
resourceType)
| if err != nil { | ||
| // Log error but continue with other locations to provide best-effort filtering. | ||
| // If all locations fail, an empty list will be returned, prompting the user to check permissions. | ||
| fmt.Printf("warning: failed to check resource availability for location %s: %v\n", location.Name, err) |
Copilot
AI
Jan 14, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Direct fmt.Printf calls bypass the structured logging system. Use the log package or a structured logger instead. This is inconsistent with the telemetry and logging infrastructure used elsewhere in azd.
This issue also appears in the following locations of the same file:
- line 212
| } | ||
|
|
||
| // Check resource type availability for each location | ||
| filteredLocations := []Location{} |
Copilot
AI
Jan 14, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the capacity is unknown but likely to be less than len(allLocations), consider using make([]Location, 0, len(allLocations)) to pre-allocate the slice with capacity to avoid reallocations during append operations.
| var templateWithResources struct { | ||
| Resources []ArmTemplateResource `json:"resources"` | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This wouldn't work for any nested Bicep modules yet, which would require recursively looking at [resources == Microsoft.Resources/deployments].properties.template.resources
| // Use a map to track unique resource types | ||
| uniqueTypes := make(map[string]struct{}) | ||
| for _, resource := range templateWithResources.Resources { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This wouldn't handle existing resources, which aren't being created or updated by the current ARM template
| for _, location := range allLocations { | ||
| supported, err := s.checkResourceTypesAvailability( | ||
| ctx, subscriptionId, tenantId, location.Name, options.ResourceTypes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is going to be real expensive. For each location, we are querying every single resource type to see if the location should be filtered, i.e. Number of queries = number of locations x number of resource types
| ctx, p.env.GetSubscriptionId(), msg, func(loc account.Location) bool { | ||
| return locationParameterFilterImpl(allowedLocations, loc) | ||
| }, defaultPromptValue(param)) | ||
| }, defaultPromptValue(param), p.extractedResourceTypes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not following the logic here entirely. This deserves a closer look
We are saying: For all location parameters in the Bicep (which could be used arbitarily inside the Bicep), ensure the location prompted works with ALL the resource types that are present in the Bicep (based on the current logic in subscriptions.go).
Current problems I'm seeing:
- The location can be arbitrarily used, it could be associated to no resources at all
- The constraint is currently an &&, i.e. the location must work with ALL resource types. However, in practice, the location may only be used for a single resource type, and that resource type should be filtered instead.
If we were to relax 2 to an ||condition, it may be not restrictive enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An alternative suggestion here is to add resourceType explicitly as a metadata to filter down the location
| } | ||
|
|
||
| // Extract resource types from compiled template for location filtering | ||
| resourceTypes, err := azure.ExtractResourceTypes(compileResult.RawArmTemplate) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The benefits of this change for users getting errors during provision comes with a tax for other users on every call to provision.
I also wonder if we are linking location parameters to the resource using it and not applying the filter for all resources to every location parameter prompt. If not, we could potentially break scenarios where people is defining allowed locations for different location parameters.
IMO, this strategy should be added either as an extension or a new azd command (even maybe as an argument/flag for azd provision) to calculate and analyze regions - returning a report for the user based on the resources discovered within the infrastructure files. Then users would use the report to set allowed-values in the infra template or know what location to use for a template w/o allowed-list
Users were selecting regions where project services aren't available, causing provision failures (e.g., Static Web Apps unavailable in France Central).
Implementation
Resource Type Extraction (
pkg/azure/arm_template.go)resources[]array["Microsoft.App/containerApps", "Microsoft.DBforPostgreSQL/flexibleServers"]Provider Availability Check (
pkg/account/subscriptions.go)Integration (
pkg/infra/provisioning/bicep/)EnsureEnv()after Bicep compilationPromptLocationWithResourceTypes()methodallowedValuesand quota filteringInterface Extensions
Manager.GetLocationsWithFilter(resourceTypes []string)- filtered location retrievalPrompter.PromptLocationWithResourceTypes(resourceTypes []string)- filtered promptingEnsureSubscriptionAndLocationOptions.ResourceTypes- provisioning optionsExample
Project using Container Apps + PostgreSQL:
Notes
resourceTypesis nil/empty, no filtering occursWarning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
code.cloudfoundry.org/update-job-proxy /update-job-proxy DROP bin/bash test -e cef98f5.0 /opt/hostedtoolc-e /bin/test rvice-availabili/usr/bin/git -buildtags /home/REDACTED/.do--global test -e oot_CA_2022.pem git est 1db302536c17e6f4/usr/sbin/iptables les ache/go/1.25.5/x-t test(dns block)dario.cat/update-job-proxy /update-job-proxy DROP bin/bash test -e cef98f5.0 /opt/hostedtoolc-e /bin/test rvice-availabili/usr/bin/git -buildtags /home/REDACTED/.do--global test -e oot_CA_2022.pem git est 1db302536c17e6f4/usr/sbin/iptables les ache/go/1.25.5/x-t test(dns block)go.googlesource.com/update-job-proxy /update-job-proxy DROP bin/bash test -e cef98f5.0 /opt/hostedtoolc-e /bin/test rvice-availabili/usr/bin/git -buildtags /home/REDACTED/.do--global test -e oot_CA_2022.pem git est 1db302536c17e6f4/usr/sbin/iptables les ache/go/1.25.5/x-t test(dns block)go.opentelemetry.io/update-job-proxy /update-job-proxy DROP bin/bash test -e cef98f5.0 /opt/hostedtoolc-e /bin/test rvice-availabili/usr/bin/git -buildtags /home/REDACTED/.do--global test -e oot_CA_2022.pem git est 1db302536c17e6f4/usr/sbin/iptables les ache/go/1.25.5/x-t test(dns block)go.uber.org/update-job-proxy /update-job-proxy DROP bin/bash test -e cef98f5.0 /opt/hostedtoolc-e /bin/test rvice-availabili/usr/bin/git -buildtags /home/REDACTED/.do--global test -e oot_CA_2022.pem git est 1db302536c17e6f4/usr/sbin/iptables les ache/go/1.25.5/x-t test(dns block)google.golang.org/update-job-proxy /update-job-proxy DROP bin/bash test -e cef98f5.0 /opt/hostedtoolc-e /bin/test rvice-availabili/usr/bin/git -buildtags /home/REDACTED/.do--global test -e oot_CA_2022.pem git est 1db302536c17e6f4/usr/sbin/iptables les ache/go/1.25.5/x-t test(dns block)gopkg.in/update-job-proxy /update-job-proxy DROP bin/bash test -e cef98f5.0 /opt/hostedtoolc-e /bin/test rvice-availabili/usr/bin/git -buildtags /home/REDACTED/.do--global test -e oot_CA_2022.pem git est 1db302536c17e6f4/usr/sbin/iptables les ache/go/1.25.5/x-t test(dns block)If you need me to access, download, or install something from one of these locations, you can either:
Original prompt
This section details on the original issue you should resolve
<issue_title>Filter Region list by provider/service availability being used in project</issue_title>
<issue_description>Findings are showing that there are unsuccessful provision attempts due to services/providers not available in the region selected for a service that is in the project.
We are already filtering the available regions by subscription, we can add the services in the project as an additional filter to further reduce the list.
There are some of the templates that attempt to do this via the
allowedparameter in the bicep files, but this is a manual list and has room for error.Proposed solution -
Extend Existing Method with Optional Filtering
A backwards-compatible approach would be to add optional parameters:
Integration with Existing Prompt System
You would also need to update the prompt system to use the filtered locations. This would involve modifying
pkg/azureutil/location.goWe would have to parse the bicep files for the services.</issue_description>
Comments on the Issue (you are @copilot in this section)
@weikanglim @spboyer Do you have a couple of a quick examples in mind?I suspect what this ends up looking, in the case of a single location being used across multiple resources, could look like: