This guide shows you how to use the for
syntax and lambda
support to iterate
over items in a collection. Loops can dynamically define multiple copies of a resource and
avoid repeating syntax in your function.
To create multiple resources with a for
loop, each resource instance must have
a unique composition-resource-name
value. You can use the index value or unique values in
arrays or collections to assign unique names. KCL sets it equal to .metadata.name
by default unless you override it with the krm.kcl.dev/composition-resource-name
annotation.
Loop syntax
KCL supports comprehensions, which lets users construct a list or dictionary value by looping over one or more items and evaluating an expression.
An example loop follows the syntax below:
myVar = [x * x for x in range(5)] # returns an array containing [0, 1, 4, 9, 16]
For example, if you want to compose a collection of role policy attachments in AWS, you could write:
import models.v1beta1 as v1beta1
nodeGroupRolePolicies = [
"arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy",
"arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy",
"arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy",
"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly",
]
nodeGroupRolePolicyAttachments = [{
v1beta1.RolePolicyAttachment {
metadata.name = xrName + "-nodegroup-rpa-{}".format(i)
spec.providerConfigRef.name = providerConfigName
spec.deletionPolicy = deletionPolicy
spec.forProvider = {
policyArn = p
roleSelector = {
matchControllerRef = True
matchLabels = {
"role" = "nodegroup"
}
}
}
}
} for i, p in nodeGroupRolePolicies]
items = [nodeGroupRolePolicyAttachments]
For more information on comprehensions, review the KCL docs.
Procedural for loop
KCL doesn’t support procedural for loops natively, but it’s possible to create a procedural loop using a lambda function:
result = [(lambda x: int -> int {
# Write procedural for loop logic in the lambda function.
z = x + 2
x * 2
})(x, y) for x in [1, 2]] # [2, 4]
For example, if you want to create multiple managed resources of the same kind based on a provided input, you could write:
import models.v1beta1 as v1beta1
awsRouteTableAssociationsPublic = [(lambda i: int, -> v1beta1.RouteTableAssociation {
v1beta1.RouteTableAssociation {
spec.forProvider = {
subnetIdSelector.matchControllerRef: True
routeTableId: _ocds["${xrName}-${i}"]
}
}
})(i) for i in range(oxr.spec.parameters.numberOfSubnets)]
items = [awsRouteTableAssociationsPublic]