Architectural Models

Creating Resources

How to use [[create_resource]] to derive new resources via direct, data-driven, or list-based patterns.

Creating Resources

Using [[create_resource]] to Build the Graph

Creating Derived Resources: [[create_resource]]

This is the primary directive for creating new resources. It transforms a single origin_resource into one or more new, derived resources, forming the backbone of your architectural model. [[create_resource]] is versatile and supports several distinct patterns for generating your graph:

  1. Direct Derivation: Creating a new resource based on the existence of an origin_resource (e.g., a server for every application). This can be unconditional or made conditional with match_on.
  2. Data-Driven Derivation: Creating new resources based on the data inside a property of an origin_resource (using create_from). This is a powerful convention-over-configuration pattern for creating multiple resources from a list or string.
  3. Generation from a Data Source: Creating new resources by iterating over an abstract list of data from the header (using create_from). This is ideal for bootstrapping parts of a graph from configuration.

The following sections explain each pattern in detail.

Unconditional Creation

This rule creates one new resource for every origin_resource.

Goal: For every application, create a corresponding server resource.

# The model reads resources of type "application".
origin_resource = "application"

server_specs = { standard_cpu = 4, large_cpu = 8 }

[[create_resource]]
resource_type = "server"
relation_type = "HOSTED_ON"
name = "{{origin_resource.name}}_server"
[create_resource.properties]
os = "Linux"
cpu_cores = "{{ server_specs.standard_cpu }}" # Access data from header
managed_by = "{{origin_resource.owner}}"   # Inherit property from application

The [[create_resource]] block has several powerful options:

Key Mandatory Description
match_on No An array of filter objects. The rule applies if all conditions match.
resource_type Yes* The type for the new resource. (*Optional when using create_from, which can infer the type.)
relation_type Yes The type for the relationship connecting the origin resource to the new resource.
name Yes* A template for the primary key of the new resource. (*Unless using create_from, which has defaults.)
properties No A key-value map of properties to add to the new resource. Values support templates.
relation_properties No A key-value map of properties to add to the new relationship. Values support templates.
create_from No Creates resources from a data source. Use { property = "..." } to create from a property’s value, or { list = "..." } to iterate a header variable. The resource type is determined with this priority: 1. the as key, 2. the top-level resource_type directive, 3. a default (the property or list name). The iterated item is available as {{ value }}.
property_origin No When using create_from, specifies a related resource type to read the property from.
relation_origin No When using create_from, controls the new relationship’s origin ("origin_resource" or "property_origin").

relation_properties: You can also add properties to the newly created relationship using a [create_resource.relation_properties] block.

[[create_resource]]
resource_type = "server"
relation_type = "HOSTED_ON"
name = "{{origin_resource.name}}_server"
[create_resource.properties]
# ... server properties
[create_resource.relation_properties]
source_app_env = "{{ origin_resource.environment }}"
managed = true
  • Result: An application named billing-api results in a new server named billing-api_server. (application:billing-api) -[HOSTED_ON]-> (server:billing-api_server)

This process can be visualized as follows:

graph TD
    subgraph "Input & Rules"
        A["Origin Resource: <code>application</code>"]
        B["<code>[[create_resource]]</code> rule<br/>to create a <code>server</code>"]
    end
    subgraph "rescile Process"
        C{"For each <code>application</code>..."}
        D["1. Render <code>name</code>, <code>properties</code>, and <code>relation_properties</code> from templates"]
        E["2. Create new <code>server</code> resource"]
        F["3. Create <code>HOSTED_ON</code> relationship with its properties"]
    end
    subgraph "Output Graph"
        G(application: billing-api)
        H(server: billing-api_server)
        G -- "HOSTED_ON<br/>{ source_app_env: 'prod', ... }" --> H
    end
    A & B --> C --> D --> E --> F
    F --> G & H

Conditional Creation with match_on

Goal: For every application running in the prod environment, create a corresponding classification resource to label it as restricted.

# In data/models/classification.toml
origin_resource = "application"

[[create_resource]]
match_on = [
  { property = "environment", value = "prod" }
]
resource_type = "classification"
relation_type = "IS_CLASSIFIED_AS"
name = "{{origin_resource.name}}_prod"
[create_resource.properties]
level = "Restricted"
  • Result: An application with environment: "prod" will be linked to a new classification resource named <app_name>_prod with level: "Restricted". Applications in other environments will be ignored by this rule.

The match_on block supports several operators:

Operator Type Description
property String Mandatory. The name of the property on the source resource to match against.
value String, Bool, Num Performs an exact, type-aware match on the property’s value.
not String, Bool, Num The condition is true if the property’s value is not equal to this value.
contains String For a string property, checks if it contains the substring. For an array property, checks if it contains this value as an element.
exists Boolean If true, the condition is true if the property exists and is not null/empty. If false, it’s true if the property does not exist or is null/empty.
empty Boolean If true, the condition is true if the property is missing, null, an empty string (""), or an empty array ([]). false if it has a value.
greater Number For a numeric property, checks if its value is greater than this number (>).
lower Number For a numeric property, checks if its value is less than this number (<).

To express OR logic, use a nested or block:

origin_resource = "server"

match_on = [
  { property = "status", value = "active" }, # Must be active AND...
  { or = [ [ { property = "cores", greater = 8 } ], [ { property = "legacy_system", value = "false" } ] ] } # (...have >8 cores OR not be a legacy system)
]