Skip to content

stuttgart-things/claim-machinery-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

152 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Claim Machinery API

███╗   ███╗ █████╗  ██████╗██╗  ██╗██╗███╗   ██╗███████╗██████╗ ██╗   ██╗
████╗ ████║██╔══██╗██╔════╝██║  ██║██║████╗  ██║██╔════╝██╔══██╗╚██╗ ██╔╝
██╔████╔██║███████║██║     ███████║██║██╔██╗ ██║█████╗  ██████╔╝ ╚████╔╝
██║╚██╔╝██║██╔══██║██║     ██╔══██║██║██║╚██╗██║██╔══╝  ██╔══██╗  ╚██╔╝
██║ ╚═╝ ██║██║  ██║╚██████╗██║  ██║██║██║ ╚████║███████╗██║  ██║   ██║
╚═╝     ╚═╝╚═╝  ╚═╝ ╚═════╝╚═╝  ╚═╝╚═╝╚═╝  ╚═══╝╚══════╝╚═╝  ╚═╝   ╚═╝

A Backstage-compatible API for discovering, managing, and rendering KCL-based Crossplane claim templates.

Documentation

Features

Feature Description
Template Discovery Browse and search KCL-based Crossplane claim templates
Template Details Get schema information including parameters, validation rules, and UI hints
Claim Rendering Render claims with custom parameters using KCL
Homerun2 Notifications Optional event notifications via homerun2 omni-pitcher on claim orders
Backstage Integration Native support for Backstage Software Catalog
OCI Support Load templates from OCI registries
Parameter Schema Exposes parameter metadata (types, enums, patterns, defaults) for client-side validation
Interactive CLI Terminal UI for rendering claims with forms, dropdowns, and live YAML preview

Note: Authentication and authorization are not built into the API. These are expected to be handled by an upstream API gateway or service mesh.

Architecture

┌──────────────────────────────────────────┐
│           HTTP Request                   │
├──────────────────────────────────────────┤
│  Middleware (CORS, logging, request ID,  │
│             error/panic recovery)        │
├──────────────────────────────────────────┤
│  API Handlers (list, get, order claims)  │
├──────────────────────────────────────────┤
│  Application Layer                       │
│  - Parameter merging with defaults       │
│  - Template loading (dir + profile)      │
├──────────────────────────────────────────┤
│  KCL Rendering Engine                    │
│  - OCI-based (kcl run oci://...)         │
│  - File-based (Go SDK)                   │
├──────────────────────────────────────────┤
│  External: OCI Registries (ghcr.io)      │
└──────────────────────────────────────────┘

Tech stack: Go, Gorilla Mux, KCL SDK, Cobra, Charmbracelet (bubbletea/huh)

Quick Start

git clone https://github.com/stuttgart-things/claim-machinery-api.git
cd claim-machinery-api
go mod download

# Run API server
go run main.go server

# Or interactive CLI (default when no subcommand is given)
go run main.go render

The server loads templates from tests/profile.yaml by default and listens on port 8080.

API Endpoints

Endpoint Method Description
/api/v1/claim-templates GET List all available claim templates
/api/v1/claim-templates/{name} GET Get template details with parameter schema
/api/v1/claim-templates/{name}/order POST Render a claim with custom parameters
/health GET Health check
/version GET Build version metadata
/openapi.yaml GET OpenAPI specification
/docs GET OpenAPI documentation (Redoc UI)

List Templates

curl http://localhost:8080/api/v1/claim-templates

Response:

{
  "apiVersion": "api.claim-machinery.io/v1alpha1",
  "kind": "ClaimTemplateList",
  "items": [
    {
      "apiVersion": "resources.stuttgart-things.com/v1alpha1",
      "kind": "ClaimTemplate",
      "metadata": {
        "name": "volumeclaim",
        "title": "Crossplane Volume Claim",
        "description": "Creates a persistent volume claim via Crossplane",
        "tags": ["storage", "crossplane"]
      },
      "spec": { "type": "volumeclaim", "source": "oci://...", "parameters": [...] }
    }
  ]
}

Get Template Details

curl http://localhost:8080/api/v1/claim-templates/volumeclaim

Returns the full ClaimTemplate object including all parameter definitions (type, enum, default, required, pattern, etc.).

Render a Claim

curl -X POST http://localhost:8080/api/v1/claim-templates/volumeclaim/order \
  -H "Content-Type: application/json" \
  -d '{"parameters": {"namespace": "production", "storage": "100Gi"}}'

Response:

{
  "apiVersion": "api.claim-machinery.io/v1alpha1",
  "kind": "OrderResponse",
  "metadata": {
    "name": "volumeclaim",
    "timestamp": "2025-01-10T12:00:00Z"
  },
  "rendered": "apiVersion: sthings.io/v1alpha1\nkind: VolumeClaim\n..."
}

Extract just the YAML:

curl -s -X POST http://localhost:8080/api/v1/claim-templates/volumeclaim/order \
  -H "Content-Type: application/json" \
  -d '{"parameters": {"namespace": "production", "storage": "100Gi"}}' | jq -r '.rendered'

Passing an empty body {} renders with all default values.

The order request supports an optional author field for tracking who ordered the resource:

curl -X POST http://localhost:8080/api/v1/claim-templates/volumeclaim/order \
  -H "Content-Type: application/json" \
  -d '{"author": "jane.doe", "parameters": {"namespace": "production"}}'
More Examples (HarborProject)
# With default parameters
curl -X POST http://localhost:8080/api/v1/claim-templates/harborproject/order \
  -H "Content-Type: application/json" \
  -d '{}'

# With custom parameters
curl -X POST http://localhost:8080/api/v1/claim-templates/harborproject/order \
  -H "Content-Type: application/json" \
  -d '{
    "parameters": {
      "projectName": "my-app-project",
      "harborURL": "https://harbor.idp.kubermatic.sva.dev",
      "storageQuota": 10737418240,
      "harborInsecure": false,
      "providerConfigRef": "default"
    }
  }'

Health & Version

curl http://localhost:8080/health
# {"status":"healthy","timestamp":"2025-01-10T12:00:00Z"}

curl http://localhost:8080/version
# {"version":"dev","commit":"none","buildDate":"unknown"}

Usage

API Server

claim-machinery-api server

Interactive CLI (Default)

# Default when no subcommand is given
claim-machinery-api

# Or explicitly
claim-machinery-api render

Features: template selection, dynamic parameter forms, enum dropdowns, random value selection, default pre-fill, type/pattern validation, live YAML preview, and optional file save.

Configuration

Both modes support the same configuration options:

# Custom templates directory
claim-machinery-api --templates-dir /path/to/templates

# Custom profile (or disable with "")
claim-machinery-api --template-profile-path /path/to/profile.yaml

# Profile from HTTP URL (downloaded at startup)
claim-machinery-api --template-profile-path https://example.com/profile.yaml

# Environment variables
export TEMPLATES_DIR=/path/to/templates
export TEMPLATE_PROFILE_PATH=/path/to/profile.yaml        # local file
export TEMPLATE_PROFILE_PATH=https://example.com/profile.yaml  # or HTTP URL
export ENABLE_TEMPLATES_DIR=true  # enable loading from templates directory
export PORT=9090
export LOG_FORMAT=json   # default: text

# Homerun2 notifications (optional)
export ENABLE_HOMERUN=true
export HOMERUN_URL=https://pitcher.example.com
export HOMERUN_AUTH_TOKEN=your-bearer-token

Priority: Flag > Environment Variable > Default

New in v0.6.0: TEMPLATE_PROFILE_PATH supports HTTP/HTTPS URLs. The profile is downloaded at startup before parsing template entries.

Template Profile

Add additional templates via a profile file (merged with the templates directory):

cat <<EOF > profile.yaml
---
templates:
  - https://raw.githubusercontent.com/stuttgart-things/kcl/refs/heads/main/crossplane/claim-xplane-volumeclaim/templates/volumeclaim-simple.yaml
  - /tmp/template123.yaml
EOF
export TEMPLATE_PROFILE_PATH=/absolute/path/to/profile.yaml
go run main.go

Or via CLI flag (overrides env):

go run main.go --template-profile-path /absolute/path/to/profile.yaml

Or as container:

docker run --rm \
  -v $PWD/tests/profile.yaml:/tmp/profile.yaml \
  -e TEMPLATE_PROFILE_PATH=/tmp/profile.yaml \
  -e TEMPLATES_DIR="/tmp" \
  -p 8080:8080 \
  ghcr.io/stuttgart-things/claim-machinery-api:v0.5.6

Behavior:

  • Profile entries (URLs/paths) are validated; unreachable entries trigger a warning and are skipped
  • Templates from the profile and directory are merged; duplicates are deduplicated based on metadata.name (profile takes precedence)
  • On startup, the API displays loaded sources and final template names
Request ID and Correlation
  • Incoming X-Request-ID header is preserved; otherwise the server generates an ID
  • Response always includes the X-Request-ID header (CORS: exposed)
  • Logs (text/JSON) include requestId for correlation
  • On panics, the server returns JSON with {"error":"internal server error","requestId":"..."} and logs structured output
Debug Mode

Enable debug logging to see parameter processing:

DEBUG=1 go run main.go
Homerun2 Notifications

When enabled, the API sends a notification to homerun2 omni-pitcher on every successful claim order. This provides visibility into who ordered which resource.

Enable:

export ENABLE_HOMERUN=true
export HOMERUN_URL=https://pitcher.example.com
export HOMERUN_AUTH_TOKEN=your-bearer-token  # optional

Both ENABLE_HOMERUN and HOMERUN_URL must be set for notifications to fire. This lets you keep the URL configured while toggling notifications on/off.

Example notification sent to pitcher:

{
  "title": "Claim Order: postgresql",
  "message": "Template 'PostgreSQL Database Claim' ordered successfully.\n\nParameters:\n  instanceClass: db.t3.medium\n  namespace: production",
  "severity": "success",
  "author": "jane.doe",
  "system": "claim-machinery-api",
  "tags": "claim-order,database,crossplane,postgresql",
  "artifacts": "oci://ghcr.io/stuttgart-things/claim-xplane-volumeclaim:0.1.1"
}

Notifications are sent asynchronously and never block the API response. On failure, a warning is logged but the order still succeeds.

Development

Testing
go test ./...
Legacy Test CLIs (tests/cli & tests/cli-api)

Note: These are legacy test tools. The integrated CLI via claim-machinery-api render is recommended.

Two interactive CLI tools are available in /tests for testing and development.

Local KCL CLI (tests/cli):

Renders templates directly using KCL (requires kcl CLI installed locally).

go build -o tests/cli/claim-cli ./tests/cli/
./tests/cli/claim-cli

API-Connected CLI (tests/cli-api):

Connects to the running API server - no local KCL required.

# Start API first
go run main.go

# Then run CLI
go build -o tests/cli-api/claim-cli-api ./tests/cli-api/
./tests/cli-api/claim-cli-api

CI/CD

Dagger Build Pipeline

This project uses Dagger for reproducible builds, tests, and container image creation.

Available functions:

Function Description
build-and-test Compile binary and run integration tests
build Build Go binary only
build-image Build container image with ko (with optional Trivy scanning)
scan-image Scan container images for vulnerabilities
lint Run Go linting
test Run Go tests

Quick start:

# Run tests
dagger call -m .dagger build-and-test --src . --progress plain

# Build container image and push to ttl.sh
dagger call -m .dagger build-image \
  --src . \
  --repo ttl.sh/claim-machinery-api-test \
  --push true \
  --scan true \
  --progress plain

# Scan existing image
dagger call -m .dagger scan-image \
  --image-ref ttl.sh/my-app:latest \
  --severity "HIGH,CRITICAL" \
  export --path /tmp/scan-report.json

Full documentation: .dagger/README.md

Task Automation

Common tasks are available via Taskfile:

# Interactive task selector
task do

# Build and push image
task build-push-image

# Scan an image
task scan-image

# Run API locally
task run-local-go

See Taskfile.yaml for all available tasks.

Deployment

The release pipeline publishes a kustomize base as an OCI artifact (ghcr.io/stuttgart-things/claim-machinery-api-kustomize:<version>) and a container image (ghcr.io/stuttgart-things/claim-machinery-api:<version>).

Kustomize Overlay

A kustomize overlay example is provided in deployment/overlays/example/. Pull the base and customize:

oras pull ghcr.io/stuttgart-things/claim-machinery-api-kustomize:v0.5.6 \
  -o deployment/kustomize-base

kubectl kustomize deployment/overlays/example/
Flux (GitOps)

A Flux app definition is available in the stuttgart-things/flux repository at apps/claim-machinery-api/. It uses a two-layer Flux reconciliation with OCIRepository + Flux Kustomization (not Helm) and Gateway API HTTPRoute.

1. Create the GitRepository source:

apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: stuttgart-things-flux
  namespace: flux-system
spec:
  interval: 1m0s
  url: https://github.com/stuttgart-things/flux.git
  ref:
    tag: v1.1.0

2. Create the Kustomization:

apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: claim-machinery-api
  namespace: flux-system
spec:
  interval: 1h
  retryInterval: 1m
  timeout: 5m
  sourceRef:
    kind: GitRepository
    name: stuttgart-things-flux
  path: ./apps/claim-machinery-api
  prune: true
  wait: true
  postBuild:
    substitute:
      CLAIM_MACHINERY_API_NAMESPACE: claim-machinery
      CLAIM_MACHINERY_API_VERSION: v0.6.0
      GATEWAY_NAME: my-gateway
      GATEWAY_NAMESPACE: default
      HOSTNAME: claim-api
      DOMAIN: example.sthings-vsphere.labul.sva.de
      CLAIM_MACHINERY_PROFILE_PATH: /app/config/profile.yaml
      TEMPLATE_PROFILES: |
        templates:
          - https://raw.githubusercontent.com/stuttgart-things/kcl/refs/heads/main/crossplane/claim-xplane-volumeclaim/templates/volumeclaim-simple.yaml
          - https://raw.githubusercontent.com/stuttgart-things/kcl/refs/heads/main/crossplane/claim-xplane-harborproject/templates/harborproject-simple.yaml
Variable Default Purpose
CLAIM_MACHINERY_API_NAMESPACE claim-machinery Target namespace
CLAIM_MACHINERY_API_VERSION v0.6.0 OCI tag + container image tag
GATEWAY_NAME (required) Gateway parentRef name
GATEWAY_NAMESPACE default Gateway parentRef namespace
HOSTNAME (required) HTTPRoute hostname prefix
DOMAIN (required) HTTPRoute domain suffix
TEMPLATE_PROFILES (required) Full profile.yaml content (template URL list)
CLAIM_MACHINERY_PROFILE_PATH /app/config/profile.yaml Override to external HTTP URL

How it works: The outer Kustomization reads ./apps/claim-machinery-api from the GitRepository, substitutes variables, and creates the Namespace + OCIRepository + inner Kustomization + HTTPRoute. The inner Kustomization (release.yaml) reconciles the OCI kustomize base from ghcr.io/stuttgart-things/claim-machinery-api-kustomize, patches out the Ingress (replaced by HTTPRoute), overrides the container image tag, and applies the resulting manifests.

Documentation

Document Description
SPEC.md Full technical specification
ROADMAP.md Project roadmap and tracking
API Examples API usage examples
Template Schema Claim template specification
CI/CD Pattern CI/CD pipeline stages, Dagger functions, Taskfile interface
OpenAPI Spec OpenAPI / Swagger definition

License

Apache 2.0

About

enables discovering, managing, and rendering KCL-based crossplane claim templates

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors