Adding a new type

Adding a new type

New NodeConfig types are pluggable. A type is one Go file that implements the Handler interface plus one Register call. No changes to the controller, CRD, or templating engine are required.

Handler interface

type Handler interface {
    Name() string
    Validate(params map[string]string) error
    Ensure(ctx context.Context, root string, params map[string]string) (changed bool, err error)
}
  • Name() returns the value of NodeConfig.spec.type that selects the handler.
  • Validate(params) checks required params before anything runs (params here are unrendered).
  • Ensure(ctx, root, params) applies the configuration. root is the host root mount (e.g. /host). Return changed=true when the node's state was actually modified — this is what triggers service restarts.

Example: a "command" type

package handlers

import (
    "context"
    "fmt"
)

type CommandHandler struct{}

func (h *CommandHandler) Name() string { return "command" }

func (h *CommandHandler) Validate(params map[string]string) error {
    if params["command"] == "" {
        return fmt.Errorf("command handler: param %q is required", "command")
    }
    return nil
}

func (h *CommandHandler) Ensure(ctx context.Context, root string, params map[string]string) (bool, error) {
    runner := MakeRunner(root) // chroot(root) so it acts on the host OS
    if _, err := runner.Run(ctx, params["command"]); err != nil {
        return false, err
    }
    return false, nil // commands are not idempotency-checked; report changed=false
}

Register the handler

Add it to init() in internal/handlers/registry.go:

func init() {
    Register(&FileHandler{})
    Register(&PackageHandler{})
    Register(&CommandHandler{})
}

Register panics on empty or duplicate names, so a bad registration fails at startup.

Notes

  • Run commands against the host with MakeRunner(root) — never exec.Command directly, which would act on the container.
  • changed must be accurate: false positives cause unnecessary service restarts, false negatives mean changes are never picked up by dependents.
  • Keep Validate strict enough to give good error messages in CR status.
  • If the handler changes or removes file content, prefer atomic writes (see the file handler).
  • Add unit tests that exercise Validate, Ensure, and changed semantics.