Educational RunWhen CodeCollection that discovers Crossplane GCP Bucket CRDs (storage.gcp.upbound.io/v1beta1) and generates one SLX per bucket. Ships only generation rules and Jinja templates; the runtime lives in rw-generic-codecollection/k8s-kubectl-cmd (already loaded by the airgap runner). Includes: - codebundles/gcp-bucket-crossplane-health with generation rule + 3 templates - docs/01..07 numbered training chapters with screenshot placeholders - README, .gitignore Co-authored-by: Cursor <cursoragent@cursor.com>
5.1 KiB
04 — Generation rule walkthrough
What you'll do
Read the generation rule at codebundles/gcp-bucket-crossplane-health/.runwhen/generation-rules/gcp-bucket-crossplane-health.yaml
line by line and understand each block.
The full file
apiVersion: runwhen.com/v1
kind: GenerationRules
spec:
platform: kubernetes
generationRules:
- resourceTypes:
- buckets.storage.gcp.upbound.io/v1beta1
matchRules:
- type: pattern
pattern: ".+"
properties: [name]
mode: substring
slxs:
- baseName: xp-bkt-hlth
qualifiers: ["resource", "cluster"]
baseTemplateName: gcp-bucket-crossplane-health
levelOfDetail: detailed
outputItems:
- type: slx
- type: sli
- type: runbook
templateName: gcp-bucket-crossplane-health-taskset.yaml
Block-by-block
Envelope
apiVersion: runwhen.com/v1
kind: GenerationRules # note the plural — the loader rejects "GenerationRule"
spec:
platform: kubernetes # per-file default; can be overridden per rule
generationRules: [ ... ] # one or more rules
kindmust be exactlyGenerationRules. RunWhen Local's loader compares this to a schema constant.spec.platformsets the default platform for every rule in the file.spec.generationRulesis a list — you can define many rules per file.
resourceTypes
resourceTypes:
- buckets.storage.gcp.upbound.io/v1beta1
This is the selective discovery signal. Because this string appears in a loaded rule, the Kubernetes indexer knows to enumerate that CRD. Without any rule mentioning a CRD, it would not be listed.
You can list multiple types in one rule if you want the same SLX shape for each. Splitting into separate rules is usually cleaner though.
matchRules
matchRules:
- type: pattern
pattern: ".+"
properties: [name]
mode: substring
Match predicates are ANDed together. The pattern predicate here says
"the resource's name property must match the regex .+ (i.e. non-empty)
as a substring". Since every Bucket has a name, every Bucket matches.
You can filter more aggressively if you want. Examples:
# Only buckets whose name starts with "prod-"
- type: pattern
pattern: "^prod-"
properties: [name]
mode: substring
# Only buckets that carry the label env=production
- type: exists
path: "resource/metadata/labels/env"
# Combine — buckets in the prod GCP project label AND with a Ready condition entry
- type: and
matches:
- type: pattern
pattern: "^runwhen-prod-.*"
properties: [name]
mode: substring
- type: exists
path: "resource/status/conditions"
slxs
slxs:
- baseName: xp-bkt-hlth
qualifiers: ["resource", "cluster"]
baseTemplateName: gcp-bucket-crossplane-health
levelOfDetail: detailed
outputItems:
- type: slx
- type: sli
- type: runbook
templateName: gcp-bucket-crossplane-health-taskset.yaml
baseName— short identifier appended to the qualifier prefix to form the finalslx_name. Keep it under 15 characters (xp-bkt-hlthis 11).qualifiers— determines both the generated SLX name and how many SLXs are produced.- Including
resourcemeans "one SLX per matching Bucket". - Including
clusterprefixes the name with the cluster name so it is stable across multi-cluster workspaces. - Not including
namespace— Crossplane managed resources are cluster-scoped; they have no namespace.
- Including
baseTemplateName— the file-name stem for the templates. The output items resolve to<baseTemplateName>-<type>.yamlunless overridden. Sotype: slxlooks upgcp-bucket-crossplane-health-slx.yaml,type: sli→-sli.yaml, etc.levelOfDetail— one ofnone | basic | detailed(or0|1|2). This gates whether the SLX is emitted based on the platform's LOD filter. Since our airgapdefaultLODisdetailed, we set the SLX todetailedso it always renders.outputItems— one entry per artifact we want.type: runbookspecifies an explicittemplateNamebecause we want to point at a file named-taskset.yaml, not-runbook.yaml, purely for convention matching what other RunWhen bundles do.
What resource identity ends up in the SLX
Given a Bucket named runwhen-nonprod-shared-litellm-logging on cluster
shared-cluster, the rule will produce an SLX whose name is roughly:
shared-cluster-runwhen-nonprod-shared-litellm-logging-xp-bkt-hlth
RunWhen Local will also shorten and hash-suffix pieces as needed for
length. The exact rendering happens in
generation_rules.py::make_slx_name.
Screenshot placeholders
images/04-generation-rule-annotated.png— the YAML above with arrows pointing to the resource type, match rule, and output items.
Next
Continue to 05 — SLX and templates.