feat(foundry): eject infrastructure for existing projects - #9683
Conversation
- unify existing-project provisioning across embedded and on-disk graphs - generate mode-specific Bicep and Terraform ACR infrastructure
|
Azure Pipelines: Successfully started running 2 pipeline(s). 19 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
There was a problem hiding this comment.
Pull request overview
Adds editable Bicep and Terraform infrastructure eject flows for existing Foundry projects while preserving ownership boundaries.
Changes:
- Adds existing-project IaC templates and ACR modes.
- Aligns provisioning, validation, outputs, and teardown behavior.
- Expands eject, synthesis, and dependency tests.
Reviewed changes
Copilot reviewed 62 out of 64 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
azure.ai.projects/.../terraform/outputs.tf.tmpl |
Reorders connection outputs. |
azure.ai.projects/.../terraform/container-registry.tf |
Adds greenfield ACR resources. |
azure.ai.projects/.../terraform-existing-project/variables.tf |
Defines existing-project inputs. |
azure.ai.projects/.../terraform-existing-project/provider.tf |
Configures cross-subscription providers. |
azure.ai.projects/.../terraform-existing-project/outputs.tf.tmpl |
Emits existing-project outputs. |
azure.ai.projects/.../terraform-existing-project/main.tf |
Manages model deployments. |
azure.ai.projects/.../terraform-existing-project/container-registry-reuse.tf |
Reuses ACR with role assignment. |
azure.ai.projects/.../terraform-existing-project/container-registry-create.tf |
Creates adjunct ACR infrastructure. |
azure.ai.projects/.../terraform-existing-project/container-registry-connect.tf |
Connects an existing ACR. |
azure.ai.projects/.../terraform-existing-project/connections.tf |
Manages declared connections. |
azure.ai.projects/.../modules/foundry-project.bicep |
Adds shared project-child module. |
azure.ai.projects/.../modules/container-registry.bicep |
Adds shared ACR module. |
azure.ai.projects/.../modules/container-registry-eject.bicep.tmpl |
Adds mode-specific eject module. |
azure.ai.projects/.../templates/main.bicep |
Adds connection endpoint output. |
azure.ai.projects/.../templates/main.arm.json |
Regenerates compiled ARM. |
azure.ai.projects/.../templates/existing-project.bicep |
Adds embedded existing-project graph. |
azure.ai.projects/.../templates/existing-project.arm.json |
Adds compiled existing-project ARM. |
azure.ai.projects/.../templates/existing-project-eject.bicep.tmpl |
Adds editable Bicep graph. |
azure.ai.projects/.../templates/brownfield.bicep |
Removes legacy brownfield template. |
azure.ai.projects/.../templates/brownfield.arm.json |
Removes legacy compiled ARM. |
azure.ai.projects/.../synthesis/templates_embed.go |
Embeds new template sets. |
azure.ai.projects/.../synthesis/synthesizer.go |
Adds existing-project synthesis. |
azure.ai.projects/.../synthesis/synthesizer_test.go |
Updates template embedding tests. |
azure.ai.projects/.../synthesis/schema_test.go |
Updates ARM drift checks. |
azure.ai.projects/.../synthesis/parity_test.go |
Tightens byte parity checks. |
azure.ai.projects/.../provisioning/resource_group_location_check.go |
Checks create-mode adjunct groups. |
azure.ai.projects/.../resource_group_location_check_validate_test.go |
Tests adjunct-group validation. |
azure.ai.projects/.../provisioning/ondisk_template.go |
Filters host parameters by template. |
azure.ai.projects/.../provisioning/ondisk_template_test.go |
Tests parameter filtering. |
azure.ai.projects/.../foundry_provisioning_provider_test.go |
Expands existing-project lifecycle tests. |
azure.ai.projects/.../foundry_provisioning_provider_brownfield_acr_test.go |
Removes obsolete brownfield tests. |
azure.ai.projects/.../exterrors/codes.go |
Adds connection operation codes. |
azure.ai.agents/.../terraform/outputs.tf.tmpl |
Reorders connection outputs. |
azure.ai.agents/.../terraform/container-registry.tf |
Adds greenfield ACR resources. |
azure.ai.agents/.../terraform-existing-project/variables.tf |
Defines existing-project inputs. |
azure.ai.agents/.../terraform-existing-project/provider.tf |
Configures cross-subscription providers. |
azure.ai.agents/.../terraform-existing-project/outputs.tf.tmpl |
Emits existing-project outputs. |
azure.ai.agents/.../terraform-existing-project/main.tf |
Manages model deployments. |
azure.ai.agents/.../terraform-existing-project/container-registry-reuse.tf |
Reuses ACR with role assignment. |
azure.ai.agents/.../terraform-existing-project/container-registry-create.tf |
Creates adjunct ACR infrastructure. |
azure.ai.agents/.../terraform-existing-project/container-registry-connect.tf |
Connects an existing ACR. |
azure.ai.agents/.../terraform-existing-project/connections.tf |
Manages declared connections. |
azure.ai.agents/.../modules/foundry-project.bicep |
Adds shared project-child module. |
azure.ai.agents/.../modules/container-registry.bicep |
Adds shared ACR module. |
azure.ai.agents/.../modules/container-registry-eject.bicep.tmpl |
Adds mode-specific eject module. |
azure.ai.agents/.../templates/main.bicep |
Adds connection endpoint output. |
azure.ai.agents/.../templates/main.arm.json |
Regenerates compiled ARM. |
azure.ai.agents/.../templates/existing-project.bicep |
Adds embedded existing-project graph. |
azure.ai.agents/.../templates/existing-project-eject.bicep.tmpl |
Adds editable Bicep graph. |
azure.ai.agents/.../templates/brownfield.bicep |
Removes legacy brownfield template. |
azure.ai.agents/.../templates/brownfield.arm.json |
Removes legacy compiled ARM. |
azure.ai.agents/.../synthesis/templates_embed.go |
Embeds new template sets. |
azure.ai.agents/.../synthesis/synthesizer.go |
Adds existing-project synthesis. |
azure.ai.agents/.../synthesis/synthesizer_test.go |
Updates embedding tests. |
azure.ai.agents/.../synthesis/schema_test.go |
Updates ARM drift checks. |
azure.ai.agents/.../project/foundry_dependencies.go |
Scopes connection readiness. |
azure.ai.agents/.../project/foundry_dependencies_test.go |
Tests cross-project rejection. |
azure.ai.agents/.../cmd/init.go |
Supplies environment state during eject. |
azure.ai.agents/.../cmd/init_infra_test.go |
Adds eject-mode coverage. |
azure.ai.agents/.../cmd/init_foundry_resources_helpers.go |
Persists ACR mode and assignment state. |
azure.ai.agents/docs/infrastructure-eject.md |
Documents existing-project eject behavior. |
Suppressed comments (1)
cli/azd/extensions/azure.ai.agents/internal/cmd/init_infra_test.go:1063
- [azd-code-reviewer] Checking only for
azmakes this test fail on machines that have Azure CLI but have not installed its Bicep component;az bicep buildmay prompt or attempt a download rather than skip. Detect an already-installed standalone or~/.azure/binBicep binary, as the synthesis drift tests do, and invoke it directly so this unit test stays offline and deterministic.
az, err := exec.LookPath("az")
if err != nil {
t.Skip("Azure CLI not found; skipping generated Bicep compilation")
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 63 out of 65 changed files in this pull request and generated no new comments.
Suppressed comments (3)
cli/azd/extensions/azure.ai.agents/internal/cmd/init_infra.go:2233
- An existing-project eject is explicitly marked as needing environment state, but this branch silently continues without it.
ejectInfrathen skips the project identity checks and, for container-based agents, inferscreatemode, so the generated templates may target an unvalidated project and fail to preserve the ACR choice made during init. Return a validation error requiring an active environment instead. [azd-code-reviewer]
if current == nil || current.Environment == nil || current.Environment.Name == "" {
return nil, nil
}
cli/azd/extensions/azure.ai.projects/internal/provisioning/resource_group_location_check.go:185
- This can report a blocking location mismatch for a prebuilt-image environment. The provider forces existing-project ACR mode to
nonewheneverAZD_AGENT_SKIP_ACR=true, but this check consults the persisted mode first; an environment switched fromcreateto prebuilt can therefore retainAZD_FOUNDRY_ACR_MODE=createand be treated as creating an adjunct resource group even though provisioning will not create one. Check the skip flag before the mode. [azd-code-reviewer]
cli/azd/extensions/azure.ai.projects/internal/provisioning/foundry_provisioning_provider.go:510 - The new
AZD_FOUNDRY_ACR_MODEandAZD_FOUNDRY_ACR_PULL_ASSIGNEDenvironment inputs are not documented incli/azd/docs/environment-variables.md, which is the repository’s required source of truth for every environment variable azd reads. Add both variables there with their accepted values/default behavior (and document the new connection-project endpoint key introduced by this change as well). [azd-code-reviewer]
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 63 out of 65 changed files in this pull request and generated 1 comment.
Suppressed comments (2)
Previously missed (1) — in code that hasn't changed since the last review.
cli/azd/extensions/azure.ai.projects/internal/provisioning/foundry_provisioning_provider.go:1575
- This rejects
reuse-connectbefore cleanup, even though that mode creates anAcrPullrole assignment and a project ACR connection while reusing the registry. Consequentlyazd downcannot remove the adjunct resources created by azd, contrary to the stated teardown behavior. Handlereuse-connectby deleting the ownership-verified connection and role assignment while leaving the registry and Foundry project untouched.
cli/azd/extensions/azure.ai.agents/internal/cmd/init_infra_test.go:1046
- This test file still has multiple lines above the repository's enforced 125-character Go limit (including 1046, 1050–1051, 1056, 1061, and later additions).
golangci-lint'slllcheck will fail preflight; please reformat all of the newly added long literals and calls.
{name: "create", env: map[string]string{"AZD_FOUNDRY_ACR_MODE": "create"}, wantMode: "create", wantMain: "resource adjunctResourceGroup", wantRegistry: "resource registry ", expectRegistry: true},
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 65 out of 67 changed files in this pull request and generated 3 comments.
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
cli/azd/extensions/azure.ai.projects/internal/provisioning/foundry_provisioning_provider.go:1575
- For an existing project, this gate also rejects
noneandalready-connected, even though those generated graphs own no adjunct resource to delete. A Docker-backed project using an existing ACR connection therefore makesazd downfail instead of preserving the reused resources as a successful no-op; manually deleting project children cannot clear this error because the branch never inspects Azure. Handle the non-owning modes as no-op success (while keeping the stricterreuse-connecthandling if needed) and add mode-specific teardown tests.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 65 out of 67 changed files in this pull request and generated no new comments.
Suppressed comments (3)
Previously missed (3) — in code that hasn't changed since the last review.
cli/azd/extensions/azure.ai.projects/internal/synthesis/templates/terraform-existing-project/outputs.tf.tmpl:25
- [azd-code-reviewer] This precondition still validates only two environment-fed values. After eject, changing the service
endpoint:inazure.yamlleaves bothproject_endpointandproject_resource_idpointing at the old project, so Terraform passes this check because themicrosoft.foundryprovider no longer runs. Bake the configured YAML endpoint into the generated Terraform inputs and compare it here as well to enforce the promised three-way identity validation.
cli/azd/extensions/azure.ai.agents/internal/synthesis/templates/terraform-existing-project/outputs.tf.tmpl:25 - [azd-code-reviewer] This precondition still validates only two environment-fed values. After eject, changing the service
endpoint:inazure.yamlleaves bothproject_endpointandproject_resource_idpointing at the old project, so Terraform passes this check because themicrosoft.foundryprovider no longer runs. Bake the configured YAML endpoint into the generated Terraform inputs and compare it here as well to enforce the promised three-way identity validation.
precondition {
condition = (
lower(local.project_endpoint_account) == lower(local.foundry_account_name) &&
lower(local.project_endpoint_project) == lower(local.foundry_project_name)
)
error_message = "project_endpoint must identify the same Foundry project as project_resource_id."
cli/azd/extensions/azure.ai.projects/internal/provisioning/resource_group_location_check.go:184
- [azd-code-reviewer] This returns
truefrom persisted mode before checking the current service graph. If a project previously created ACR and later removesdocker:(or setsAZD_AGENT_SKIP_ACR),AZD_FOUNDRY_ACR_MODEcan remaincreate, while provider initialization correctly overrides the effective mode tonone; validation can then block on an adjunct resource-group location that provision will not touch. DeriveincludeAcrfirst and require both it and effective create mode before enabling this check.
Summary
Existing Foundry projects can now eject editable Bicep or Terraform with
azd ai agent init --infra, instead of being limited to opaque brownfield provisioning. The generated infrastructure references the existing account and project without taking ownership of them.Design and UX
--infragenerates a rootinfra/layout for Foundry-only projects or an isolatedinfra/foundrylayer when infrastructure already exists.azure.yaml,AZURE_AI_PROJECT_ID, andFOUNDRY_PROJECT_ENDPOINTidentify the same project.azd downremoves only ownership-verified adjunct resources and their matching ACR connection; reused resources remain untouched.Changes
azure.ai.agents init: add existing-project Bicep and Terraform eject flows, layered-project migration, mode-specific ACR generation, and collision-safe installation.microsoft.foundry provider: unify embedded and on-disk existing-project provisioning, preserve endpoint-only compatibility, align planned outputs, and harden preview, state, and teardown behavior.synthesis templates: replace the brownfield templates with shared existing-project ARM/Bicep modules and editable Terraform templates.dependency outputs: scope connection readiness to the active Foundry project across embedded and ejected infrastructure.Manual Validation
terraform validate, and completed preview and provision for both IaC formats without modifying the reused account or project.azd downremoved only those owned resources.