akua / examples / 11-install-as-package

11-install-as-package

Composes a third-party Akua package (`./upstream/`) and applies a tenant overlay, drops a kind, and appends extras — the install-as-Package shape. Demonstrates the natural call form `upstream.render(u

Composes a third-party Akua package (./upstream/) and applies a tenant overlay, drops a kind, and appends extras — the install-as-Package shape. Demonstrates the natural call form upstream.render(upstream.Input{...}): typed inputs at the consumer call site, no path strings in user code.

Layout

filepurpose
upstream/package.kSibling Akua package — Deployment + Service + PodDisruptionBudget. Authored as a normal Package; nothing about it is install-aware.
akua.tomlDep alias upstream = { path = "./upstream" } for akua tree + lock-time validation.
package.kThe install: upstream.render(...), overlay tenant label, drop PDB, append a ConfigMap.
inputs.example.yamlPer-install inputs (tenant, app, replicas).
rendered/Reference output (3 files: Deployment, Service, ConfigMap).

Render

akua render --out ./rendered

The install pattern

import pkgs.upstream as upstream

_up = upstream.render(upstream.Input { appName = ..., replicas = ... })

# Overlay
_patched = [r | {metadata.labels = {"install.cnap.tech/tenant" = input.tenant}} for r in _up]

# Filter
_filtered = [r for r in _patched if r.kind != "PodDisruptionBudget"]

# Extras
_extras = [{apiVersion = "v1", kind = "ConfigMap", ...}]

resources = _filtered + _extras

The import lands a synthesized stub that owns a render lambda and re-exports upstream's schemas — KCL type-checks upstream.Input{...} at the call site (typos surface as compile errors, not as runtime worker traps). The mechanism mirrors import charts.<name> for Helm charts; see docs/package-format.md for the full shape.

package.k

import akua.ctx
import pkgs.upstream as upstream

# An "install" Package: composes a third-party Akua package
# (`upstream`) and applies tenant-specific overlay + filter + extras.
# This is the install-as-Package shape — no separate install schema,
# no helm-values-only escape hatch. Just KCL composing KCL.

schema Input:
    """Inputs for the install."""
    tenant: str
    app: str
    replicas: int = 2

input: Input = ctx.input()

# 1. Render the upstream Package. Mirrors helm.template + import
#    charts.webapp: the synthesized `pkgs.upstream` stub owns a
#    `render` lambda that dispatches to the host plugin with the
#    alias hardcoded, so the call site is just the typed inputs.
#    `upstream.Input { ... }` type-checks here — typos surface as
#    KCL compile errors, not as runtime worker traps.
_up = upstream.render(upstream.Input {
    appName  = input.app
    replicas = input.replicas
})

# 2. Overlay: apply a tenant label to every upstream resource.
_patched = [r | {
    metadata.labels = {"install.cnap.tech/tenant" = input.tenant}
} for r in _up]

# 3. Filter: this install doesn't want PDBs (single-replica policy).
_filtered = [r for r in _patched if r.kind != "PodDisruptionBudget"]

# 4. Extras: append an install-meta ConfigMap.
_extras = [{
    apiVersion = "v1"
    kind = "ConfigMap"
    metadata.name = input.app + "-install-meta"
    metadata.labels = {"install.cnap.tech/tenant" = input.tenant}
    data.tenant = input.tenant
    data.upstreamApp = input.app
}]

resources = _filtered + _extras

Rendered output

000-deployment-webapp.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp
  labels:
    install.cnap.tech/tenant: acme
spec:
  replicas: 3
  selector:
    matchLabels:
      app: webapp
  template:
    metadata:
      labels:
        app: webapp
    spec:
      containers:
      - image: nginx:1.27
        name: webapp
        ports:
        - containerPort: 80

001-service-webapp.yaml

apiVersion: v1
kind: Service
metadata:
  name: webapp
  labels:
    install.cnap.tech/tenant: acme
spec:
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: webapp

002-configmap-webapp-install-meta.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: webapp-install-meta
  labels:
    install.cnap.tech/tenant: acme
data:
  tenant: acme
  upstreamApp: webapp

Source: examples/11-install-as-package/