note

package
v0.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 28, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

README

pkg/note

Notes are pure transformation functions available in every Orkestra template expression — status.fields, normalize.spec, onCreate, onReconcile, mutation rules, validation rules, and conversion paths.

The name is intentional. In music, notes are the atomic units from which everything is composed — precise, combinable, universally understood. In Orkestra, notes serve the same role.

What a note is

  • Pure — same input always produces the same output
  • Safe — handles empty/nil input without panicking
  • Stateless — no I/O, no external calls, no shared state

Notes are not hooks. Hooks are for external API calls and side effects. Notes are for data transformation.

Where notes work

Every {{ }} expression in any Katalog field:

normalize:
  spec:
    schedule: "{{ cronFromMap .spec.schedule }}"

status:
  fields:
    - path: phase
      value: "{{ boolTernary .spec.suspend \"Suspended\" \"Active\" }}"

onCreate:
  secrets:
    - name: "{{ .metadata.name }}-creds"
      once: true
      data:
        password: "{{ randomAlphanumeric 32 }}"

Developer documentation

Complete documentation is in docs/.

I want to… Go to
Work with strings 01 — String Notes
Do arithmetic on spec fields 02 — Math Notes
Express conditional values 03 — Conditional Notes
Inspect or convert field types 04 — Type Notes
Work with cron expressions 05 — Cron Notes
Generate secrets 06 — Random Notes
Work with lists and maps 07 — Collection Notes
Access fields safely with defaults 08 — Safe Access Notes
Navigate child/cross-CRD objects 09 — Kubernetes Notes
Read container images and env vars 10 — Container Notes

Adding a new note

  1. Identify the domain (cron, strings, math, types, conditional, …)
  2. Add the function to the appropriate *.go file
  3. Register it in that file's xxxNotes() function — it is automatically included via note.Map()
  4. Document it in the corresponding docs/ file
  5. Write a test

Contract: handle empty/nil input with a safe zero value, not a panic. Return (value, error) for functions that can meaningfully fail; return just value for infallible ones.

Documentation

Overview

pkg/note/git_docker.go

Git and Docker notes for use in Katalog templates.

These notes work in two directions:

  1. Input to git:/docker: blocks — constructing the values those blocks need.
  2. Output from git:/docker: blocks — transforming .git.* and .docker.* context.

Git context injected by the git: block:

.git.commit       — full commit SHA
.git.changed      — "true" / "false"
.git.path         — local clone path
.git.branch       — resolved branch name
.git.error        — non-empty on failure (when continueOnError: true)
.git.called       — "true" when the block ran

Docker context injected by the docker: block:

.docker.image     — fully qualified image reference (registry/repo:tag)
.docker.digest    — image digest after push (sha256:abc...)
.docker.buildSucceeded  — "true" / "false"
.docker.error           — non-empty on failure
.docker.called          — "true" when the block ran

Example — image with commit-pinned tag:

docker:
  image: "{{ .spec.registry }}/{{ repoName .spec.repo }}:{{ gitShortCommit .git.commit }}"

Example — only deploy when git changed and build succeeded:

deployments:
  - name: "{{ .metadata.name }}"
    image: "{{ dockerWithDigest .docker.image .docker.digest }}"
    when:
      - field: git.changed
        equals: "true"
      - field: docker.buildSucceeded
        equals: "true"

Package note provides the Orkestra template function library.

A note is a pure, named transformation function available in every template expression across the Orkestra runtime — conversion paths, status fields, mutation rules, when conditions, onCreate templates.

The name aligns with Orkestra's musical identity. Notes are the atomic units from which music is composed. In Orkestra, notes are the atomic units from which declarative operator behavior is composed — small, precise, and available everywhere a template expression is evaluated.

Notes are pure functions. They receive values and return transformed values. They cannot perform I/O, call external APIs, or produce side effects. For those, use Go hooks.

Usage in a Katalog:

conversion:
  paths:
    - from: v1
      to: v2
      spec:
        schedule: "{{ cronToMap .spec.schedule }}"

status:
  fields:
    - path: environment
      value: "{{ toLower .spec.environment }}"
    - path: replicas
      value: "{{ default .spec.replicas 2 }}"
    - path: schedule
      value: "{{ cronFromAny .spec.schedule }}"

pkg/note/random.go

Random generation notes — for use with once: true on secrets.

IMPORTANT: These notes are pure in the mathematical sense — they produce random output. They are NOT idempotent. They MUST only be used in template sources that declare once: true (SecretTemplateSource.Once), which ensures the template is only evaluated once (when the Secret does not yet exist).

Using random notes without once: true causes a new value to be generated on every reconcile cycle — passwords change every 30 seconds, breaking every application that uses them.

Correct usage:

secrets:
  - name: "{{ .metadata.name }}-credentials"
    once: true                              # ← REQUIRED with random notes
    data:
      password: "{{ randomAlphanumeric 32 }}"
      apiKey:   "{{ randomHex 16 }}"

The notes are registered in note.Map() and available in all template expressions — the once: guard is the semantic safeguard, not a code restriction.

Index

Constants

View Source
const CronMapSentinel = "\x00CMAP\x00"

CronMapSentinel is a prefix written by the cronToMap template function to signal that the resolved string is a JSON-encoded cron map, not a plain string. Detected by pkg/webhook/conversion_logic.resolveValue, which parses it back to map[string]interface{} so it lands as a nested object in the converted spec — enabling {{ cronToMap .spec.schedule }} as a one-liner shorthand for the v1 → v2 conversion path.

Null bytes are used because they cannot appear in normal YAML field values.

Variables

This section is empty.

Functions

func CronToMap added in v0.3.1

func CronToMap(v interface{}) map[string]interface{}

CronToMap is the Go API for splitting a cron expression into its five named fields. Accepts a string or an existing map (returned as-is).

func Map

func Map() template.FuncMap

Map returns the complete Orkestra note library as a template.FuncMap. The map is built once and returned on every call — no allocation overhead.

Integrate into the resolver:

tmpl, err := template.New("f").
    Option("missingkey=zero").
    Funcs(note.Map()).
    Parse(value)

func OrkLen

func OrkLen(v interface{}) int

OrkLen returns the length of a string, slice, or map. Named orkLen to avoid shadowing Go's built-in len. Registered in note.Map() as "len" since Go templates do not have a built-in len that handles all three types uniformly.

Template: {{ len .spec.regions }} → 3 (slice with 3 elements) Template: {{ len .spec.schedule }} → 5 (map with 5 fields) Template: {{ len .metadata.name }} → 12 (string length)

func TypeOf

func TypeOf(v interface{}) string

typeOf — returns the runtime type name of any value. orkLen — returns the length of a string, slice, or map.

typeOf is used in:

  • Template expressions: {{ typeOf .spec.schedule }} → "string" or "map"
  • when: conditions: operator: typeOf, value: map

The condition operator path uses NavigateRawPath → note.TypeOf directly. The template expression path uses the FuncMap entry registered in note.Map(). Both must return the same strings for the Katalog to be predictable.

Type strings (match Python/JavaScript convention for familiarity):

"string"  → Go string
"number"  → Go float64, int64, int (JSON numbers come back as float64)
"bool"    → Go bool
"map"     → Go map[string]interface{} (YAML objects, structured fields)
"slice"   → Go []interface{} (YAML arrays, list fields)
"null"    → nil
"unknown" → any other type

YAML type behaviour:

spec:
  schedule: "*/5 * * * *"          → typeOf returns "string"
  schedule:                          → typeOf returns "map"
    minute: "*/5"
  regions: [us-east-1, eu-west-1]   → typeOf returns "slice"
  replicas: 3                        → typeOf returns "number"
  enabled: true                      → typeOf returns "bool"

TypeOf returns the type name of any interface{} value. Exported so pkg/types/when.go can call it from EvaluateOneCond without the template engine being involved.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL