/** * Retriever install/verify/teardown plan builder. * * Unlike Reporter/Receiver (which ride on top of a forwarder), the * Retriever is a standalone set of workloads (indexer + query-handler * + stream-worker + filter CronJobs) that read from S3 via SQS and * serve an HTTP query endpoint. No forwarder choice — just one chart * (`log10x/retriever-10x` or the log10x-hosted variant) with AWS infra * pointers. * * The advisor's job is to: * - Surface the AWS infra the Retriever expects (S3 input bucket, * index bucket, 4 SQS queues, IRSA role). * - List in `blockers` every input a complete plan is still missing, * and emit no steps while that list is non-empty. The preflight * table is the state report beside it: a `fail` row there is * reported (and counted in the envelope's `preflight_summary`), * not a gate, because the conditions it reads (kubectl unusable, * a release already installed) are not answered by re-invoking * with a different argument. * - Emit a values.yaml that wires the infra into the chart. * - Provide verify probes that prove indexing + querying work, * each gated on the storage provider they belong to. * - Provide teardown. On AWS, helm uninstall only: infra lifecycle is * a Terraform concern. On Azure, the provisioning script's own * `--destroy`, which deletes the resource group it created. * * Two storage providers. `aws` is the historical path: S3 buckets, four SQS * queues, an IRSA role. `azure` targets AKS with Azure Blob Storage and Azure * Storage Queues behind the chart's `storage.provider: azure` block, with AKS * workload identity in place of IRSA. The Azure path is read and index side * only: the Retriever indexes and queries blobs already in the container, and * the forwarder offload recipes stay S3-shaped, so the offload markdown says * so rather than emitting a sink that writes elsewhere. */ import type { DiscoverySnapshot } from '../discovery/types.js'; import type { AdvisePlan } from './types.js'; export interface RetrieverAdviseArgs { snapshot: DiscoverySnapshot; /** Helm release name. Default: `my-retriever`. */ releaseName?: string; /** Target namespace. Default: snapshot's suggestedNamespace. */ namespace?: string; /** * Log10x license JWT — mints from `POST /api/v1/license/demo` (anonymous) * or `POST /api/v1/license` (Auth0-authed). Required for a complete * install plan. * * NOTE: the retriever helm chart uses a different value-key naming * convention from the Reporter chart's `log10xLicenseJwt` (top-level * `apiKeySecret`, with the secret data under `apiKey`), so the retriever * install plan renders the JWT into the `apiKey` slot. */ licenseJwt?: string; /** * Whether `licenseJwt` came from the caller. A JWT the wizard minted on the * caller's behalf is used for nothing that lands on disk: `false` keeps the * key out of every emitted values file. Defaults to `true`, so a direct * caller that passes `licenseJwt` still gets it wired. */ licenseSupplied?: boolean; /** Override: input S3 bucket name. Default: from snapshot. */ inputBucket?: string; /** Override: index bucket (with prefix). Default: `/indexing-results/`. */ indexBucket?: string; /** Override: IRSA role ARN for the retriever SA. Default: from snapshot. */ irsaRoleArn?: string; /** * Which object store the Retriever reads. `aws` (default) is S3 + SQS + * IRSA; `azure` is Azure Blob + Azure Storage Queues + AKS workload * identity, behind the chart's `storage.provider` key. */ storageProvider?: RetrieverStorageProvider; /** Azure storage account holding the containers. Required when storageProvider is `azure`. */ storageAccount?: string; /** Azure resource group, for the provisioning command and the teardown in the plan. */ resourceGroup?: string; /** * AKS cluster the release installs into. Used both by the provisioning * command and by the `az aks get-credentials` step that points kubectl at * the cluster before any kubectl command runs. */ aksCluster?: string; /** Azure region for the provisioning command (e.g. `eastus`). */ location?: string; /** Client id of the user-assigned managed identity federated to the release ServiceAccount. */ azureClientId?: string; /** Entra tenant id. */ azureTenantId?: string; /** Azure Storage Queue names, in place of the four SQS URLs. */ azureQueues?: { index?: string; query?: string; subquery?: string; stream?: string; }; /** Override: SQS queue URLs. Default: from snapshot.recommendations.retrieverSqsUrls. */ sqsUrls?: { index?: string; query?: string; subquery?: string; stream?: string; }; /** Skip install. */ skipInstall?: boolean; /** Skip teardown. */ skipTeardown?: boolean; /** Skip verify. */ skipVerify?: boolean; /** * Destination SIEM the customer routes the kept slice to. Used to gate * the SIEM down-tier sub-sections in the offload markdown * (Datadog Flex only for `datadog`, CloudWatch IA only for `cloudwatch`, * etc., per `DEFAULT_ACTION_BY_DESTINATION`). When omitted, the offload * section shows both leads. */ destination?: string; } /** Object store behind the Retriever. */ export type RetrieverStorageProvider = 'aws' | 'azure'; /** * Blob containers the provisioning script creates, and the names it creates * them under when the plan passes neither `--input-container` nor * `--index-container` (which it does not). Read off * `scripts/azure/provision-retriever.sh` in chart 1.0.24: the defaults are * `logs` and `tenx-index`, and the BlobCreated event subscription the same run * creates is filtered to `--subject-begins-with * /blobServices/default/containers//`. * * Both facts matter to the caller: a container name other than `logs` names * something the script never created, and even once created by hand it carries * no event subscription, so an upload into it raises no BlobCreated event and * the indexer never hears about the blob. */ export declare const AZURE_SCRIPT_INPUT_CONTAINER = "logs"; export declare const AZURE_SCRIPT_INDEX_CONTAINER = "tenx-index"; /** Chart version carrying the Azure provisioning script this advisor quotes. */ export declare const RETRIEVER_CHART_VERSION = "1.0.24"; /** Engine image the Azure path documents and the provisioning script pins. */ export declare const RETRIEVER_IMAGE_TAG = "1.1.78"; /** * Node size for a cluster the script creates. The Azure CLI default * (`Standard_D4d_v4`) is refused on subscriptions that do not carry that * family, which stops a first install dead, so the size is always passed. * * The value matches the provisioning script's own default. `Standard_D2s_v5` * was refused on the subscription the Azure path was proved against, and the * script moved to v7; an advisor that keeps passing v5 overrides the working * default with the refused one. */ export declare const AKS_NODE_SIZE = "Standard_D2s_v7"; /** * What the chart labels a retriever pod, and what it names the container. * * From `retriever-10x` 1.0.24: `templates/deployment.yaml` stamps * `app: {{ chart name }}` and `cluster: {{ cluster.name }}` on the pod, and * names the container `{{ chart name }}-{{ cluster.name }}`. The default * cluster in `values.yaml` is `all-in-one`. Nothing in the chart sets * `app.kubernetes.io/instance`, so a selector on that key matches no pod and * every probe built on it reports "No resources found" instead of the state * it was asked about. */ export declare const RETRIEVER_POD_SELECTOR = "app=retriever-10x"; export declare const RETRIEVER_CONTAINER = "retriever-10x-all-in-one"; /** Cluster entry the chart ships, and the suffix on every per-cluster object. */ export declare const RETRIEVER_CLUSTER_NAME = "all-in-one"; /** * The provisioning script that ships with the retriever chart. One run creates * the account, the two containers, the four queues, the managed identity and * its two blob/queue data roles, the Event Grid system topic and its * BlobCreated subscription onto the index queue, and the federated credential * binding the identity to the release ServiceAccount, then writes a values * file. * * The path is the one inside the untarred chart tarball, which is the only * copy a customer has. `charts/retriever/scripts/azure/...` is a path in the * chart source repo and exists in nothing a customer downloads. */ export declare const AZURE_PROVISION_SCRIPT = "retriever-10x/scripts/azure/provision-retriever.sh"; /** * Where a query's results land, and the shape of the path. `` is * the script's `--index-path` (default `tenx`); the literal `tenx` segment * after it is the engine's own, and `` is the first path segment of the * indexed blob, which is also what the query's `name` field must equal. * * One level below the queryId comes a slice segment, `_`, * because each scan task writes under the time slice it was dispatched for * (`IndexObjectQueryResultsWriter`: `{queryId}/{sliceFrom}_{sliceTo}/{worker}.jsonl`). * A listing that stops at the queryId prefix sees folders rather than objects, * so every list in this plan is recursive. */ export declare const AZURE_RESULT_PATH = "//tenx//qr//_/.jsonl"; /** * How long a bounded poll of the results prefix runs before the answer comes * from `_DONE.json` instead. Ten polls fifteen seconds apart is two and a half * minutes, which covers a one-hour window sliced a minute at a time on a * single-node cluster. */ export declare const AZURE_RESULT_POLL_ATTEMPTS = 10; export declare const AZURE_RESULT_POLL_INTERVAL_SEC = 15; /** * Two facts a first install needs and neither the chart nor the script states: * the operator's own data-plane access, and what `_DONE.json` is not. */ export declare const AZURE_OPERATOR_ROLES_NOTE: string; export declare const AZURE_RESULTS_NOTE: string; /** * P1 from the second acceptance round. Indexing keys on the timestamp parsed * out of the event, and the sample query asks for `now("-1h")` to `now()`, so * a sample line stamped with a fixed hour matches its own query only during * that hour. The line is therefore generated by the command, at the moment the * operator runs it. */ export declare const AZURE_SAMPLE_LOG_COMMAND = "printf '%s\\n' \"$(date -u +%Y-%m-%dT%H:%M:%SZ) ERROR checkout failed for order ORD-DEMO-1\" > ./test.log"; export declare const AZURE_EVENT_TIME_NOTE: string; /** * P7 from the second acceptance round. Every index run logs a 403 that reads * as a failure and is the expected state on this path. */ export declare const AZURE_FLAT_NAMESPACE_403_NOTE: string; /** * P6 from the second acceptance round. Storage account names live in one * global namespace, which neither the question nor its example said. */ export declare const AZURE_STORAGE_ACCOUNT_UNIQUE_NOTE: string; /** * P5 from the second acceptance round. `log10x_discover_env` probes kubectl * and AWS. On the machine the acceptance run used it enumerated an unrelated * AWS estate and stamped `estate=serverless` into a snapshot that then backed * an Azure plan. */ export declare const AZURE_SNAPSHOT_SCOPE_NOTE: string; export declare const AZURE_API_KEY_NOTE: string; /** * A licence the caller did not hand over is never written into an emitted * values file. The file stays on the operator's disk and the plan tells them * to keep it, so a key put there without being asked for is a key leaked into * a file nobody agreed to hold. */ export declare function licenseNotEmittedNote(storageProvider: RetrieverStorageProvider): string; /** Node-size refusals stop a first install dead, so the retry path is stated up front. */ export declare const AZURE_NODE_SIZE_NOTE: string; /** * Azure teardown. The resource group holds the storage account, the queues, * the managed identity, the Event Grid subscription and the AKS cluster, and * the script's `--destroy` deletes the group and everything in it. No * Terraform state exists on this path. */ export declare function buildAzureTeardownCommand(resourceGroup: string): string; /** * The query body the provisioning script prints in its own runbook. `name` * has to equal the first path segment of the uploaded blob, which the upload * step below makes `app`. */ export declare const AZURE_SAMPLE_QUERY_BODY = "{\"name\":\"app\",\"from\":\"now(\\\"-1h\\\")\",\"to\":\"now()\",\"search\":\"severity_level==\\\"ERROR\\\"\",\"writeResults\":true}"; /** * The provisioning commands, in the order a customer runs them: add the repo, * pull and untar the chart, then run the script from the untarred directory. * `helm repo add` on a repo that is already present skips without refreshing * the index, so `helm repo update` runs before the pull or `--version` can * miss a freshly published chart. * * The script is invoked through `bash`. `helm package` writes every file in a * chart tarball as mode 0644 whatever its mode in git, so the copy that comes * out of `helm pull --untar` carries no exec bit and a direct invocation is * refused with "permission denied". */ export declare function buildAzureProvisionCommands(opts: { resourceGroup: string; location: string; account: string; aksCluster: string; namespace: string; releaseName: string; valuesOut: string; }): string[]; export declare function buildRetrieverPlan(args: RetrieverAdviseArgs): Promise;