DSL Cheat Sheet

A single-page quick reference for the Inmanta modeling language. For full details, see Language Reference.

Entities

entity File:
    string path
    string content
    int mode = 640
    string? owner = null      # nullable attribute
    string[] tags = []        # list attribute
    dict metadata = {}        # dictionary attribute
end

Inheritance:

entity Base extends std::PurgeableResource:
    bool send_event = true
end

entity Child extends Base:
    string extra
end

# Empty extension (inherit without adding attributes)
entity Leaf extends Child: end

Relations

# Bidirectional with cardinalities: [min:max]
Host.files [0:]  -- File.host [1]        # one-to-many
A.b [1]          -- B.a [1]              # one-to-one
A.bs [0:]        -- B.as [0:]            # many-to-many
A.maybe_b [0:1]  -- B.a [1]             # optional

# Unidirectional (no reverse end name)
Service.config [1:] -- ConfigFile

Index and lookup

index Host(name)
index File(host, path)

# Lookup by index
h = Host[name="web1"]
f = File[host=h, path="/etc/motd"]

# Selector-style lookup on relation
f = h.files[path="/etc/motd"]

Typedef

# Matching with condition
typedef tcp_port as int matching self > 0 and self < 65535

# Matching with regex
typedef mac_addr as string matching /([0-9a-fA-F]{2})(:[0-9a-fA-F]{2}){5}$/

# Matching with list membership
typedef protocol as string matching self in ["tcp", "udp", "icmp"]

# Using pydantic validation
typedef vlan_id as int matching std::validate_type("pydantic.conint", self, {"ge": 1, "le": 4094})

# Using a plugin function
typedef valid_name as string matching my_module::validate_name(self)

# Chained constraint (building on existing typedef)
typedef short_word as std::ascii_word matching std::length(self) <= 20

Implementation and implement

implementation webSetup for WebServer:
    self.config = std::template("mymod/web.conf.tmpl")
    self.requires += self.network
end

# Unconditional binding
implement WebServer using webSetup

# Conditional binding
implement WebServer using sslSetup when self.ssl_enabled

# Multiple implementations
implement WebServer using webSetup, loggingSetup

# No-op implementation
implement HelperEntity using std::none

# Inherit parent implementations
implement ChildEntity using parents

# Cross-module implementation
implement other_module::TheirEntity using my_local_impl

For loop

for i in std::sequence(5, 1):
    Host(name=f"app{i}")
end

hosts = [Host(name="vm-1"), Host(name="vm-2")]
for host in all_hosts:
    File(host=host, path="/etc/motd", content="Welcome")
end

If / elif / else

if self.mode == "ha":
    self.replicas = 3
elif self.mode == "single":
    self.replicas = 1
else:
    self.replicas = 0
end

Conditional (ternary) expression

x = count > 0 ? count : 1
label = is_production ? "prod" : "dev"

List comprehension

short_paths = [f.path for f in host.files if std::length(f.path) < 20]

# Nested for
all_files = [f for h in hosts for f in h.files]

String types

regular   = "hello\nworld"                  # escape sequences interpreted
raw       = r"no\nescapes"                  # backslashes are literal
fstring   = f"host={hostname}, port={port}" # f-string formatting
interp    = "host={{hostname}}"              # string interpolation (legacy)
multiline = """line one
line two"""                                  # triple-quoted multi-line
concat    = "hello " + "world"              # string concatenation

Imports and aliases

import mymodule
import mymodule::subns
import mymodule::subns as sub

Constructor with dict keyword argument unpacking

config = {"path": "/etc/app.conf", "mode": 644}
f = File(host=h, **config)

Module-level constants

# In module infra, model/_init.cf
nokia_sros = "nokia_sros"
juniper_mx = "juniper_mx"

# From another module
implement Router using sros_impl when self.kind == infra::nokia_sros

is defined check

if self.gateway is defined:
    # use self.gateway
end

implement Host using monitoringSetup when monitoring_server is defined

in for list and dict membership

if "tcp" in protocols:
    # ...
end

if "host" in config_dict:
    addr = config_dict["host"]
end

+= for relation append

self.requires += self.network
self.requires += self.subnet
host.files += File(path="/etc/motd")

Type casting

s = string(42)        # "42"
n = int("42")         # 42
f = float("3.14")     # 3.14
b = bool(1)           # true

Common std functions

std::print("debug info")
std::assert(count > 0, "count must be positive")

content = std::template("mymod/config.tmpl")
path = std::file("mymod/data.json")
data = std::source("mymod/schema.json")

items = std::sequence(10, 1)       # [1, 2, ..., 10]
elem = std::at(my_list, 0)         # first element
n = std::count(my_list)            # number of elements
l = std::length("hello")           # 5

parts = std::split("a,b,c", ",")   # ["a", "b", "c"]
result = std::replace(s, "old", "new")

ip = std::ipindex("10.0.0.0/24", 5, true)  # "10.0.0.5/24"

env_val = std::get_env("MY_VAR", "default")
env_int = std::get_env_int("RETRY_COUNT", 3)

fact_val = std::getfact(my_resource, "ip_address")

Resource dependencies

implementation setup for MyService:
    # Deploy network before this service
    self.requires += self.network

    # Deploy this service before the monitor
    self.provides += self.monitor
end