Architectural Models

Linking Resources

How to use [[link_resources]] to join resources by key, expression, or filter and pull data from them.

Linking Resources

Using [[link_resources]]: A “Pull” Operation

The [[link_resources]] directive is a powerful “pull” operation, analogous to a database JOIN or a lookup function. It enriches the origin_resource by finding a remote resource based on a join condition and pulling data from it.

Unlike [[copy_property]] (a “push” operation that requires an existing connection), [[link_resources]] actively searches for the remote resource. It is the primary tool for enriching a resource with data from a central “lookup” table (e.g., joining a server with a central location database) or for creating explicit relationships based on shared keys.

Key Mandatory Description
with Yes The type of the “remote” resource to find and join with.
join No A table defining the join condition: { local = "prop_on_origin", remote = "prop_on_with" }. If property names are the same, a simple string can be used.
copy_properties No An array defining properties to copy between the origin_resource and the with resource. Supports simple strings, rename syntax ({ from = "...", as = "..." }), and transformation with a Tera template. The engine first tries to copy a property from the origin_resource to the with resource; only if the origin does not have that property does it fall back to copying from the with resource to the origin.
create_relation No A table { type = "RELATION_TYPE" } to create a new relationship from the origin_resource to the with resource.
match_on No An array of filter objects to apply to the origin_resource set.
match_with No An array of filter objects to apply to the with resource set. This is the counterpart to match_on. It supports advanced expression filters that can compare properties between the origin_resource and a candidate target_resource from the with set.

The directive supports distinct patterns depending on which keys are used.

1. Precise Property-Based Joins (join)

This is the most common pattern, used for linking resources based on a shared identifier (like a foreign key).

Goal: For each server, find its corresponding application by matching server.app_id to application.id, copy the application’s owner property, and create a RUNS relationship.

origin_resource = "server"

[[link_resources]]
with = "application"
join = { local = "app_id", remote = "id" }
copy_properties = [
  { from = "owner", as = "server_owner" },
  { from = "version", as = "major_version", template = "{{ value | split(pat='.') | first }}" }
]
create_relation = { type = "RUNS" }
  • Graph Impact: A server with app_id: "app-123" will be joined with an application that has id: "app-123". The server will gain a server_owner property and a major_version property (e.g., "2" if the application’s version was "2.7.1"). A new (server) -[RUNS]-> (application) relationship will also be created.

2. Expression-Based Joins

For complex join conditions that go beyond simple key equality, you can use an expression in the match_with block. This provides access to both the origin_resource (the resource being processed in the main iteration) and a special target_resource variable.

The target_resource variable refers to a candidate resource from the with set that is currently being evaluated as a potential match. For each origin_resource, rescile iterates through all resources of the with type, evaluating the expression for each (origin_resource, target_resource) pair. Every pair that causes the expression to render exactly "true" is considered a match.

Goal: For each vm_request (origin_resource), find a physical_host (with resource) that has sufficient available_ram. The target_resource variable refers to the physical_host being checked.

origin_resource = "vm_request"

[[link_resources]]
with = "physical_host"
match_with = [
  { expression = "{% if origin_resource.requested_ram <= target_resource.available_ram %}true{% endif %}" }
]
copy_properties = [ { from = "name", as = "assigned_host" } ]
create_relation = { type = "HOSTED_ON" }
  • Graph Impact: For each vm_request, rescile will iterate through all physical_host resources. The expression compares vm_request.requested_ram with physical_host.available_ram. Every host that satisfies the condition will be linked. When copy_properties is used and multiple targets match, the copied values are gathered into the origin resource as arrays.

3. Filtered Set Linking (N:M Joins)

This pattern links groups of resources based on filters, not on shared property values. It creates a relationship from every resource in the filtered source set to every resource in the filtered destination set.

Goal: Link all production applications to the central production_gateway.

origin_resource = "application"

[[link_resources]]
match_on = [ { property = "environment", value = "production" } ]
with = "gateway"
match_with = [ { property = "name", value = "production_gateway" } ]
create_relation = { type = "ROUTES_THROUGH" }
  • Graph Impact: Every application resource with environment: "production" will get a new ROUTES_THROUGH relationship pointing to the production_gateway.

4. Unconditional Cross-Join

By omitting on, join, match_on, and match_with, you link every origin_resource to every resource of the with type. This produces a cross-join (N:M) unless there is exactly one with resource in the graph.

Goal: Link every server resource to the single, central subscription resource.

origin_resource = "server"

[[link_resources]]
with = "subscription"
create_relation = { type = "PART_OF" }
  • Graph Impact: When only one subscription exists, every server gets a PART_OF relationship pointing to it. If multiple subscription resources exist, every server is linked to every one of them. To obtain true singleton behavior, add a match_with filter that selects a single target.

Comparison of Linking Patterns

Feature on / join Expression-Based Join Filtered Set Linking (match_on / match_with) Unconditional (Cross-Join)
Join Logic Value Equality: local.prop == remote.prop Arbitrary Expression: f(origin, target) -> bool Set Intersection: Links filtered sets Unconditional: Links all sources to every matching remote
Cardinality Typically 1:1 or 1:N 1:N or N:M (all matches kept) Can be 1:1, 1:N, N:1, or N:M N:M unless only one target exists
Primary Use Case Foreign-key style relationships based on shared identifiers. Resource allocation or complex policy-based joins. Applying broad, policy-based connections between groups of resources. Connecting all resources to a central entity; use match_with to enforce a single target.

While both directives can add properties to a resource, they serve fundamentally different purposes based on their “push” vs. “pull” nature.

Feature [[copy_property]] [[link_resources]] (with copy_properties)
Operation Push: Pushes data from the origin_resource to a connected node. Pull / lookup: The engine tries to copy a property from the origin_resource to the with resource first; only if the origin does not have the property does it fall back to copying from the with resource to the origin.
Requirement An existing, direct connection must be present. No existing connection required. It finds the remote node via a join condition or filter.
Analogy Property Assignment / Inheritance: connected_object.property = self.property Database JOIN / Lookup: tries self.property = remote.property; if self already owns the property, it may be pushed instead.
Use Case Propagating context along an existing relationship graph (e.g., an application pushing its environment to its server). Enriching a resource with data from a central “lookup” source (e.g., a server looking up its location from a datacenter resource).