Documentation
¶
Overview ¶
Package config holds the lab configuration: everything the interactive form asks for, persisted to agentlab.yaml so re-runs are reproducible.
Index ¶
- Constants
- Variables
- func BackendPort(backend string) int
- func BackendServerName(backend string) string
- func SanitizeBranch(branch string) string
- func ValidateAIModel(s string) error
- func ValidateAPIKeyEnv(s string) error
- func ValidateChartBranch(s string) error
- func ValidateChartVersion(s string) error
- func ValidateClusterName(s string) error
- func ValidateImageRef(s string) error
- func ValidateModelName(s string) error
- func ValidateNodePort(s string) error
- func ValidatePort(s string) error
- type Backstage
- type Config
- func (c *Config) AdminUser() *User
- func (c *Config) AgentgatewayBaseURL() string
- func (c *Config) BackstageBaseURL() string
- func (c *Config) BackstageDirectURL() string
- func (c *Config) ChartMajor() uint64
- func (c *Config) ChooseFreePorts(ours map[int]bool, minPublishable int) []PortChange
- func (c *Config) ControlPlaneNode() string
- func (c *Config) EnsureHashes() (changed bool, err error)
- func (c *Config) FindUser(email string) *User
- func (c *Config) FindUserInGroup(group string) *User
- func (c *Config) Issuer() string
- func (c *Config) KagentUIBaseURL() string
- func (c *Config) KlausGatewayEnabled() bool
- func (c *Config) LegacyChart() bool
- func (c *Config) MCPServerName() string
- func (c *Config) ModelManagerBaseURL() string
- func (c *Config) ModelManagerEnabled() bool
- func (c *Config) MusterBaseURL() string
- func (c *Config) MusterDirectURL() string
- func (c *Config) Normalize()
- func (c *Config) ObservabilityBaseURL() string
- func (c *Config) PortConflicts(ours map[int]bool) []PortConflict
- func (c *Config) Save() error
- func (c *Config) VMManagerEnabled() bool
- func (c *Config) Validate() error
- type ExtraModel
- type KlausGateway
- type ModelManager
- type Platform
- type PlatformTLS
- type PortChange
- type PortConflict
- type User
- type VMManager
Constants ¶
const ( // ModelManagerBackendOllama is a host Ollama. ModelManagerBackendOllama = "ollama" // ModelManagerBackendLemonade is a host Lemonade Server // (lemonade-server.ai): FastFlowLM on AMD Ryzen AI NPUs, llama.cpp on // GPU and CPU, behind one OpenAI-compatible API plus a management API. ModelManagerBackendLemonade = "lemonade" // ModelManagerBackendLMStudio is a host LM Studio (lmstudio.ai): // llama.cpp on GPU and CPU, MLX on Apple silicon, behind one // OpenAI-compatible API plus its own /api/v1. Needs 0.4.0 or newer, and // it cannot delete a model — that is `lms rm` on the host. ModelManagerBackendLMStudio = "lmstudio" )
The model servers the lab runs against on the host, which model-manager and agent pods reach through the kind docker network's gateway.
const ( OllamaPort = 11434 LemonadePort = 13305 LMStudioPort = 1234 )
The servers' default API ports, the ones the autodetected endpoints assume.
const ( KubernetesClientID = "kubernetes" KubernetesClientSecret = "kubernetes-lab-secret" // #nosec G101 -- static throwaway lab credential, by design // The ONE platform client, following the chart's global.identity // convention: muster and Backstage authenticate with the same Dex client, // so a token minted for either carries an audience the other trusts. AgentPlatformClientID = "agent-platform" AgentPlatformClientSecret = "agent-platform-lab-secret" // #nosec G101 -- static throwaway lab credential, by design )
Static OAuth client IDs and secrets, paired per client. The IDs also appear in the templates (Dex staticClients and each consumer's own config), which must agree with these. The lab's identity is self-contained and throwaway by design; nothing here guards anything real.
const ( ProviderOpenAI = "OpenAI" ProviderAnthropic = "Anthropic" ProviderGemini = "Gemini" ProviderOllama = "Ollama" )
The provider vocabulary for extra models, spelled exactly as the kagent ModelConfig CRD's provider enum spells them.
const BrowserCallbackPort = 5555
BrowserCallbackPort is the fixed local port for the OAuth callback of `agentlab login --browser` (and its hidden `agentlab browser` alias). Fixed because it must be pre-registered in Dex's redirectURIs.
const ChartRepository = "oci://gsoci.azurecr.io/charts/giantswarm/agent-platform"
ChartRepository is where the agent-platform chart releases live.
const DefaultChartVersion = "4.15.2"
DefaultChartVersion is the agent-platform release the lab installs when agentlab.yaml pins none — the release this agentlab was verified with: the 4.x line (kagent API v2 with Agent Substrate and the platform Postgres shipped by the chart). Bump deliberately, with a lab run: the lab never floats.
const DefaultDevRegistryPort = 5001
DefaultDevRegistryPort is the host port of the lab registry when agentlab.yaml sets none: kind's documented local-registry port.
const DefaultDexPort = 32000
DefaultDexPort is the lab Dex NodePort when agentlab.yaml sets none.
const DevImageHarness = "harness"
DevImageHarness is the devImages key of the platform Harness's workload image — the Go ADK runtime every agent runs on under kagent API v2. Not a Deployment: the connectivity chart renders the image by digest into the `Harness` object, and Substrate's atelet pulls it from a registry into its own layer cache, so the lab pushes the local build to its registry (DevRegistryPort) and forwards the digest through kagent.harness.image.
const DevImageKlausGateway = "klaus-gateway"
DevImageKlausGateway is the devImages key of the klaus-gateway component (platform.klausGateway): the Deployment `klaus-gateway`, container `klaus-gateway`. Meaningful only while the component is on.
const File = "agentlab.yaml"
File is the configuration file written next to the binary's working directory by `agentlab configure` and read by every other command.
const GatewayNodePort = 30443
GatewayNodePort is the fixed NodePort publishing the agentgateway edge (the chart-owned Gateway's HTTPS :443 listener) on the kind node. The data-plane Service is created by the agentgateway controller at run time — not part of the Helm release, so neither values nor a postRenderers patch can pin its NodePort. The lab renders its own selector-matched NodePort Service instead (gateway-nodeport.yaml.tmpl), pinned here so the kind port mapping has a stable node-side port. Host side: Platform.GatewayPort.
const GatewayPublicNodePort = 30444
GatewayPublicNodePort pins the NodePort of the edge Service's second port (platform.gatewayPort, rendered off 443 only) so the apiserver never picks one that collides with the other fixed NodePorts. Nothing on the host maps it.
const KagentUINodePort = 30880
KagentUINodePort is the fixed NodePort the kagent-ui Service is pinned to, so the kind port mapping (created once, at cluster creation) has a stable node-side port to publish. The kagent chart renders `ui.service.type` but no `nodePort` field, so the pin is a Kustomize patch in the kagent component's `postRenderers` (HACKS.md U9). A real Kubernetes NodePort, hence the 30000-32767 range; the host side is configurable via Platform.AgentsPort.
const MusterNodePort = 8090
MusterNodePort is the port muster's aggregator binds on the kind node (hostNetwork). It is the muster chart's default listen port, not a lab choice: in-node consumers (Backstage) always dial localhost:8090, while the host-side port mapping is configurable via Platform.MusterPort.
Variables ¶
var DevImageComponents = []string{"muster", "backstage", "kagent", "mcp-kubernetes", "model-manager", "agent-manager", "vm-manager", DevImageKlausGateway, DevImageHarness}
DevImageComponents are the targets platform.devImages can swap: the agent-platform chart's component names (its `components.<name>` entries) for the Deployments the lab's dev loops build from a checkout, plus DevImageHarness for the platform Harness's runtime image.
var Groups = []string{groupPlatformAdmins, groupDevelopers, groupViewers}
var ModelManagerBackends = backendKinds()
ModelManagerBackends lists the backends the lab accepts, in the canonical order `agentlab configure` writes them — which is also the preference for the one model-manager fronts.
var ModelProviderNames = []string{ProviderOpenAI, ProviderAnthropic, ProviderGemini, ProviderOllama}
ModelProviderNames is ModelProviders' keys in a stable order, for the form options and error messages.
var ModelProviders = map[string]string{ ProviderOpenAI: "OPENAI_API_KEY", ProviderAnthropic: "ANTHROPIC_API_KEY", ProviderGemini: "GOOGLE_API_KEY", ProviderOllama: "", }
ModelProviders maps each provider to the key name inside the Secret. The kagent controller injects that key as an env var of the same name into agent pods, and the ADK runtime looks up exactly these canonical names — so the key name is provider-derived, not configurable. Ollama is keyless (empty key = no Secret).
var PinnedNodePorts = []int{MusterNodePort, KagentUINodePort, GatewayNodePort, GatewayPublicNodePort}
PinnedNodePorts are the node-side ports the lab fixes itself. They share the node's port space with DexPort, whose Service claims the host port as its NodePort, so nothing else may take one of these numbers.
Functions ¶
func BackendPort ¶ added in v0.15.0
BackendPort is the default API port of a backend's server, 0 for a kind the lab does not know.
func BackendServerName ¶ added in v0.15.0
BackendServerName is a backend's server as messages name it; an unknown kind is named by itself rather than mistaken for one of the known servers.
func SanitizeBranch ¶ added in v0.27.0
SanitizeBranch spells a git branch the way gitsemver (v2.0.1, sanitizeBranchName) embeds it in a dev version: lowercased, runs of anything but [a-z0-9] collapsed to one hyphen, hyphens trimmed off both ends — `poc/kagent-main` is `poc-kagent-main`. A purely numeric result loses its leading zeros (a semver numeric identifier forbids them); an empty result is gitsemver's "unknown". gitsemver may further shorten the name to fit its 63-character version budget (head`--`tail), which the dev-tag filter accounts for.
func ValidateAIModel ¶
ValidateAIModel constrains the DEFAULT model to Anthropic: both consumers (the kagent ModelConfig provider and Backstage's ai-chat prefix routing) are wired for Anthropic only, keyed by the one $ANTHROPIC_API_KEY secret. Other providers go through platform.extraModels instead.
func ValidateAPIKeyEnv ¶ added in v0.10.0
ValidateAPIKeyEnv accepts an env var name or empty (keyless endpoint).
func ValidateChartBranch ¶ added in v0.27.0
ValidateChartBranch accepts a branch name that leaves something to match a dev tag with; "" is the stable channel and always fine.
func ValidateChartVersion ¶ added in v0.23.0
ValidateChartVersion accepts an exact chart version only.
func ValidateClusterName ¶
ValidateClusterName is the one home of the cluster-name rule; the huh form uses it directly as an input validator.
func ValidateImageRef ¶ added in v0.23.0
ValidateImageRef accepts an image reference that names its tag or digest.
func ValidateModelName ¶ added in v0.10.0
ValidateModelName is the one home of the extra-model-name rule; the huh form uses it directly as an input validator.
func ValidateNodePort ¶
ValidateNodePort checks the Kubernetes NodePort range; the Dex port must be a NodePort because the Service exposes it as one. String-typed (like ValidatePort) so the huh form inputs can use it directly.
func ValidatePort ¶
Types ¶
type Backstage ¶
type Backstage struct {
Enabled bool `yaml:"enabled"`
// Backstage binds this port on the node (hostNetwork) and kind maps the
// same number onto the host, so the URL is identical on both sides.
// The image is not configured here: the agent-platform chart's backstage
// component (its version range, resolved by the chart's Flux) decides the
// version; platform.devImages swaps in a build of your own.
Port int `yaml:"port"`
}
type Config ¶
type Config struct {
// Kind cluster name; also prefixes RBAC bindings and names the muster
// installation surfaced in Backstage.
ClusterName string `yaml:"clusterName"`
// Dex NodePort == host port: the issuer https://localhost:<port>/dex must
// be the same URL from the Mac and from inside the node, so both sides
// use one number. Must sit in the NodePort range (30000-32767).
DexPort int `yaml:"dexPort"`
DexImage string `yaml:"dexImage"`
// The Claude model both AI consumers use: the platform agents' default
// ModelConfig (kagent) and Backstage's ai-chat. The API key is NOT config:
// it is read from $ANTHROPIC_API_KEY at deploy time and lands only in
// Kubernetes Secrets, never in this file or in rendered manifests.
AIModel string `yaml:"aiModel"`
Users []User `yaml:"users"`
Platform Platform `yaml:"platform"`
Backstage Backstage `yaml:"backstage"`
}
func Default ¶
func Default() *Config
Default returns the canonical lab setup: the agent platform enabled (it is what the lab exists to test) with the agentgateway edge and Backstage — the real platform topology — three users, and Dex on 32000.
func Load ¶
Load reads agentlab.yaml. A missing file is reported as os.ErrNotExist so callers can decide whether to fall back to the form or to defaults.
func (*Config) AdminUser ¶
AdminUser returns the first user in platform-admins: the identity the up verification loop and the smoke tests default to.
func (*Config) AgentgatewayBaseURL ¶ added in v0.11.0
AgentgatewayBaseURL is the agentgateway hostname through the edge: the path-prefixed platform APIs (the kagent controller at /kagent, model-manager at /model-manager) live here, same as the chart's Backstage app-config derives them.
func (*Config) BackstageBaseURL ¶
BackstageBaseURL is Backstage's public URL through the agentgateway edge.
func (*Config) BackstageDirectURL ¶
BackstageDirectURL bypasses the edge (hostNetwork port mapping), kept for debugging.
func (*Config) ChartMajor ¶ added in v0.39.1
ChartMajor is the major version of the meta chart release platform. chartVersion pins (a leading v tolerated); 0 when it is not an exact version — ValidateChartVersion rejects that before anything renders.
func (*Config) ChooseFreePorts ¶ added in v0.7.0
func (c *Config) ChooseFreePorts(ours map[int]bool, minPublishable int) []PortChange
ChooseFreePorts probes every host-side port of the configuration on 127.0.0.1 — the address all kind port mappings bind — and moves each unusable one to a nearby free port, returning what changed so the caller can tell the user. Ports in `ours` are the lab's own (published by an existing kind node of this very configuration) and never count as occupied. Ports below minPublishable are ones the container engine cannot bind at all (rootless podman and the privileged range); pass 1 where every port is available. Meant for a configuration whose cluster does not exist (yet, or any more): an existing cluster's mappings are fixed at node creation, where renumbering would only mislead — PortConflicts is the read-only check for that case.
func (*Config) ControlPlaneNode ¶
ControlPlaneNode is the docker container name kind gives the (only) node.
func (*Config) EnsureHashes ¶
EnsureHashes fills in User.PasswordHash wherever it is missing or no longer matches the password. The hash is cached in the config file on purpose: bcrypt salts are random, so hashing at render time would change the Dex manifest (and roll the pod) on every single run.
func (*Config) FindUserInGroup ¶ added in v0.13.0
FindUserInGroup returns the first user carrying group, or nil.
func (*Config) KagentUIBaseURL ¶
func (*Config) KlausGatewayEnabled ¶ added in v0.45.0
KlausGatewayEnabled reports whether the platform runs the klaus-gateway component: the platform with its agents runtime, and the key on.
func (*Config) LegacyChart ¶ added in v0.39.1
LegacyChart reports whether the lab installs a released meta chart of the 3.x line: an exact platform.chartVersion below 4.0.0 on the stable channel. The 3.x line's values are a different shape (kagent 0.10 with its bundled Postgres, no Agent Substrate, no platform Postgres, a closed root schema that refuses the 4.x keys), so the lab values render in that shape for it; a dev channel (platform.chartBranch) or a chart directory (platform.chartPath) is always the current line, whatever version its Chart.yaml or resolved tag carries.
func (*Config) MCPServerName ¶
MCPServerName is the MCPServer CR name the umbrella chart registers for its bundled mcp-kubernetes (templates/mcp-kubernetes/mcpserver.yaml): a fixed name, independent of the cluster. Muster prefixes the server's tools with it: x_mcp-kubernetes_<tool>.
func (*Config) ModelManagerBaseURL ¶ added in v0.11.0
ModelManagerBaseURL is the model-manager API through the edge — the umbrella's components.model-manager.route (pathPrefix /model-manager, stripped before the service, so its REST API sits at <base>/api/v1). The route's JWT policy wants a Dex token on every call.
func (*Config) ModelManagerEnabled ¶ added in v0.11.0
ModelManagerEnabled reports whether the platform installs model-manager.
func (*Config) MusterBaseURL ¶
MusterBaseURL is muster's public URL: client -> agentgateway edge -> muster, the real platform topology. What Claude Code dials and what muster's OAuth server advertises.
func (*Config) MusterDirectURL ¶
MusterDirectURL bypasses the edge: the hostNetwork port mapping straight to muster, kept for debugging the lab's own plumbing.
func (*Config) Normalize ¶
func (c *Config) Normalize()
Normalize applies cross-field implications after an entry point sets the enable flags: Backstage's muster plugin is the reason to run it, so it implies the platform. Validate stays the backstop for hand-edited files.
func (*Config) ObservabilityBaseURL ¶ added in v0.6.0
ObservabilityBaseURL is the lab Prometheus's public query API through the edge, at the /prometheus prefix Backstage's Mimir integration expects (observability-route.yaml.tmpl). Backstage itself always dials it in-cluster on 443 (the CoreDNS rewrite), so only host-side callers see GatewayPort.
func (*Config) PortConflicts ¶ added in v0.15.0
func (c *Config) PortConflicts(ours map[int]bool) []PortConflict
PortConflicts reports which host-side ports of the configuration another process holds, ignoring the lab's own (`ours`, the ports the existing kind node publishes). Nothing is changed.
func (*Config) VMManagerEnabled ¶ added in v0.43.0
VMManagerEnabled reports whether the platform registers the host vm-manager with muster. The platform is all it needs: vm-manager is an MCP server of muster's, not a consumer of the agents runtime.
type ExtraModel ¶ added in v0.10.0
type ExtraModel struct {
// ModelConfig CR name; also names the key Secret kagent-<name>.
Name string `yaml:"name"`
// One of ModelProviders (a subset of the kagent CRD's enum: the providers
// expressible with just a model + base URL).
Provider string `yaml:"provider"`
// The provider's model id (what the endpoint serves, e.g. `qwen3-8-27b`
// for a local vLLM or `deepseek/deepseek-chat` on OpenRouter).
Model string `yaml:"model"`
// Endpoint override. Required for Ollama (the in-cluster default would be
// useless), optional for OpenAI/Anthropic (any compatible endpoint:
// vLLM `http://host:8000/v1`, OpenRouter `https://openrouter.ai/api/v1`),
// not applicable to Gemini.
BaseURL string `yaml:"baseUrl,omitempty"`
// Host env var holding the API key at deploy time. Empty means a keyless
// endpoint: the Secret is still created with a placeholder, because the
// kagent ADK runtime requires the provider's env var to exist.
APIKeyEnv string `yaml:"apiKeyEnv,omitempty"`
// Skip TLS verification on the provider connection (ModelConfig spec.tls.
// disableVerify) — for self-hosted endpoints with self-signed certs.
InsecureTLS bool `yaml:"insecureTLS,omitempty"`
}
ExtraModel is one additional kagent ModelConfig. API keys are NOT config: APIKeyEnv only names the host env var read at deploy time — the value lands in the Secret kagent-<name>, never in this file or in rendered state/.
func (ExtraModel) NeedsSecret ¶ added in v0.10.0
func (m ExtraModel) NeedsSecret() bool
NeedsSecret reports whether this model's ModelConfig references a Secret.
func (ExtraModel) SecretKey ¶ added in v0.10.0
func (m ExtraModel) SecretKey() string
SecretKey is the key inside the Secret — the provider's canonical env var name. Empty for keyless providers (no Secret attached at all).
func (ExtraModel) SecretName ¶ added in v0.10.0
func (m ExtraModel) SecretName() string
SecretName is the Kubernetes Secret (in ns kagent) holding this model's key.
func (ExtraModel) Validate ¶ added in v0.10.0
func (m ExtraModel) Validate() error
Validate checks one extra model entry; string-typed like the port validators where the form shares it, entry-level here.
type KlausGateway ¶ added in v0.45.0
type KlausGateway struct {
// On, `agentlab platform` enables components.klaus-gateway with the
// lab's values (the values template's `klausGateway:` block) and creates
// the two Secrets the component reads: the placeholder Slack
// credentials and the OBO keys.
Enabled bool `yaml:"enabled"`
}
KlausGateway configures the chart's klaus-gateway component in the lab.
type ModelManager ¶ added in v0.11.0
type ModelManager struct {
// On, `agentlab platform` enables components.model-manager in front of
// every listed backend, its agentgateway route (JWT-validated: the portal
// backend forwards the user's Dex token) and the muster registration.
// `agentlab configure` turns it on whenever a host model server answers
// (and off when none does), unless --model-manager pins it.
Enabled bool `yaml:"enabled"`
// The host model servers, in order; backends.go names them and owns the
// list, so this comment cannot go stale as servers are added. ONE
// model-manager fronts all of them at once (model-manager >= 0.17.0,
// `model-manager.backends` in the chart values); the first entry is its
// default backend — where a request that names none goes. `agentlab
// configure` fills the list from what answers on this machine and can be
// reached from pods (Ollama first); --model-manager-backends pins it.
// kserve is no lab backend: GPU nodes and a KServe install.
Backends []string `yaml:"backends,omitempty"`
// Per-backend base URL as pods reach it, keyed by backend. Empty
// autodetects http://<kind docker network gateway>:<default port> at
// platform time (BackendPort names each server's) — the same
// address docs/models.md documents for extraModels (`docker network inspect
// kind`). Set one for a server elsewhere on the LAN: a backend with an
// endpoint here is kept by `agentlab configure` whether or not a server
// answers on this machine.
Endpoints map[string]string `yaml:"endpoints,omitempty"`
// The one-backend form earlier versions wrote (backend + endpoint):
// still read, folded into backends/endpoints on load, never written.
Backend string `yaml:"backend,omitempty"`
Endpoint string `yaml:"endpoint,omitempty"`
}
ModelManager configures the umbrella's model-manager component in the lab.
func (*ModelManager) ApplyDiscovered ¶ added in v0.15.0
func (m *ModelManager) ApplyDiscovered(found []string, agents bool, pinEnabled *bool, pinBackends []string)
ApplyDiscovered merges what `agentlab configure` found on this machine into the block: the backends are the servers that answer plus every backend kept by an explicit endpoint (a server elsewhere on the LAN), in canonical order; managed models go on when there is at least one and the agents runtime is on, and off otherwise. pinBackends (--model-manager-backends) replaces the list outright; pinEnabled (--model-manager) decides the flag instead of the discovery — a pinned-on block without a backend falls back to the Ollama default, so the platform preflight reports the real reachability error.
func (ModelManager) EndpointFor ¶ added in v0.15.0
func (m ModelManager) EndpointFor(backend string) string
EndpointFor is the configured endpoint override of a backend, "" to autodetect.
func (ModelManager) Primary ¶ added in v0.15.0
func (m ModelManager) Primary() string
Primary is model-manager's default backend — where a request that names none goes: the first of the list, or the historical default (an Ollama) for an enabled block that names none.
func (ModelManager) Validate ¶ added in v0.11.0
func (m ModelManager) Validate(agents bool) error
Validate checks the model-manager block; agents reports whether the kagent runtime is on (model-manager wires ModelConfigs into it).
type Platform ¶
type Platform struct {
Enabled bool `yaml:"enabled"`
// The agents runtime (kagent), an optional part of the platform install.
// On real clusters agent delivery runs through Flux/GitOps, which the lab
// does not run, so labs that are not exercising agents can skip the
// runtime entirely. Inert when the platform itself is disabled.
Agents bool `yaml:"agents"`
// A minimal observability stack: the Giant Swarm kube-prometheus-stack
// chart (the observability bundle's own pinned constituent, with the
// Prometheus server re-enabled — the bundle itself is MC-shaped: Alloy
// remote-writing to Mimir, no local query endpoint) plus mcp-prometheus
// registered in muster, so agents can answer PromQL questions
// (x_mcp-prometheus_<tool>). On by default: asking the platform about the
// cluster's CPU/memory is part of the demo story. Not in the umbrella's
// BOM (yet) — the lab pins the two charts itself (observability.go).
// Inert when the platform itself is disabled.
Observability bool `yaml:"observability"`
// The fake fleet (lab/fleetfixture.go): six `Auth Required` MCPServers
// (kubernetes/capi/prometheus × two fake management clusters) that give
// the portal's server groups, its fleet coverage and the agent Tools
// step a federated shape to render on one cluster. Off by default: a
// default lab lists only the MCP servers of the lab that runs it, and
// the fixture's rows ask a person to sign in to clusters that do not
// exist. Switching it off removes the members on the next `agentlab
// platform`; the proofs assert the fleet shape only while it is on.
// Inert when the platform itself is disabled.
FakeFleet bool `yaml:"fakeFleet"`
// Host-side port for the kagent UI (http://localhost:<port>). The kind
// mapping onto KagentUINodePort always exists — like the other mappings,
// it is fixed at cluster creation — so agents can be enabled later.
AgentsPort int `yaml:"agentsPort"`
// Host-side port for muster's DIRECT debug access (hostNetwork + kind
// mapping, bypassing the gateway). The platform's public URLs go through
// the agentgateway edge on GatewayPort.
MusterPort int `yaml:"musterPort"`
// The platform's public domain. Every public hostname derives from it
// (muster.<domain>, backstage.<domain>, ...). The default, nip.io's
// loopback wildcard, resolves to 127.0.0.1 from anywhere without host
// configuration; inside pods a CoreDNS rewrite points the same names at
// the edge Gateway Service.
Domain string `yaml:"domain"`
// Host-side port of the agentgateway edge (HTTPS). 443 keeps the public
// URLs port-free; any other value suffixes every public URL with it, and
// the lab's edge Service (gateway-nodeport.yaml.tmpl) then also serves
// that port in-cluster, so the ported URLs resolve from pods too. Change
// only if 443 is taken.
GatewayPort int `yaml:"gatewayPort"`
// TLS optionally hands the edge an externally provisioned certificate
// pair (PEM) instead of the minted lab-CA wildcard — for users who own a
// real domain (wildcard record -> 127.0.0.1) and run their own ACME
// tooling. Both fields set or both empty. The Dex issuer still serves
// the lab CA either way; see docs/tls.md.
TLS PlatformTLS `yaml:"tls"`
// The agent-platform chart release the lab installs
// (oci://gsoci.azurecr.io/charts/giantswarm/agent-platform): an exact
// version, never a range — two runs install the same thing, and the lab
// never floats onto a release nobody tested it with. DefaultChartVersion
// is the release this agentlab was verified against.
ChartVersion string `yaml:"chartVersion"`
// ChartPath installs the meta chart from a local directory instead of the
// pinned release — an agent-platform checkout's helm/agent-platform, for
// chart changes that have no release yet (the lab's chart loop). The
// directory is read, never written; chartVersion is ignored while set.
ChartPath string `yaml:"chartPath,omitempty"`
// ChartBranch selects the DEV CHANNEL: the lab follows the newest dev
// build of this agent-platform branch — the `X.Y.Z-dev.<branch>.<date>.
// <time>.h<sha>` prerelease tags gitsemver publishes for every commit of
// a branch with branch publishing on — instead of a release. `configure`,
// `up` and `platform` resolve it against the chart registry's tags and
// write the tag they picked into chartVersion, so `render`, the image
// preload and a re-run install exactly what was resolved, and the boot
// says which build it runs. Mutually exclusive with chartPath; "" is the
// stable channel. See docs/platform.md "Dev channel".
ChartBranch string `yaml:"chartBranch,omitempty"`
// ChartPinned freezes chartVersion at the recorded dev build while
// chartBranch is set: `up` and `platform` stop re-resolving, so the lab
// keeps running the build under test until `agentlab platform --pin=false`
// (or the key is dropped). Meaningless without chartBranch.
ChartPinned bool `yaml:"chartPinned,omitempty"`
// DevImages swaps a component's image for a build of your own (the lab's
// dev-image loop): target -> image ref (`muster: muster:dev-1a2b`). Keys
// are the DevImageComponents. For a Deployment target `agentlab platform`
// side-loads the ref from the host docker cache, resolves the image name
// it replaces from the component chart's render (the kagent controller is
// `ghcr.io/giantswarm/kagent/controller` on the 4.x line and
// `gsoci.azurecr.io/giantswarm/kagent-controller` on 3.x — a target that
// matches nothing in the render is an error before the install, never a
// silently dropped override) and renders it into the component's
// HelmRelease as a kustomize image override (postRenderers) with
// imagePullPolicy IfNotPresent. For the `harness` target it pushes the
// build to the lab registry and forwards the digest as
// kagent.harness.image, so the platform Harness runs it and recompiles
// every admitted template. Either way the swap is part of the release — a
// plain `helm upgrade` applies it, and removing the entry restores the
// chart's image (or digest) on the next run.
DevImages map[string]string `yaml:"devImages,omitempty"`
// DevRegistryPort is the host port (127.0.0.1) of the lab registry that
// serves the `harness` dev image: a `registry` container on the kind
// docker network, created on demand by `agentlab platform` and removed by
// `agentlab down`. Unset means DefaultDevRegistryPort.
DevRegistryPort int `yaml:"devRegistryPort,omitempty"`
// ValuesFiles are extra Helm values files merged over the lab's rendered
// values before the meta chart install, in order, with `helm -f`
// semantics (maps merge, lists replace, the later file wins): a lab that
// points a component at another chart source
// (components.<name>.repository / versionRange / insecure) or forwards
// values the lab template does not know. Paths are absolute or relative
// to the lab directory; each must exist.
ValuesFiles []string `yaml:"valuesFiles,omitempty"`
// Additional kagent ModelConfigs beyond the chart-rendered default
// (aiModel): self-hosted OpenAI-compatible endpoints (vLLM, Ollama),
// OpenRouter, Gemini, plain OpenAI. Rendered as lab-labeled ModelConfig
// CRs by `agentlab platform`; entries removed here are pruned on the next
// run. Inert unless agents are enabled.
ExtraModels []ExtraModel `yaml:"extraModels,omitempty"`
// Managed models: the chart's model-manager component in front of the
// model servers that run on the lab host (backends.go is the list, with
// each server's port and name) — pull, load,
// unload and delete models from the portal (or as x_model-manager_*
// tools through muster), each pulled model wired into kagent as a
// keyless ModelConfig automatically. Complements extraModels, which
// wires endpoints statically and manages nothing. Requires agents.
// `agentlab configure` fills the backends from what answers on this
// machine, on every run.
ModelManager ModelManager `yaml:"modelManager"`
// The platform's VM provisioner (github.com/giantswarm/vm-manager) as a
// pod of the kind node: the chart's components.vm-manager, turned on by
// the lab's values (x_vm-manager_<tool> through muster, tool group
// agent-platform, forward-token auth against the lab Dex). The node is a
// privileged container, so the host's /dev/kvm and /dev/vhost-vsock are
// in it for the pod. The guest image is the artifact the chart's release
// published, or a local build pushed into the lab registry (imageDir).
// `agentlab configure` turns it off on a machine without the devices;
// --vm-manager turns it on. A build of the checkout swaps in through
// devImages.
VMManager VMManager `yaml:"vmManager"`
// Swarmgeist (github.com/giantswarm/klaus-gateway) as the meta chart's
// in-cluster component (components.klaus-gateway), the way every
// installation runs it: A2A to the kagent controller over the in-cluster
// agentgateway target, the web channel, the Slack adapter on a
// placeholder credentials Secret (no workspace answers it; the gateway
// refuses OBO without Slack), and the OBO link store as a Kubernetes
// Secret (obo.store: secret) with keys the lab generates once. Off by
// default; --klaus-gateway turns it on; needs the agents runtime. A build
// of the checkout swaps in through devImages. `agentlab
// klaus-gateway-test` proves it next to the host-mode gateway
// (klausgateway.go).
KlausGateway KlausGateway `yaml:"klausGateway"`
}
type PlatformTLS ¶
type PlatformTLS struct {
CertFile string `yaml:"certFile,omitempty"`
KeyFile string `yaml:"keyFile,omitempty"`
}
PlatformTLS is an externally provisioned certificate for the edge; see Platform.TLS.
func (PlatformTLS) Set ¶
func (t PlatformTLS) Set() bool
Set reports whether an external edge certificate is configured.
type PortChange ¶ added in v0.7.0
PortChange records one port of the configuration that was moved off its value because this machine cannot serve the lab there. Field is the agentlab.yaml path, What names the component for the human-facing message, Why says what made the port unusable, and Note carries an extra caveat where a non-default port has consequences beyond the number itself.
func (PortChange) String ¶ added in v0.7.0
func (ch PortChange) String() string
type PortConflict ¶ added in v0.15.0
PortConflict records one port of an existing cluster's configuration that another process on this machine holds — the lab cannot renumber it (the kind mappings are fixed at node creation), so it is reported instead.
func (PortConflict) String ¶ added in v0.15.0
func (pc PortConflict) String() string
type User ¶
type VMManager ¶ added in v0.43.0
type VMManager struct {
// On, `agentlab platform` enables components.vm-manager: the pod with
// the node's KVM devices, OAuth against the lab Dex and the muster
// registration the chart renders. Refused on a machine without /dev/kvm
// and /dev/vhost-vsock (`agentlab configure` turns it off there).
Enabled bool `yaml:"enabled"`
// A local guest image build the pod boots instead of the artifact the
// chart's release published — a vm-manager checkout's images/build
// after `make -C images`: the base image, its UKI, the Kubernetes sysext
// layers and policy.json. `agentlab platform` pushes it into the lab
// registry and pins the chart to its digest, so a rebuilt image rolls
// the pod on the next run. Empty: the release's guest image. An absolute
// path, or relative to the lab directory.
ImageDir string `yaml:"imageDir,omitempty"`
}
VMManager configures the chart's vm-manager component in the lab.
func (*VMManager) ApplyDiscovered ¶ added in v0.43.0
ApplyDiscovered follows what `agentlab configure` found: a machine without the KVM devices cannot run the pod, so the key goes off there with the reason; a machine with them keeps what the file says (the pod is a heavier piece of the lab than a model server, so it is never turned on by itself); pinEnabled (--vm-manager) decides instead.