Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,12 @@ const (
envKeyPrincipalID = "AZURE_PRINCIPAL_ID"
)

// deploymentNamePrefix is prepended to the azd environment name to form
// the ARM deployment name so re-runs update the same deployment record.
const deploymentNamePrefix = "azd-foundry-"
const (
// deploymentNamePrefix is prepended to the azd environment name so re-runs
// update the same ARM deployment record.
deploymentNamePrefix = "azd-foundry-"
maxDeploymentNameLength = 64
)

// FoundryProvisioningProvider implements azdext.ProvisioningProvider for
// the service whose host is FoundryProjectHost. By default it deploys
Expand Down Expand Up @@ -1791,28 +1794,35 @@ func (p *FoundryProvisioningProvider) deploymentsClient(ctx context.Context) (*a
return factory.NewDeploymentsClient(), nil
}

// deploymentName is stable per azd env so re-runs update one record, plus a
// short hash of the project path so two projects sharing an env name (e.g.
// "dev") in the same subscription don't write the same deployment and read each
// other's outputs.
// deploymentName is stable per azd env and capped at ARM's 64-character limit.
// The project-path hash separates projects sharing an env name; an env-name hash
// preserves that identity when the readable env-name segment must be truncated.
func (p *FoundryProvisioningProvider) deploymentName() string {
h := fnv.New32a()
_, _ = h.Write([]byte(p.projectPath))
return fmt.Sprintf("%s%s-%08x", deploymentNamePrefix, p.envName, h.Sum32())
pathHash := fnv.New32a()
_, _ = pathHash.Write([]byte(p.projectPath))
name := fmt.Sprintf("%s%s-%08x", deploymentNamePrefix, p.envName, pathHash.Sum32())
if len(name) <= maxDeploymentNameLength {
return name
}

envHash := fnv.New32a()
_, _ = envHash.Write([]byte(p.envName))
hashTail := fmt.Sprintf("-%08x-%08x", envHash.Sum32(), pathHash.Sum32())
keep := maxDeploymentNameLength - len(deploymentNamePrefix) - len(hashTail)
return deploymentNamePrefix + p.envName[:keep] + hashTail
}

// brownfieldDeploymentName is deploymentName plus a "-brownfield" suffix, capped
// at ARM's 64-character deployment-name limit. The trailing path hash and suffix
// are preserved (uniqueness and intent); only the env-name portion is truncated.
func (p *FoundryProvisioningProvider) brownfieldDeploymentName() string {
const maxLen = 64
name := p.deploymentName() + "-brownfield"
if len(name) <= maxLen {
if len(name) <= maxDeploymentNameLength {
return name
}
const suffix = "-brownfield"
hashTail := name[len(name)-len(suffix)-9 : len(name)-len(suffix)] // "-<8 hex>"
keep := maxLen - len(hashTail) - len(suffix)
keep := maxDeploymentNameLength - len(hashTail) - len(suffix)
Comment thread
hund030 marked this conversation as resolved.
return name[:keep] + hashTail + suffix
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ func TestArmInputsToProto(t *testing.T) {
func TestDeploymentName_StableForEnv(t *testing.T) {
p := &FoundryProvisioningProvider{envName: "dev", projectPath: "/proj/a"}
first := p.deploymentName()
assert.Equal(t, "azd-foundry-dev-accd5375", first, "names that already fit must not change")
assert.Equal(t, first, p.deploymentName(), "same env+path is stable")
assert.True(t, strings.HasPrefix(first, "azd-foundry-dev-"), "carries env and discriminator")

Expand All @@ -421,6 +422,25 @@ func TestDeploymentName_StableForEnv(t *testing.T) {
assert.NotEqual(t, first, other.deploymentName())
}

func TestDeploymentName_LongEnvironmentName(t *testing.T) {
projectPath := `C:\Users\zhihuan\source\repos\agent-framework-egress-control-responses`
p := &FoundryProvisioningProvider{
envName: "agent-framework-egress-control-responses-dev",
projectPath: projectPath,
}

name := p.deploymentName()
assert.Len(t, name, maxDeploymentNameLength)
assert.Equal(t, "azd-foundry-agent-framework-egress-control-res-269fe92a-aa9d4054", name)

// Environment names that differ only beyond the retained prefix must not collide.
other := &FoundryProvisioningProvider{
envName: "agent-framework-egress-control-responses-test",
projectPath: projectPath,
}
assert.NotEqual(t, name, other.deploymentName())
}

func TestDeploymentOutputsResources_NilSafe(t *testing.T) {
assert.Nil(t, deploymentOutputs(nil))
assert.Nil(t, deploymentResources(nil))
Expand Down
Loading