-
Notifications
You must be signed in to change notification settings - Fork 35
Description
What happened?
A regression was introduced in v0.11.4 that causes "multiple composed resources with same name" errors when using direct list comprehensions in KCL functions, even when the composition resource names are unique.
The error occurs when using patterns like:
_items += [Resource {...} for idx, s in someList]
This same code works correctly in v0.11.1 but fails in v0.11.4 with:
cannot compose resources: pipeline step "kcl" returned a fatal result: cannot process xr and state with the pipeline output in *v1beta1.RunFunctionResponse: duplicate resource names example-network-private-0 found, when returning multiple resources, you need to set different metadata.name or matadata.annotations."krm.kcl.dev/composition-resource-name" to distinguish between different resources in the composition functions.
How can we reproduce it?
Complete KCL Function Code:
import models.io.upbound.azure.network.v1beta1 as networkv1beta1
# Mock input parameters for reproduction
oxr = {
spec = {
parameters = {
id = "example-network"
subnets = [
{ type = "public", cidrBlock = "192.168.1.0/24", availabilityZone = "1" }
{ type = "public", cidrBlock = "192.168.2.0/24", availabilityZone = "2" }
{ type = "private", cidrBlock = "192.168.10.0/24", availabilityZone = "1" }
{ type = "private", cidrBlock = "192.168.11.0/24", availabilityZone = "2" }
]
}
}
}
parameters = oxr.spec.parameters
id = parameters.id
# Metadata function that generates UNIQUE composition resource names
_metadata = lambda id: str, kind: str, suffix: str -> any {
{
annotations = {
if suffix == "":
"krm.kcl.dev/composition-resource-name" = id + "-" + kind
else:
# This creates UNIQUE names like: example-network-subnet-public-0, example-network-subnet-public-1, etc.
"krm.kcl.dev/composition-resource-name" = id + "-" + kind + "-" + suffix
}
name = id + (("-" + suffix) if suffix != "" else "")
}
}
# This is the problematic code that works in v0.11.1 but fails in v0.11.4
subnets = parameters.subnets
publicSubnets = [s for s in subnets if s.type == "public"]
privateSubnets = [s for s in subnets if s.type == "private"]
_items: [any] = []
# These direct list comprehensions cause the bug in v0.11.4
_items += [networkv1beta1.Subnet {
metadata = _metadata(id, "subnet", "public-${idx}") | {
labels = {
access = "public"
}
}
spec = {
forProvider = {
addressPrefixes = [s.cidrBlock]
}
}
} for idx, s in publicSubnets]
_items += [networkv1beta1.Subnet {
metadata = _metadata(id, "subnet", "private-${idx}") | {
labels = {
access = "private"
}
}
spec = {
forProvider = {
addressPrefixes = [s.cidrBlock]
}
}
} for idx, s in privateSubnets]
items = _items
Expected Output (what v0.11.1 produces correctly):
The _metadata function generates these UNIQUE composition resource names:
example-network-subnet-public-0example-network-subnet-public-1example-network-subnet-private-0example-network-subnet-private-1
Actual Error in v0.11.4:
Despite the composition resource names being provably unique, v0.11.4 throws:
duplicate resource names example-network-subnet-private-0 found
Proof that Names are Unique:
You can verify the uniqueness by adding debug output:
# Add this to see the unique names being generated
publicSubnetNames = [_metadata(id, "subnet", "public-${idx}").annotations["krm.kcl.dev/composition-resource-name"] for idx, s in publicSubnets]
privateSubnetNames = [_metadata(id, "subnet", "private-${idx}").annotations["krm.kcl.dev/composition-resource-name"] for idx, s in privateSubnets]
# This will show: ["example-network-subnet-public-0", "example-network-subnet-public-1", "example-network-subnet-private-0", "example-network-subnet-private-1"]
# All names are unique!
What environment did it happen in?
- Function version: v0.11.4
- Working version: v0.11.1
- Platform: Crossplane network composition functions
Root Cause Analysis
The _metadata function IS generating unique names. The bug is that v0.11.4's duplicate detection logic is incorrectly flagging unique resources as duplicates when they're created through direct list comprehensions.
The regression appears to be related to changes made between v0.11.1 and v0.11.4, likely connected to the duplicate name detection added in PR #253. The error detection logic seems to be incorrectly flagging legitimate resources with unique names as duplicates when they're generated through direct list comprehensions.
Workarounds
Two workarounds are available:
Option 1: Use intermediate variables (works with v0.11.4)
# Store results in intermediate variables first
publicSubnetResources = [Subnet {
metadata = _metadata(id, "subnet", "public-${idx}")
# ... rest of configuration
} for idx, s in publicSubnets]
privateSubnetResources = [Subnet {
metadata = _metadata(id, "subnet", "private-${idx}")
# ... rest of configuration
} for idx, s in privateSubnets]
# Then add to _items
_items += publicSubnetResources
_items += privateSubnetResources
Option 2: Downgrade to v0.11.1
# In providers/functions.yaml
apiVersion: pkg.crossplane.io/v1beta1
kind: Function
metadata:
name: kcl-function
spec:
package: xpkg.upbound.io/crossplane-contrib/function-kcl:v0.11.1Additional Context
- This regression affects real-world compositions that were working correctly before
- AWS compositions using similar patterns work because they likely use an older function version
- The error suggests duplicate names even when
krm.kcl.dev/composition-resource-nameannotations are demonstrably unique - This is similar to the regression reported in issue Multiple resources #125 for v0.9.2
Related Issues
- Return error for duplicate names in composed resources #253 - Added duplicate name detection (likely related to this regression)
- Name conflict for resources of Different Kinds #241 - Original issue about name conflicts
- Multiple resources #125 - Similar regression in v0.9.2
This regression breaks existing working compositions and should be prioritized for fixing in the next release.