Initial scaffold: generation-rule-only Crossplane Bucket example
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>
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
# 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`](../codebundles/gcp-bucket-crossplane-health/.runwhen/generation-rules/gcp-bucket-crossplane-health.yaml)
|
||||
line by line and understand each block.
|
||||
|
||||
## The full file
|
||||
|
||||
```yaml
|
||||
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
|
||||
|
||||
```yaml
|
||||
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
|
||||
```
|
||||
|
||||
- `kind` must be exactly `GenerationRules`. RunWhen Local's loader
|
||||
compares this to a schema constant.
|
||||
- `spec.platform` sets the default platform for every rule in the file.
|
||||
- `spec.generationRules` is a list — you can define many rules per file.
|
||||
|
||||
### `resourceTypes`
|
||||
|
||||
```yaml
|
||||
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`
|
||||
|
||||
```yaml
|
||||
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:
|
||||
|
||||
```yaml
|
||||
# Only buckets whose name starts with "prod-"
|
||||
- type: pattern
|
||||
pattern: "^prod-"
|
||||
properties: [name]
|
||||
mode: substring
|
||||
```
|
||||
|
||||
```yaml
|
||||
# Only buckets that carry the label env=production
|
||||
- type: exists
|
||||
path: "resource/metadata/labels/env"
|
||||
```
|
||||
|
||||
```yaml
|
||||
# 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`
|
||||
|
||||
```yaml
|
||||
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 final `slx_name`. Keep it under 15 characters (`xp-bkt-hlth` is 11).
|
||||
- `qualifiers` — determines both the **generated SLX name** and how
|
||||
many SLXs are produced.
|
||||
- Including `resource` means "one SLX per matching Bucket".
|
||||
- Including `cluster` prefixes 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.
|
||||
- `baseTemplateName` — the file-name stem for the templates. The output
|
||||
items resolve to `<baseTemplateName>-<type>.yaml` unless overridden.
|
||||
So `type: slx` looks up `gcp-bucket-crossplane-health-slx.yaml`,
|
||||
`type: sli` → `-sli.yaml`, etc.
|
||||
- `levelOfDetail` — one of `none | basic | detailed` (or `0|1|2`). This
|
||||
gates whether the SLX is emitted based on the platform's LOD filter.
|
||||
Since our airgap `defaultLOD` is `detailed`, we set the SLX to
|
||||
`detailed` so it always renders.
|
||||
- `outputItems` — one entry per artifact we want. `type: runbook`
|
||||
specifies an explicit `templateName` because 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`](https://github.com/runwhen-contrib/runwhen-local/blob/main/src/enrichers/generation_rules.py).
|
||||
|
||||
## 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](05-slx-and-templates.md).
|
||||
Reference in New Issue
Block a user