Generation Rules
Introduction
Generation Rules help the RunWhen Workspace Builder determine which CodeBundles (and thus which SLXs) should be included in a workspace, based on the resources the Workspace Builder discovers on configured cloud platforms (e.g. Kubernetes, Azure, GCP).
When you run the Workspace Builder:
It loads the generation rules defined in your CodeBundles (which are defined/enabled in your workspace info file).
It indexes resources from your configured cloud platforms and stores them in a simple in-memory database.
It evaluates the generation rules to see which resources match certain criteria.
For each matching rule, it generates one or more SLX files in the final workspace directory structure.
This document explains the format of those generation rules and how they work. It’s particularly helpful if you’re creating or modifying CodeCollections.
Directory Structure
Each CodeBundle can include an optional folder named .runwhen
that stores:
generation-rules/
: All the YAML files that define your match logic and what SLXs to create.templates/
: Jinja2-based files used to render the actual content (YAML) of the SLXs when a rule matches.
For example:
k8s-namespace-healthcheck
└── .runwhen
├── generation-rules
│ └── k8s-namespace-healthcheck.yaml
└── templates
├── k8s-namespace-healthcheck-sli.yaml
├── k8s-namespace-healthcheck-slo.yaml
├── k8s-namespace-healthcheck-slx.yaml
├── k8s-namespace-healthcheck-taskset.yaml
└── k8s-namespace-healthcheck-workflow.yaml
Generation Rule YAML File
A generation rules file can contain one or more rules. Its general structure looks like:
apiVersion: runwhen.com/v1
kind: GenerationRules
spec:
platform: <target-platform> # e.g. 'kubernetes', 'azure', or 'gcp'
generationRules:
- resourceTypes:
- <resource-type-name> # e.g. 'k8s.core.v1.pods' or 'azure_compute_instances'
matchRules:
- # (list of match predicates)
slxs:
- # (SLX generation settings)
Supported Platforms
kubernetes
azure
gcp
If no platform is specified, it defaults to Kubernetes.
Resource Types
Each rule checks specific resource types in that platform. For example, if the rule’s resourceTypes
is [ "k8s.core.v1.pods" ]
, the Workspace Builder will index all Kubernetes Pods and evaluate the match predicates against each Pod. For Azure or GCP, the resource types typically match CloudQuery table names, or recognized aliases if available.
Platform-Specific Fields
When writing your matchRules or building Jinja2 templates, you can leverage the following built-in fields for each platform:
Kubernetes
name: Name of the resource
labels: All label keys and values
label-keys: Just the label keys
label-values: Just the label values
annotations: All annotation keys and values
annotation-keys: Just the annotation keys
annotation-values: Just the annotation values
namespace: The parent Kubernetes namespace
cluster: The parent Kubernetes cluster
Azure
name: Name of the resource
tags: All tag keys and values
tag-keys: Just the tag keys
tag-values: Just the tag values
resource_group: The parent resource group
GCP
name: Name of the resource
project: The parent project ID
You can also specify custom paths into the raw resource data (e.g., spec/region
). If the path encounters a list, it will check each element of that list for a match.
Match Rules
A match rule is how you decide if a particular resource “matches” your conditions. There are two main leaf-level predicates and three ways to combine them:
1) Pattern Predicate
This checks if a property of the resource matches a certain text pattern (regex). Example:
type: pattern
properties:
- name # could also be a path like 'metadata.name'
pattern: "^prod-.*" # python-style regex
mode: exact # or 'substring' (default)
Fields:
type: "pattern"
resourceType
: Optional; override top-level resource types.properties
: A list of resource properties to match against (e.g.name
,labels
,tags
,annotation-values
, or a raw path likespec/region
).pattern
: A Python-style regex.mode
:"exact"
or"substring"
(substring is default).
2) Exists Predicate
Checks if a property exists at all:
type: exists
properties:
- annotation-keys
Fields:
type: "exists"
Same property syntax as pattern predicates.
No
pattern
ormode
fields (because it just checks for existence).
Compound Boolean Predicates
You can combine predicates using and
, or
, and not
:
type: and
matches:
- type: pattern
properties:
- name
pattern: "^production-.*"
- type: pattern
properties:
- namespace
pattern: "^prod-namespace"
type: and
: All child predicates must match.type: or
: At least one child predicate must match.type: not
: Child predicate must not match.
Example: A Simple Kubernetes Match Rule
spec:
platform: kubernetes
generationRules:
- resourceTypes:
- "k8s.core.v1.namespaces"
matchRules:
- type: and
matches:
- type: pattern
properties: [ "name" ]
pattern: "^prod-.*"
mode: exact
slxs:
- base_name: "namespace-healthcheck"
qualifiers:
- cluster
- namespace
base_template_name: "k8s-namespace-healthcheck"
level_of_detail: "basic"
output_items:
- type: slx
- type: sli
- type: slo
- type: runbook
Explanation:
This rule targets Kubernetes namespaces (
resourceTypes: ["k8s.core.v1.namespaces"]
).It matches any namespace whose name starts with
"prod-"
.For each match, it will generate multiple SLX files (slx, sli, slo, runbook), all based on the
"k8s-namespace-healthcheck"
templates.The SLX’s full name includes
namespace-healthcheck
and the resource’scluster
andnamespace
as qualifiers.
SLX Generation (the slxs
section)
Once a resource matches, one or more SLX files can be created. Each entry in slxs
defines how to build those files.
slxs:
- base_name: "namespace-healthcheck"
qualifiers:
- namespace
shortened_base_name: "ns-healthchk" # (optional override if you need a custom shortened name)
level_of_detail: "basic" # or "detailed"
base_template_name: "k8s-namespace-healthcheck"
output_items:
- type: slx
- type: sli
level_of_detail: "detailed" # override the parent detail level
- type: runbook
template_name: "my-custom-runbook.yaml"
template_variables:
custom_var: "{{match_resource.name | upper}}"
Key Fields:
base_name
: The main identifier.qualifiers
: Attributes from the matched resource to make the name unique (e.g.resource
,namespace
,cluster
, etc.).shortened_base_name
: Override if the automatic name-shortening is too cryptic. Should be <= 15 characters.level_of_detail
:"basic"
or"detailed"
.base_template_name
: Default prefix for your template files.output_items
: Array of SLX file types to emit. Each can have:type
: The SLX type (e.g.slx
,sli
,slo
, orrunbook
).path
: (Optional) The file path in your workspace. Defaults toslx.yaml
,sli.yaml
, etc.template_name
: (Optional) If you don’t want to follow the default naming scheme, specify a custom template file.template_variables
: (Optional) Additional Jinja2 variables to pass in.level_of_detail
: (Optional) Override for that specific file.
SLX Template Files
The .runwhen/templates/
folder contains one or more Jinja2 templates for each SLX output. They often start with some boilerplate like:
apiVersion: runwhen.com/v1
kind: ServiceLevelX
metadata:
name: {{ slx_name }}
labels:
{% include "common-labels.yaml" %}
annotations:
{% include "common-annotations.yaml" %}
spec:
# your custom content here, can use Jinja2 variables
myField: {{ match_resource.name }}
Available Template Variables
Here are some of the most common variables you can use in your templates:
workspace
: The name of the parent workspace.slx_name
/full_slx_name
: Shortened vs. unshortened SLX name.base_name
: The originalbase_name
from the generation rule.match_resource
: The resource object that matched.You can do
{{ match_resource.resource.some_field }}
to reference raw data from the resource.
namespace
,cluster
,resource_group
,project
: The parent scoping data for each platform (K8s, Azure, GCP).custom
: Maps to thecustom
field in the workspace info file (if any).
Tip: If you’re not sure which fields are available in match_resource.resource
, you can consult the CloudQuery plugin docs or look at the automatically generated resource-dump.yaml
file in the shared
directory. That file shows all resources the Workspace Builder discovered, which helps you figure out the field paths you might want to match against or print in the templates.
Putting It All Together: An Azure Example
Directory Layout:
azure-vm-observability
└── .runwhen
├── generation-rules
│ └── azure-vm-observability.yaml
└── templates
├── azure-vm-observability-slx.yaml
├── azure-vm-observability-sli.yaml
└── azure-vm-observability-runbook.yaml
Generation Rule (azure-vm-observability.yaml
):
apiVersion: runwhen.com/v1
kind: GenerationRules
spec:
platform: azure
generationRules:
- resourceTypes:
- "azure_compute_instances" # CloudQuery table name for Azure VMs
matchRules:
- type: pattern
properties: [ "tags", "resource_group" ]
pattern: "critical|high-priority"
mode: substring
slxs:
- base_name: "azure-vm-observability"
qualifiers:
- resource_group
- resource
base_template_name: "azure-vm-observability"
level_of_detail: "basic"
output_items:
- type: slx
- type: sli
- type: runbook
Here we:
Target Azure VMs (
azure_compute_instances
).Match any VM whose tags or resource group contains
"critical"
or"high-priority"
.For each match, generate an SLX file, an SLI file, and a runbook, all using templates that start with
azure-vm-observability-*
.
Sample Template (azure-vm-observability-slx.yaml
):
apiVersion: runwhen.com/v1
kind: ServiceLevelX
metadata:
name: {{ slx_name }}
labels:
{% include "common-labels.yaml" %}
annotations:
{% include "common-annotations.yaml" %}
spec:
description: "Observability SLX for Azure VM: {{ match_resource.name }}"
location: {{ default_location }}
...
Summary
Generation Rules help you dynamically generate SLXs (and related files) for specific cloud resources.
matchRules
define how to identify those resources.slxs
define which files get generated and how they are named.Templates (using Jinja2) allow you to customize the final YAML content of each SLX.
Use this reference when you’re writing or modifying CodeCollections that define new SLX rules, or when you need to understand why certain SLXs are being generated in your workspace.