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 from the remote with resource to the origin_resource. Supports simple strings, rename syntax ({ from = "...", as = "..." }), and transformation with a Tera template.
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. The first pair that causes the expression to render "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. The first host that satisfies the condition will be linked. This pattern is ideal for resource allocation or policy-based linking.

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 “Singleton” Join

By omitting on, join, match_on, and match_with, you can link every origin_resource to a single, globally unique resource type.

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: Every server in the graph will now have a PART_OF relationship pointing to the subscription resource. This is a highly efficient way to establish a central point of reference.

Comparison of Linking Patterns

Feature on / join Expression-Based Join Filtered Set Linking (match_on / match_with) Unconditional (“Singleton”)
Join Logic Value Equality: local.prop == remote.prop Arbitrary Expression: f(origin, target) -> bool Set Intersection: Links filtered sets Unconditional: Links all sources to remote(s)
Cardinality Typically 1:1 or 1:N Typically 1:1 or 1:N Can be 1:1, 1:N, N:1, or N:M N:1 (most common)
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, global entity (e.g., a subscription).

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: The origin_resource pulls data from a remote node.
Requirement An existing, direct connection must be present. No existing connection required. It finds the remote node via a join condition.
Analogy Property Assignment / Inheritance: connected_object.property = self.property Database JOIN / Lookup: self.property = lookup_object(condition).property
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).