/** * Per-forwarder Helm install plans for the Log10x Receiver, plus the * standalone Reporter chart. * * Two deployment models live in this file: * * 1. RECEIVER — a `log10x/edge-10x` sidecar container injected into * the user's existing forwarder pod via a values overlay * (`extraContainers` + `extraVolumes` + per-chart config rewiring). * The forwarder chart is always the UPSTREAM one (no Log10x * repackages). The sidecar reads its license JWT from a * Kubernetes Secret mounted at `/etc/tenx/license/license.jwt` * via `TENX_LICENSE_FILE`. Each forwarder has a different * config-rewiring shape (Fluent Bit replaces `config:`, OTel * deep-merges `config:`, Vector replaces `customConfig`, Logstash * uses `logstashConfig` + `logstashPipeline`, Fluentd needs a * kustomize post-renderer that emits a sidecar-patch). * * Filebeat is the exception: the upstream `elastic/filebeat` chart * exposes no extraContainers/extraVolumes hooks, so it runs the * engine as a child process inside the `filebeat` container via an * image swap to `log10x/filebeat-10x` instead of a sidecar. * * 2. REPORTER (`STANDALONE_SPEC`) — Log10x's own `log10x/reporter-10x` * chart bundles a fluent-bit + tenx-edge that tail * `/var/log/containers/*.log` in parallel to the user's forwarder. * Read-only, zero-touch. The chart uses a flat values layout with * `log10xLicenseJwt` at the top level and a `tenx:` block ONLY for * engine resource overrides / extraArgs / extraEnv. License * delivery: chart-managed Secret by default (JWT inlined into * `log10xLicenseJwt`), or user-supplied Secret via * `licenseSecret.{create:false, existingSecret, secretKey}` for * real (non-demo) licenses. * * Sources of truth: * - Receiver overlays: mksite/docs/apps/receiver/deploy.md * - Standalone Reporter chart: mksite/docs/apps/reporter/deploy.md */ import type { ForwarderKind, MetricsBackendKind, BackendCredentialConfig } from '../discovery/types.js'; export type OutputDestination = 'mock' | 'elasticsearch' | 'splunk' | 'datadog' | 'cloudwatch'; /** How a forwarder's helm chart labels its workloads + pods. */ export type SelectorStyle = 'k8s-recommended' | 'legacy-helm'; export interface ForwarderSpec { /** Display name. */ label: string; /** One-sentence architecture summary. */ integrationMode: string; /** Helm repo URL. */ helmRepo: string; /** Helm repo alias used in `helm repo add`. */ helmRepoAlias: string; /** Published chart reference (`/`). */ chartRef: string; /** Availability of the log10x-repackaged chart. */ chartAvailability: 'published' | 'wip' | 'upstream-fallback'; /** Default container image reference (for messaging only). */ primaryImageHint: string; /** * Container name that verify probes MUST target — the one running the * 10x engine. For the sidecar forwarders (Fluent Bit, Fluentd, * Logstash, Vector, OTel Collector) this is the separate `log10x` * sidecar container injected from `log10x/edge-10x`. For Filebeat — * the only embedded forwarder, image-swapped to `log10x/filebeat-10x` * — the engine runs as a child process *inside* the `filebeat` * container, so this points at `filebeat`. */ primaryContainerName: string; /** * True when this forwarder uses sidecar mode (a separate 10x * container in the pod running `log10x/edge-10x`): Fluent Bit, * Fluentd, Logstash, Vector, OTel Collector, and the standalone * reporter-10x chart (fluent-bit tails, the `tenx` container runs the * engine). False only for Filebeat, which is embedded via an image * swap to `log10x/filebeat-10x`. */ hasTenxSidecar: boolean; /** Label-selector style the chart family uses. */ selectorStyle: SelectorStyle; /** Return the kubectl label selector for a given release. */ selectorLabel: (releaseName: string) => string; /** * Render the values.yaml as a SINGLE coherent YAML document. * * The chart format is unified around the Receiver — every supported * forwarder chart deploys the Receiver app and exposes feature flags * (`optimize`, `readOnly`) for the two opt-in modes: * - default (neither flag): receive + filter events, emit them in * their original form back through the forwarder. * - optimize=true: receive + filter + losslessly compact (volume * reduction varies by destination and by the events). * - readOnly=true: receive + emit TenXSummary metrics, do NOT write * events back through the forwarder (passive observation). * * The two flags are mutually exclusive at the chart level (every chart * has a `tenx-validate.yaml` template that fails helm install if both * are set). The advisor enforces the same invariant upstream. * * Every chart in the supported set (fluent-bit, fluentd, otel-collector, * filebeat, logstash) reads `tenx.optimize` / `tenx.readOnly` directly. */ renderValues: (opts: { /** * Log10x license JWT — the credential the engine consumes. Fetched * from the gateway's `/api/v1/license/demo` (anonymous) or * `/api/v1/license` (Auth0-authed) endpoints. Not the same as the * MCP's `LOG10X_API_KEY` env var, which is used for MCP↔gateway auth. */ licenseJwt: string; /** * True when the JWT was minted from the demo endpoint (anonymous, * 14-day, transient). Renderers inline the JWT for demo licenses * (one-step setup, no Secret to manage). For real (user) licenses * the renderer points the chart at an out-of-band Kubernetes Secret * that the user creates before `helm upgrade` — the JWT itself is * never written into values.yaml. */ isDemoLicense?: boolean; /** Name of the Kubernetes Secret holding the real license JWT (when isDemoLicense=false). */ licenseSecretName?: string; /** Key inside the Secret whose value is the JWT (when isDemoLicense=false). */ licenseSecretKey?: string; releaseName: string; destination: OutputDestination; outputHost?: string; splunkHecToken?: string; /** Placeholder emitted into `tenx.gitToken`. Defaults to the public-repo no-op string. */ gitToken?: string; /** * When true, emit events in compact encoded form (volume reduction * varies by destination and by the events). Mutually exclusive with * `readOnly`. */ optimize?: boolean; /** * When true, run the receiver in read-only mode (passive metrics * emitter — no events written back through the forwarder). Mutually * exclusive with `optimize`. */ readOnly?: boolean; /** * Metrics backends the engine emits TenXSummary to. `['log10x']` is * the chart default (SaaS Prometheus); additional / replacement * backends are wired via `tenx.extraArgs` (`@run/output/metric/`) * and `tenx.extraEnv` (vendor-specific env vars). */ backends?: MetricsBackendKind[]; /** * Per-backend credential configuration (secret name + plain-value * overrides). The wizard collects these from the user; if a backend * is selected but no entry exists here, the renderer falls back to * `-credentials` for the secret name and the per-backend * defaults/placeholders for plain values. */ backendCredentials?: Partial>; /** * When true, the engine runs fully airgapped. For the standalone * Reporter chart this is the top-level `airgapped: true` value; * for Receiver inline overlays it's the `TENX_AIRGAPPED=true` env * var on the engine sidecar. */ airgapped?: boolean; /** * How the helm command lands. Per-forwarder renderers branch on * this to emit either a full chart values file (fresh-release — * Reporter or Receiver with no existing release detected) or a * minimal overlay containing ONLY the keys the receiver adds or * replaces on top of the user's existing chart values * (upgrade-existing — canonical Receiver path; the helm command uses * --reuse-values to keep the user's existing config intact beneath * the overlay). * * Most receiver overlays (fluentbit, otel, vector, logstash) are * minimal already — they only declare extraContainers, extraVolumes, * and the config block. They render the same shape regardless of * mode. Only fluentd needs branched output (the kustomize-post- * renderer chart's values vary substantially between fresh-deploy * and overlay-on-existing). */ installMode?: 'upgrade-existing' | 'fresh-release'; }) => string; /** * Optional: extra files to emit alongside the values.yaml. Used by * forwarders whose sidecar pattern requires more than a single * values file — the Fluentd receiver overlay emits a kustomize * post-renderer directory (`tenx-kustomize/{kustomization.yaml, * sidecar-patch.yaml, post-render.sh, post-render.cmd}`) alongside * its values file. Returning [] is equivalent to omitting the field. * * Paths are relative to the working directory the user runs * `helm upgrade` from. The shell-shim file must declare * `executable: true` so the renderer surfaces a chmod hint AND the * AdvisePlanSummary surfaces `install_requires_chmod=true`. */ renderExtraFiles?: (opts: { releaseName: string; namespace: string; optimize?: boolean; airgapped?: boolean; licenseSecretName: string; licenseSecretKey: string; }) => import('./types.js').PlanFile[]; /** * Optional: extra command-line flags appended to the * `helm upgrade --install` invocation. Used by the Fluentd overlay * to add `--post-renderer ./tenx-kustomize/post-render.sh`. * Returning [] is equivalent to omitting. */ extraHelmFlags?: (opts: { releaseName: string; namespace: string; }) => string[]; /** * Optional: commands to run BEFORE `helm upgrade` (within the * "Install via Helm" step). Used by the Fluentd overlay to chmod * the post-render shim. Returning [] is equivalent to omitting. */ extraInstallCommands?: (opts: { releaseName: string; namespace: string; }) => string[]; /** Verify probes — commands that, collectively, prove data is flowing. */ verifyProbes: (opts: { releaseName: string; namespace: string; destination: OutputDestination; /** True when the install enabled encoded output (see renderValues.optimize). */ optimize?: boolean; /** True when the install enabled read-only mode (no return loop). */ readOnly?: boolean; }) => Array<{ name: string; question: string; commands: string[]; expectOutput?: string; timeoutSec?: number; }>; } /** * Per-backend env-var contract — what the engine's metric output module * reads from the container env. Sourced verbatim from * `config/pipelines/run/output/metric//config.yaml`. If the * engine changes a name, update it HERE — the wizard, the renderer, * and the elicitation form all key off this spec. * * Two classes of env vars: * - `secret`: sensitive (API keys, tokens, passwords) — emitted as * `valueFrom.secretKeyRef` so they're pulled from a k8s Secret. * - `plain`: non-sensitive (URLs, regions, namespaces) — emitted as * direct `value:` strings. * * Each `plain` entry can have a `default` (engine has a sensible * fallback if the user doesn't override) or a `placeholder` (user * MUST supply a value; the renderer emits a ``-style marker so * `helm upgrade` doesn't silently install with garbage). */ export interface BackendEnvSpec { /** Sensitive env vars sourced via `valueFrom.secretKeyRef`. */ secret: Array<{ envVar: string; secretKey: string; }>; /** Non-sensitive env vars sourced via plain `value:`. */ plain: Array<{ envVar: string; default?: string; placeholder?: string; }>; } export declare const BACKEND_ENV_SPECS: Partial>; /** Default Secret name for a given backend when the wizard doesn't override. */ export declare function defaultSecretNameFor(kind: MetricsBackendKind): string; /** * Renders the `extraContainers[log10x]` + `extraVolumes[tenx-license]` * block that every Receiver overlay needs. Per-forwarder specs supply * the engine launch args (`@run/input/forwarder/` + `@apps/receiver` * + optional `receiverOptimize true` for compact mode) and call this * helper to emit the shared sidecar shape consistently. * * Indentation: emits each line with no leading indent. Callers paste * it at column 0 of the values overlay. The two top-level keys it emits * are `extraContainers:` and `extraVolumes:`. * * License delivery: always via the Secret-mounted file pattern * (`TENX_LICENSE_FILE=/etc/tenx/license/license.jwt`). For demo licenses * the caller's pre-install step still has to create the Secret — there * is no "inline JWT" path for the Receiver. The chart values belong to * the user's upstream chart, which interprets no Log10x-specific * top-level field. */ /** Name of the policy ConfigMap the engine's kubernetes pull lane reads * (matches the engine's $K8S_CONFIGMAP default and configure_engine's * kubectl_configmap_name default). */ export declare const POLICY_CONFIGMAP_NAME = "log10x-action-intent"; /** * Engine-policy pull env for the receiver container: activates the engine's * kubernetes ConfigMap lane (K8S_ENABLED, gated off by default engine-side) * and points the regulator's three lookup files at the pull driver's stable * destination `${java.io.tmpdir}/tenx/kubernetes///`. * * K8S_NAMESPACE comes from the downward API so the paths track the pod's * real namespace; `$(K8S_NAMESPACE)` in the file paths is Kubernetes * dependent-env interpolation (order matters: the fieldRef entry must come * first). CAP_LOOKUP_FILE must be explicit — the engine ships it unset so * receivers boot with no policy; setting it is what arms the cap variant * once the pull lane materializes the seeded files (see * renderPolicyConfigMapManifest: the pull crashes a launch on a MISSING * ConfigMap, and the lookup loader refuses a rows-less CSV, so the wizard * seeds both files with a no-op `tenx-seed` row). * * Engines older than the config release that enables the kubernetes lane * ignore K8S_ENABLED entirely — these vars are inert there, and the * regulator keeps running capless exactly as before. * * `indent` is the leading whitespace of each `- name:` line. */ export declare function renderPolicyPullEnvLines(indent: string): string[]; /** * Seed manifest for the policy ConfigMap + the RBAC read grant, applied as * a pre-install step on every Receiver install. * * Why a seed (both facts probed live against the engine): * - the kubernetes pull's FIRST fetch runs on the launch thread and a * missing ConfigMap aborts startup by design; * - the lookup loader refuses a zero-byte AND a header-only CSV, so each * seeded file carries one no-op `tenx-seed` row (matches no container: * cap 1 on a nonexistent key regulates nothing). * configure_engine merges real policy over the seed and drops the seed row * once real rows land. * * The Role grants `get` on this ONE ConfigMap; the binding covers every * ServiceAccount in the namespace because the forwarder chart's SA name * varies per chart and the grant is read-only on a single object. */ export declare function renderPolicyConfigMapManifest(namespace: string): string; export declare const RECEIVER_FORWARDER_SPECS: Record, ForwarderSpec>; export declare const STANDALONE_SPEC: ForwarderSpec;