typekro 0.33.9 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/compositions/typekro-runtime/typekro-runtime.d.ts +0 -33
- package/dist/compositions/typekro-runtime/typekro-runtime.d.ts.map +1 -1
- package/dist/compositions/typekro-runtime/typekro-runtime.js +63 -1
- package/dist/compositions/typekro-runtime/typekro-runtime.js.map +1 -1
- package/dist/compositions/typekro-runtime/types.d.ts +8 -0
- package/dist/compositions/typekro-runtime/types.d.ts.map +1 -1
- package/dist/compositions/typekro-runtime/types.js +1 -0
- package/dist/compositions/typekro-runtime/types.js.map +1 -1
- package/dist/core/aspects/values-merge.d.ts +17 -0
- package/dist/core/aspects/values-merge.d.ts.map +1 -1
- package/dist/core/aspects/values-merge.js +67 -8
- package/dist/core/aspects/values-merge.js.map +1 -1
- package/dist/core/deployment/direct-factory.d.ts +9 -0
- package/dist/core/deployment/direct-factory.d.ts.map +1 -1
- package/dist/core/deployment/direct-factory.js +37 -3
- package/dist/core/deployment/direct-factory.js.map +1 -1
- package/dist/core/deployment/engine.d.ts +34 -0
- package/dist/core/deployment/engine.d.ts.map +1 -1
- package/dist/core/deployment/engine.js +173 -29
- package/dist/core/deployment/engine.js.map +1 -1
- package/dist/core/deployment/index.d.ts +2 -0
- package/dist/core/deployment/index.d.ts.map +1 -1
- package/dist/core/deployment/index.js +1 -0
- package/dist/core/deployment/index.js.map +1 -1
- package/dist/core/deployment/k8s-helpers.d.ts +73 -0
- package/dist/core/deployment/k8s-helpers.d.ts.map +1 -1
- package/dist/core/deployment/k8s-helpers.js +198 -4
- package/dist/core/deployment/k8s-helpers.js.map +1 -1
- package/dist/core/deployment/kro-factory.d.ts.map +1 -1
- package/dist/core/deployment/kro-factory.js +21 -1
- package/dist/core/deployment/kro-factory.js.map +1 -1
- package/dist/core/deployment/status-leaf-resolution.d.ts +101 -0
- package/dist/core/deployment/status-leaf-resolution.d.ts.map +1 -0
- package/dist/core/deployment/status-leaf-resolution.js +232 -0
- package/dist/core/deployment/status-leaf-resolution.js.map +1 -0
- package/dist/core/deployment/strategies/base-strategy.d.ts.map +1 -1
- package/dist/core/deployment/strategies/base-strategy.js +31 -3
- package/dist/core/deployment/strategies/base-strategy.js.map +1 -1
- package/dist/core/deployment/strategies/kro-strategy.d.ts.map +1 -1
- package/dist/core/deployment/strategies/kro-strategy.js +8 -1
- package/dist/core/deployment/strategies/kro-strategy.js.map +1 -1
- package/dist/core/expressions/composition/composition-analyzer-helpers.d.ts.map +1 -1
- package/dist/core/expressions/composition/composition-analyzer-helpers.js +20 -2
- package/dist/core/expressions/composition/composition-analyzer-helpers.js.map +1 -1
- package/dist/core/kro/index.d.ts +6 -0
- package/dist/core/kro/index.d.ts.map +1 -0
- package/dist/core/kro/index.js +6 -0
- package/dist/core/kro/index.js.map +1 -0
- package/dist/core/kro/label-guard-capability.d.ts +141 -0
- package/dist/core/kro/label-guard-capability.d.ts.map +1 -0
- package/dist/core/kro/label-guard-capability.js +257 -0
- package/dist/core/kro/label-guard-capability.js.map +1 -0
- package/dist/core/kro/labels.d.ts +56 -0
- package/dist/core/kro/labels.d.ts.map +1 -0
- package/dist/core/kro/labels.js +62 -0
- package/dist/core/kro/labels.js.map +1 -0
- package/dist/core/kubernetes/api-capability.d.ts +196 -0
- package/dist/core/kubernetes/api-capability.d.ts.map +1 -0
- package/dist/core/kubernetes/api-capability.js +301 -0
- package/dist/core/kubernetes/api-capability.js.map +1 -0
- package/dist/core/kubernetes/index.d.ts +2 -0
- package/dist/core/kubernetes/index.d.ts.map +1 -1
- package/dist/core/kubernetes/index.js +2 -0
- package/dist/core/kubernetes/index.js.map +1 -1
- package/dist/core/kubernetes/naming.d.ts +100 -0
- package/dist/core/kubernetes/naming.d.ts.map +1 -0
- package/dist/core/kubernetes/naming.js +93 -0
- package/dist/core/kubernetes/naming.js.map +1 -0
- package/dist/core/planning/direct-runtime-adapter.d.ts.map +1 -1
- package/dist/core/planning/direct-runtime-adapter.js +54 -17
- package/dist/core/planning/direct-runtime-adapter.js.map +1 -1
- package/dist/core/planning/planner.d.ts.map +1 -1
- package/dist/core/planning/planner.js +17 -0
- package/dist/core/planning/planner.js.map +1 -1
- package/dist/core/planning/schema.d.ts.map +1 -1
- package/dist/core/planning/schema.js +7 -3
- package/dist/core/planning/schema.js.map +1 -1
- package/dist/core/references/cel-lexical-scanner.d.ts +100 -1
- package/dist/core/references/cel-lexical-scanner.d.ts.map +1 -1
- package/dist/core/references/cel-lexical-scanner.js +196 -2
- package/dist/core/references/cel-lexical-scanner.js.map +1 -1
- package/dist/core/references/cel.d.ts +249 -1
- package/dist/core/references/cel.d.ts.map +1 -1
- package/dist/core/references/cel.js +289 -8
- package/dist/core/references/cel.js.map +1 -1
- package/dist/core/serialization/arktype-ast.d.ts +21 -0
- package/dist/core/serialization/arktype-ast.d.ts.map +1 -0
- package/dist/core/serialization/arktype-ast.js +29 -0
- package/dist/core/serialization/arktype-ast.js.map +1 -0
- package/dist/core/serialization/cel-references.d.ts +133 -32
- package/dist/core/serialization/cel-references.d.ts.map +1 -1
- package/dist/core/serialization/cel-references.js +908 -109
- package/dist/core/serialization/cel-references.js.map +1 -1
- package/dist/core/serialization/core.d.ts.map +1 -1
- package/dist/core/serialization/core.js +13 -2
- package/dist/core/serialization/core.js.map +1 -1
- package/dist/core/serialization/schema.d.ts +16 -2
- package/dist/core/serialization/schema.d.ts.map +1 -1
- package/dist/core/serialization/schema.js +113 -21
- package/dist/core/serialization/schema.js.map +1 -1
- package/dist/core/types/composable.d.ts +7 -1
- package/dist/core/types/composable.d.ts.map +1 -1
- package/dist/core/types/deployment.d.ts +32 -2
- package/dist/core/types/deployment.d.ts.map +1 -1
- package/dist/core/types/serialization.d.ts +37 -0
- package/dist/core/types/serialization.d.ts.map +1 -1
- package/dist/core/validation/cel-dialect.d.ts +246 -0
- package/dist/core/validation/cel-dialect.d.ts.map +1 -0
- package/dist/core/validation/cel-dialect.js +1997 -0
- package/dist/core/validation/cel-dialect.js.map +1 -0
- package/dist/core/validation/cel-validator.d.ts.map +1 -1
- package/dist/core/validation/cel-validator.js +8 -1
- package/dist/core/validation/cel-validator.js.map +1 -1
- package/dist/core/validation/literal-status.d.ts +107 -0
- package/dist/core/validation/literal-status.d.ts.map +1 -0
- package/dist/core/validation/literal-status.js +346 -0
- package/dist/core/validation/literal-status.js.map +1 -0
- package/dist/core/validation/structural-spec-dependence.d.ts +179 -0
- package/dist/core/validation/structural-spec-dependence.d.ts.map +1 -0
- package/dist/core/validation/structural-spec-dependence.js +911 -0
- package/dist/core/validation/structural-spec-dependence.js.map +1 -0
- package/dist/factories/apisix/compositions/apisix-bootstrap.d.ts.map +1 -1
- package/dist/factories/apisix/compositions/apisix-bootstrap.js +9 -0
- package/dist/factories/apisix/compositions/apisix-bootstrap.js.map +1 -1
- package/dist/factories/clickhouse/compositions/clickhouse-cluster.d.ts +6 -0
- package/dist/factories/clickhouse/compositions/clickhouse-cluster.d.ts.map +1 -1
- package/dist/factories/clickhouse/compositions/clickhouse-cluster.js +273 -23
- package/dist/factories/clickhouse/compositions/clickhouse-cluster.js.map +1 -1
- package/dist/factories/clickhouse/resources/index.d.ts +1 -0
- package/dist/factories/clickhouse/resources/index.d.ts.map +1 -1
- package/dist/factories/clickhouse/resources/index.js +1 -0
- package/dist/factories/clickhouse/resources/index.js.map +1 -1
- package/dist/factories/clickhouse/resources/installation.d.ts.map +1 -1
- package/dist/factories/clickhouse/resources/installation.js +31 -4
- package/dist/factories/clickhouse/resources/installation.js.map +1 -1
- package/dist/factories/clickhouse/resources/s3-backup.d.ts +215 -0
- package/dist/factories/clickhouse/resources/s3-backup.d.ts.map +1 -0
- package/dist/factories/clickhouse/resources/s3-backup.js +410 -0
- package/dist/factories/clickhouse/resources/s3-backup.js.map +1 -0
- package/dist/factories/clickhouse/types.d.ts +416 -20
- package/dist/factories/clickhouse/types.d.ts.map +1 -1
- package/dist/factories/clickhouse/types.js +235 -11
- package/dist/factories/clickhouse/types.js.map +1 -1
- package/dist/factories/clickhouse/utils/helm-values-mapper.d.ts +42 -0
- package/dist/factories/clickhouse/utils/helm-values-mapper.d.ts.map +1 -1
- package/dist/factories/clickhouse/utils/helm-values-mapper.js +48 -0
- package/dist/factories/clickhouse/utils/helm-values-mapper.js.map +1 -1
- package/dist/factories/clickhouse/utils/index.d.ts +2 -0
- package/dist/factories/clickhouse/utils/index.d.ts.map +1 -1
- package/dist/factories/clickhouse/utils/index.js +2 -0
- package/dist/factories/clickhouse/utils/index.js.map +1 -1
- package/dist/factories/clickhouse/utils/s3-storage.d.ts +503 -0
- package/dist/factories/clickhouse/utils/s3-storage.d.ts.map +1 -0
- package/dist/factories/clickhouse/utils/s3-storage.js +1139 -0
- package/dist/factories/clickhouse/utils/s3-storage.js.map +1 -0
- package/dist/factories/clickhouse/utils/validation.d.ts +103 -0
- package/dist/factories/clickhouse/utils/validation.d.ts.map +1 -1
- package/dist/factories/clickhouse/utils/validation.js +129 -0
- package/dist/factories/clickhouse/utils/validation.js.map +1 -1
- package/dist/factories/clickhouse/utils/xml.d.ts +87 -0
- package/dist/factories/clickhouse/utils/xml.d.ts.map +1 -0
- package/dist/factories/clickhouse/utils/xml.js +151 -0
- package/dist/factories/clickhouse/utils/xml.js.map +1 -0
- package/dist/factories/clickstack/compositions/clickstack-bootstrap.d.ts +57 -0
- package/dist/factories/clickstack/compositions/clickstack-bootstrap.d.ts.map +1 -1
- package/dist/factories/clickstack/compositions/clickstack-bootstrap.js +266 -7
- package/dist/factories/clickstack/compositions/clickstack-bootstrap.js.map +1 -1
- package/dist/factories/clickstack/types.d.ts +205 -26
- package/dist/factories/clickstack/types.d.ts.map +1 -1
- package/dist/factories/clickstack/types.js +106 -8
- package/dist/factories/clickstack/types.js.map +1 -1
- package/dist/factories/clickstack/utils/collector-config.d.ts +104 -0
- package/dist/factories/clickstack/utils/collector-config.d.ts.map +1 -0
- package/dist/factories/clickstack/utils/collector-config.js +266 -0
- package/dist/factories/clickstack/utils/collector-config.js.map +1 -0
- package/dist/factories/clickstack/utils/helm-values-mapper.d.ts +26 -0
- package/dist/factories/clickstack/utils/helm-values-mapper.d.ts.map +1 -1
- package/dist/factories/clickstack/utils/helm-values-mapper.js +53 -12
- package/dist/factories/clickstack/utils/helm-values-mapper.js.map +1 -1
- package/dist/factories/clickstack/utils/index.d.ts +2 -0
- package/dist/factories/clickstack/utils/index.d.ts.map +1 -1
- package/dist/factories/clickstack/utils/index.js +2 -0
- package/dist/factories/clickstack/utils/index.js.map +1 -1
- package/dist/factories/clickstack/utils/storage.d.ts +449 -0
- package/dist/factories/clickstack/utils/storage.d.ts.map +1 -0
- package/dist/factories/clickstack/utils/storage.js +698 -0
- package/dist/factories/clickstack/utils/storage.js.map +1 -0
- package/dist/factories/cnpg/resources/helm.d.ts.map +1 -1
- package/dist/factories/cnpg/resources/helm.js +4 -4
- package/dist/factories/cnpg/resources/helm.js.map +1 -1
- package/dist/factories/cnpg/types.d.ts +10 -1
- package/dist/factories/cnpg/types.d.ts.map +1 -1
- package/dist/factories/cnpg/types.js.map +1 -1
- package/dist/factories/cnpg/utils/helm-values-mapper.d.ts +19 -2
- package/dist/factories/cnpg/utils/helm-values-mapper.d.ts.map +1 -1
- package/dist/factories/cnpg/utils/helm-values-mapper.js +22 -4
- package/dist/factories/cnpg/utils/helm-values-mapper.js.map +1 -1
- package/dist/factories/envoy-ai-gateway/compositions/gateway.d.ts.map +1 -1
- package/dist/factories/envoy-ai-gateway/compositions/gateway.js +16 -3
- package/dist/factories/envoy-ai-gateway/compositions/gateway.js.map +1 -1
- package/dist/factories/envoy-ai-gateway/constants.d.ts +5 -2
- package/dist/factories/envoy-ai-gateway/constants.d.ts.map +1 -1
- package/dist/factories/envoy-ai-gateway/constants.js +5 -2
- package/dist/factories/envoy-ai-gateway/constants.js.map +1 -1
- package/dist/factories/envoy-ai-gateway/resources/gateway.d.ts +12 -0
- package/dist/factories/envoy-ai-gateway/resources/gateway.d.ts.map +1 -1
- package/dist/factories/envoy-ai-gateway/resources/gateway.js +27 -104
- package/dist/factories/envoy-ai-gateway/resources/gateway.js.map +1 -1
- package/dist/factories/envoy-ai-gateway/types.d.ts +15 -47
- package/dist/factories/envoy-ai-gateway/types.d.ts.map +1 -1
- package/dist/factories/envoy-ai-gateway/types.js.map +1 -1
- package/dist/factories/gateway-api/constants.d.ts +27 -0
- package/dist/factories/gateway-api/constants.d.ts.map +1 -0
- package/dist/factories/gateway-api/constants.js +27 -0
- package/dist/factories/gateway-api/constants.js.map +1 -0
- package/dist/factories/gateway-api/index.d.ts +14 -0
- package/dist/factories/gateway-api/index.d.ts.map +1 -0
- package/dist/factories/gateway-api/index.js +14 -0
- package/dist/factories/gateway-api/index.js.map +1 -0
- package/dist/factories/gateway-api/readiness.d.ts +67 -0
- package/dist/factories/gateway-api/readiness.d.ts.map +1 -0
- package/dist/factories/gateway-api/readiness.js +213 -0
- package/dist/factories/gateway-api/readiness.js.map +1 -0
- package/dist/factories/gateway-api/resources/gateway.d.ts +91 -0
- package/dist/factories/gateway-api/resources/gateway.d.ts.map +1 -0
- package/dist/factories/gateway-api/resources/gateway.js +99 -0
- package/dist/factories/gateway-api/resources/gateway.js.map +1 -0
- package/dist/factories/gateway-api/resources/index.d.ts +2 -0
- package/dist/factories/gateway-api/resources/index.d.ts.map +1 -0
- package/dist/factories/gateway-api/resources/index.js +2 -0
- package/dist/factories/gateway-api/resources/index.js.map +1 -0
- package/dist/factories/gateway-api/types.d.ts +1269 -0
- package/dist/factories/gateway-api/types.d.ts.map +1 -0
- package/dist/factories/gateway-api/types.js +417 -0
- package/dist/factories/gateway-api/types.js.map +1 -0
- package/dist/factories/helm/readiness-evaluators.d.ts +21 -3
- package/dist/factories/helm/readiness-evaluators.d.ts.map +1 -1
- package/dist/factories/helm/readiness-evaluators.js +117 -11
- package/dist/factories/helm/readiness-evaluators.js.map +1 -1
- package/dist/factories/helm/types.d.ts +28 -0
- package/dist/factories/helm/types.d.ts.map +1 -1
- package/dist/factories/index.d.ts +2 -0
- package/dist/factories/index.d.ts.map +1 -1
- package/dist/factories/index.js +8 -0
- package/dist/factories/index.js.map +1 -1
- package/dist/factories/inngest/compositions/inngest-bootstrap.d.ts.map +1 -1
- package/dist/factories/inngest/compositions/inngest-bootstrap.js +10 -0
- package/dist/factories/inngest/compositions/inngest-bootstrap.js.map +1 -1
- package/dist/factories/kubernetes/admission/index.d.ts +2 -0
- package/dist/factories/kubernetes/admission/index.d.ts.map +1 -1
- package/dist/factories/kubernetes/admission/index.js +2 -0
- package/dist/factories/kubernetes/admission/index.js.map +1 -1
- package/dist/factories/kubernetes/admission/label-propagation-guard.d.ts +108 -0
- package/dist/factories/kubernetes/admission/label-propagation-guard.d.ts.map +1 -0
- package/dist/factories/kubernetes/admission/label-propagation-guard.js +247 -0
- package/dist/factories/kubernetes/admission/label-propagation-guard.js.map +1 -0
- package/dist/factories/kubernetes/admission/mutating-admission-policy.d.ts +286 -0
- package/dist/factories/kubernetes/admission/mutating-admission-policy.d.ts.map +1 -0
- package/dist/factories/kubernetes/admission/mutating-admission-policy.js +157 -0
- package/dist/factories/kubernetes/admission/mutating-admission-policy.js.map +1 -0
- package/dist/factories/opensearch/compositions/cluster.d.ts.map +1 -1
- package/dist/factories/opensearch/compositions/cluster.js +6 -1
- package/dist/factories/opensearch/compositions/cluster.js.map +1 -1
- package/dist/factories/ory/compositions/ory-identity-stack.d.ts +8 -8
- package/dist/factories/ory/types.d.ts +16 -16
- package/dist/factories/rook/compositions/object-storage-claim.d.ts +1 -1
- package/dist/factories/rook/compositions/rook-ceph-platform.js +8 -1
- package/dist/factories/rook/compositions/rook-ceph-platform.js.map +1 -1
- package/dist/factories/rook/types.d.ts +1 -1
- package/dist/factories/searxng/compositions/searxng-bootstrap.d.ts +1 -1
- package/dist/factories/searxng/compositions/searxng-bootstrap.d.ts.map +1 -1
- package/dist/factories/searxng/compositions/searxng-bootstrap.js +18 -13
- package/dist/factories/searxng/compositions/searxng-bootstrap.js.map +1 -1
- package/dist/factories/searxng/index.d.ts +3 -0
- package/dist/factories/searxng/index.d.ts.map +1 -1
- package/dist/factories/searxng/index.js +3 -0
- package/dist/factories/searxng/index.js.map +1 -1
- package/dist/factories/searxng/types.js +1 -1
- package/dist/factories/searxng/types.js.map +1 -1
- package/dist/factories/traefik/compositions/index.d.ts +6 -0
- package/dist/factories/traefik/compositions/index.d.ts.map +1 -0
- package/dist/factories/traefik/compositions/index.js +6 -0
- package/dist/factories/traefik/compositions/index.js.map +1 -0
- package/dist/factories/traefik/compositions/traefik-bootstrap.d.ts +185 -0
- package/dist/factories/traefik/compositions/traefik-bootstrap.d.ts.map +1 -0
- package/dist/factories/traefik/compositions/traefik-bootstrap.js +339 -0
- package/dist/factories/traefik/compositions/traefik-bootstrap.js.map +1 -0
- package/dist/factories/traefik/compositions/traefik-helm-repository.d.ts +16 -0
- package/dist/factories/traefik/compositions/traefik-helm-repository.d.ts.map +1 -0
- package/dist/factories/traefik/compositions/traefik-helm-repository.js +31 -0
- package/dist/factories/traefik/compositions/traefik-helm-repository.js.map +1 -0
- package/dist/factories/traefik/constants.d.ts +78 -0
- package/dist/factories/traefik/constants.d.ts.map +1 -0
- package/dist/factories/traefik/constants.js +104 -0
- package/dist/factories/traefik/constants.js.map +1 -0
- package/dist/factories/traefik/index.d.ts +25 -0
- package/dist/factories/traefik/index.d.ts.map +1 -0
- package/dist/factories/traefik/index.js +25 -0
- package/dist/factories/traefik/index.js.map +1 -0
- package/dist/factories/traefik/resources/common.d.ts +68 -0
- package/dist/factories/traefik/resources/common.d.ts.map +1 -0
- package/dist/factories/traefik/resources/common.js +59 -0
- package/dist/factories/traefik/resources/common.js.map +1 -0
- package/dist/factories/traefik/resources/gateway.d.ts +85 -0
- package/dist/factories/traefik/resources/gateway.d.ts.map +1 -0
- package/dist/factories/traefik/resources/gateway.js +109 -0
- package/dist/factories/traefik/resources/gateway.js.map +1 -0
- package/dist/factories/traefik/resources/helm.d.ts +56 -0
- package/dist/factories/traefik/resources/helm.d.ts.map +1 -0
- package/dist/factories/traefik/resources/helm.js +131 -0
- package/dist/factories/traefik/resources/helm.js.map +1 -0
- package/dist/factories/traefik/resources/index.d.ts +10 -0
- package/dist/factories/traefik/resources/index.d.ts.map +1 -0
- package/dist/factories/traefik/resources/index.js +10 -0
- package/dist/factories/traefik/resources/index.js.map +1 -0
- package/dist/factories/traefik/resources/middleware.d.ts +169 -0
- package/dist/factories/traefik/resources/middleware.d.ts.map +1 -0
- package/dist/factories/traefik/resources/middleware.js +225 -0
- package/dist/factories/traefik/resources/middleware.js.map +1 -0
- package/dist/factories/traefik/resources/routing.d.ts +113 -0
- package/dist/factories/traefik/resources/routing.d.ts.map +1 -0
- package/dist/factories/traefik/resources/routing.js +119 -0
- package/dist/factories/traefik/resources/routing.js.map +1 -0
- package/dist/factories/traefik/resources/tls.d.ts +85 -0
- package/dist/factories/traefik/resources/tls.d.ts.map +1 -0
- package/dist/factories/traefik/resources/tls.js +93 -0
- package/dist/factories/traefik/resources/tls.js.map +1 -0
- package/dist/factories/traefik/types.d.ts +2690 -0
- package/dist/factories/traefik/types.d.ts.map +1 -0
- package/dist/factories/traefik/types.js +1084 -0
- package/dist/factories/traefik/types.js.map +1 -0
- package/dist/factories/traefik/utils/helm-values-mapper.d.ts +198 -0
- package/dist/factories/traefik/utils/helm-values-mapper.d.ts.map +1 -0
- package/dist/factories/traefik/utils/helm-values-mapper.js +372 -0
- package/dist/factories/traefik/utils/helm-values-mapper.js.map +1 -0
- package/dist/factories/traefik/utils/index.d.ts +6 -0
- package/dist/factories/traefik/utils/index.d.ts.map +1 -0
- package/dist/factories/traefik/utils/index.js +6 -0
- package/dist/factories/traefik/utils/index.js.map +1 -0
- package/dist/factories/traefik/utils/middleware-validation.d.ts +42 -0
- package/dist/factories/traefik/utils/middleware-validation.d.ts.map +1 -0
- package/dist/factories/traefik/utils/middleware-validation.js +78 -0
- package/dist/factories/traefik/utils/middleware-validation.js.map +1 -0
- package/dist/factories/webapp/compositions/web-app-with-processing.d.ts.map +1 -1
- package/dist/factories/webapp/compositions/web-app-with-processing.js +10 -0
- package/dist/factories/webapp/compositions/web-app-with-processing.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/package.json +9 -1
|
@@ -0,0 +1,698 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClickStack storage consumption: TTL retention and the collector's
|
|
3
|
+
* persistent sending queue.
|
|
4
|
+
*
|
|
5
|
+
* The storage POLICY needs nothing here. The `clickhouse` factory sets
|
|
6
|
+
* `merge_tree/storage_policy` as the server default, so the gateway
|
|
7
|
+
* collector's goose migrations create `otel_logs` / `otel_traces` /
|
|
8
|
+
* `otel_metrics_*` / `hyperdx_sessions` on the S3 policy with no
|
|
9
|
+
* `SETTINGS storage_policy` clause and no per-table DDL from TypeKro. This
|
|
10
|
+
* module covers the two things a server default cannot express:
|
|
11
|
+
*
|
|
12
|
+
* 1. **Retention** — `TTL toDateTime(<timestamp>) + INTERVAL n UNIT DELETE`,
|
|
13
|
+
* applied by an idempotent CronJob because the tables do not exist until the
|
|
14
|
+
* collector has migrated, and because TypeKro does not own their DDL.
|
|
15
|
+
* LIVE-VERIFIED: the collector's own migration already sets a 30-day TTL
|
|
16
|
+
* (`toDateTime(Timestamp) + toIntervalDay(30)` with `ttl_only_drop_parts`),
|
|
17
|
+
* so `retention` OVERRIDES that default rather than establishing the first
|
|
18
|
+
* one — which is exactly why the idempotence probe compares the COMPLETE
|
|
19
|
+
* TTL clause rather than merely asking whether a TTL exists.
|
|
20
|
+
* 2. **Persistent queue** — a `file_storage`-backed exporter queue so a
|
|
21
|
+
* ClickHouse restart (which is exactly what an S3-backed node rebuild
|
|
22
|
+
* causes) does not drop in-flight telemetry. Its directory is backed by a
|
|
23
|
+
* STANDALONE PersistentVolumeClaim owned by the composition: an `emptyDir`
|
|
24
|
+
* or a generic ephemeral volume is deleted with the collector Pod, so
|
|
25
|
+
* neither survives the collector restart the queue exists to survive.
|
|
26
|
+
*
|
|
27
|
+
* S3_PLAIN_REWRITABLE NOTE: retention and that disk type are MUTUALLY
|
|
28
|
+
* EXCLUSIVE, and `resolveClickStackStorage` rejects the combination.
|
|
29
|
+
* `MODIFY TTL` normally schedules a materialization MUTATION, which
|
|
30
|
+
* plain_rewritable does not support — every statement this module emits
|
|
31
|
+
* therefore carries `SETTINGS materialize_ttl_after_modify = 0` so expiry
|
|
32
|
+
* happens during merges instead. LIVE-VERIFIED (ClickHouse 25.7) that this is
|
|
33
|
+
* not enough: the immutable metadata type refuses the metadata ALTER itself
|
|
34
|
+
* ("ALTER TABLE commands are not supported on immutable disk", code 344), and
|
|
35
|
+
* the identical statement succeeds against a table on the server's local
|
|
36
|
+
* policy. The setting is kept for the `diskType: 's3'` path, where the
|
|
37
|
+
* materialization pass is the only thing worth skipping.
|
|
38
|
+
*/
|
|
39
|
+
import { assertSafeCollectorConfigKey } from './collector-config.js';
|
|
40
|
+
/** Default cron schedule for the retention DDL CronJob. */
|
|
41
|
+
export const DEFAULT_RETENTION_SCHEDULE = '17 * * * *';
|
|
42
|
+
/**
|
|
43
|
+
* Default image for the retention DDL CronJob. The ClickStack chart vendors
|
|
44
|
+
* ClickHouse 25.7, so the matching server image supplies a compatible
|
|
45
|
+
* `clickhouse-client`.
|
|
46
|
+
*/
|
|
47
|
+
export const DEFAULT_RETENTION_IMAGE = 'clickhouse/clickhouse-server:25.7';
|
|
48
|
+
/** Default persistent-queue directory inside the collector pod. */
|
|
49
|
+
export const DEFAULT_QUEUE_DIRECTORY = '/var/lib/otelcol/file_storage';
|
|
50
|
+
/** Default `file_storage` extension instance name. */
|
|
51
|
+
export const QUEUE_EXTENSION_NAME = 'file_storage/hyperdx';
|
|
52
|
+
/**
|
|
53
|
+
* Default exporters whose `sending_queue` is switched to file storage.
|
|
54
|
+
*
|
|
55
|
+
* The ClickStack collector defines a single ClickHouse exporter, `clickhouse`,
|
|
56
|
+
* and all three signal pipelines export through it. A name that is NOT one the
|
|
57
|
+
* agent defines fails silently: the supervisor merges the overlay, the
|
|
58
|
+
* `exporters` map simply grows an exporter no pipeline uses, and the real one
|
|
59
|
+
* keeps its in-memory queue. That is why the integration suite asserts these
|
|
60
|
+
* names against the agent's own EFFECTIVE configuration instead of trusting
|
|
61
|
+
* the default.
|
|
62
|
+
*/
|
|
63
|
+
export const DEFAULT_QUEUE_EXPORTER_NAMES = ['clickhouse'];
|
|
64
|
+
/**
|
|
65
|
+
* Default `service.extensions` list emitted with the queue overlay.
|
|
66
|
+
*
|
|
67
|
+
* A YAML list in `global.otelCollector.customConfig` REPLACES the supervisor's
|
|
68
|
+
* own list, so this must name every extension the collector needs — see the
|
|
69
|
+
* warning on {@link ClickStackPersistentQueueOptions}.
|
|
70
|
+
*/
|
|
71
|
+
export const DEFAULT_QUEUE_EXTENSIONS = ['health_check', QUEUE_EXTENSION_NAME];
|
|
72
|
+
/** Volume name used for the persistent-queue directory. */
|
|
73
|
+
export const QUEUE_VOLUME_NAME = 'otel-file-storage';
|
|
74
|
+
/**
|
|
75
|
+
* Deployment update strategy forced on the gateway whenever the queue is on.
|
|
76
|
+
*
|
|
77
|
+
* The collector chart's `rollout.strategy` (default `RollingUpdate`) becomes
|
|
78
|
+
* the Deployment's `spec.strategy.type` verbatim. `Recreate` is the only value
|
|
79
|
+
* under which a rollout terminates the old collector BEFORE creating its
|
|
80
|
+
* replacement, which is what a single-writer queue on a ReadWriteOnce claim
|
|
81
|
+
* requires — see {@link renderPersistentQueueValues} for why the replica pin
|
|
82
|
+
* does not cover this on its own.
|
|
83
|
+
*/
|
|
84
|
+
export const QUEUE_ROLLOUT_STRATEGY = 'Recreate';
|
|
85
|
+
/**
|
|
86
|
+
* The gateway subchart's OWN `extraVolumes` entry, which we must re-emit.
|
|
87
|
+
*
|
|
88
|
+
* Helm REPLACES a list-valued override rather than appending to it, and the
|
|
89
|
+
* chart mounts the ConfigMap rendered from `global.otelCollector.customConfig`
|
|
90
|
+
* through exactly these two lists. Chart 3.2.0's `values.yaml` says so in a
|
|
91
|
+
* comment on the defaults:
|
|
92
|
+
*
|
|
93
|
+
* "NOTE: if you override extraVolumes/extraVolumeMounts yourself, Helm
|
|
94
|
+
* replaces these lists entirely -- re-include the entries below to keep
|
|
95
|
+
* global.otelCollector.customConfig working."
|
|
96
|
+
*
|
|
97
|
+
* LIVE-VERIFIED what happens when you don't: the queue volume alone evicts the
|
|
98
|
+
* custom-config mount, the OpAMP supervisor logs `Could not read local config
|
|
99
|
+
* file: open /etc/otelcol-contrib/custom/custom.config.yaml: no such file or
|
|
100
|
+
* directory` on every poll, never composes a merged agent config, and the
|
|
101
|
+
* collector never starts its OTLP receivers — while the Pod still reports
|
|
102
|
+
* Ready, because readiness comes from the SUPERVISOR's health_check and not
|
|
103
|
+
* from the agent. Enabling the persistent queue would silently take the whole
|
|
104
|
+
* gateway down.
|
|
105
|
+
*/
|
|
106
|
+
export const CHART_CUSTOM_CONFIG_VOLUME_NAME = 'custom-config';
|
|
107
|
+
/** ConfigMap the chart renders `global.otelCollector.customConfig` into. */
|
|
108
|
+
export const CHART_CUSTOM_CONFIG_CONFIG_MAP_NAME = 'clickstack-otel-custom-config';
|
|
109
|
+
/** Directory the chart mounts {@link CHART_CUSTOM_CONFIG_CONFIG_MAP_NAME} at. */
|
|
110
|
+
export const CHART_CUSTOM_CONFIG_MOUNT_PATH = '/etc/otelcol-contrib/custom';
|
|
111
|
+
/** Default size of the persistent-queue PersistentVolumeClaim. */
|
|
112
|
+
export const DEFAULT_QUEUE_SIZE = '10Gi';
|
|
113
|
+
/**
|
|
114
|
+
* Access modes of the persistent-queue PersistentVolumeClaim — not an option.
|
|
115
|
+
*
|
|
116
|
+
* `ReadWriteMany` used to be selectable, on the theory that a shared volume
|
|
117
|
+
* would let several collector replicas run off one queue directory. It does
|
|
118
|
+
* not, and the volume was never the binding constraint: the OTel `file_storage`
|
|
119
|
+
* extension stores the queue in a bbolt database, and bbolt takes an EXCLUSIVE
|
|
120
|
+
* FILE LOCK on open (the extension's own README says a single collector
|
|
121
|
+
* instance per directory; collector-contrib issue #5894 is the second instance
|
|
122
|
+
* hanging on that lock). Two replicas pointed at one directory therefore either
|
|
123
|
+
* block forever or, if the lock is lost across a node boundary the way a
|
|
124
|
+
* network filesystem can lose it, corrupt the database. Offering RWX advertised
|
|
125
|
+
* a multi-replica queue that cannot exist, so the knob is gone and the claim is
|
|
126
|
+
* always `ReadWriteOnce`.
|
|
127
|
+
*/
|
|
128
|
+
export const QUEUE_ACCESS_MODES = ['ReadWriteOnce'];
|
|
129
|
+
/** Name suffix of the queue PersistentVolumeClaim (and its resource id). */
|
|
130
|
+
export const QUEUE_CLAIM_NAME_SUFFIX = '-otel-queue';
|
|
131
|
+
/**
|
|
132
|
+
* Name of the queue PersistentVolumeClaim for a release.
|
|
133
|
+
*
|
|
134
|
+
* Shared by the composition (which CREATES the claim) and the values mapper
|
|
135
|
+
* (which MOUNTS it by `claimName`), so the two cannot drift. Accepts a schema
|
|
136
|
+
* reference for `name` the same way every other name in this family does — the
|
|
137
|
+
* template literal serializes to CEL in KRO mode.
|
|
138
|
+
*
|
|
139
|
+
* @param releaseName - Helm release name (`spec.name`)
|
|
140
|
+
* @returns The claim name
|
|
141
|
+
*/
|
|
142
|
+
export function clickStackQueueClaimName(releaseName) {
|
|
143
|
+
return `${releaseName}${QUEUE_CLAIM_NAME_SUFFIX}`;
|
|
144
|
+
}
|
|
145
|
+
/** ConfigMap the ClickStack chart renders the shared non-secret env into. */
|
|
146
|
+
export const CLICKSTACK_CONFIG_MAP_NAME = 'clickstack-config';
|
|
147
|
+
/** Secret the ClickStack chart renders the shared secret env into. */
|
|
148
|
+
export const CLICKSTACK_SECRET_NAME = 'clickstack-secret';
|
|
149
|
+
/**
|
|
150
|
+
* Tables per signal, with the timestamp column each one's TTL keys off.
|
|
151
|
+
*
|
|
152
|
+
* Columns mirror the `defaultSources` the values mapper emits (which mirror
|
|
153
|
+
* the chart's own defaults), so they track the schema HyperDX queries:
|
|
154
|
+
* `Timestamp` for logs/traces, `TimeUnix` for metrics, `TimestampTime` for
|
|
155
|
+
* sessions.
|
|
156
|
+
*/
|
|
157
|
+
export const CLICKSTACK_RETENTION_TABLES = {
|
|
158
|
+
logs: [
|
|
159
|
+
{ table: 'otel_logs', column: 'Timestamp' },
|
|
160
|
+
// A session is a log-kind table in HyperDX's own source definitions, so it
|
|
161
|
+
// follows the logs retention rather than getting its own knob.
|
|
162
|
+
{ table: 'hyperdx_sessions', column: 'TimestampTime' },
|
|
163
|
+
],
|
|
164
|
+
traces: [{ table: 'otel_traces', column: 'Timestamp' }],
|
|
165
|
+
metrics: [
|
|
166
|
+
{ table: 'otel_metrics_gauge', column: 'TimeUnix' },
|
|
167
|
+
{ table: 'otel_metrics_sum', column: 'TimeUnix' },
|
|
168
|
+
{ table: 'otel_metrics_histogram', column: 'TimeUnix' },
|
|
169
|
+
],
|
|
170
|
+
};
|
|
171
|
+
const RETENTION_UNITS = {
|
|
172
|
+
m: 'MINUTE',
|
|
173
|
+
h: 'HOUR',
|
|
174
|
+
d: 'DAY',
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* Parse a retention duration string into a ClickHouse `INTERVAL`.
|
|
178
|
+
*
|
|
179
|
+
* @param context - Entry point name for the error message
|
|
180
|
+
* @param field - Offending field path (e.g. `storage.retention.logs`)
|
|
181
|
+
* @param value - Duration string such as `'30d'`, `'720h'`, or `'90m'`
|
|
182
|
+
* @returns The parsed amount and `INTERVAL` unit
|
|
183
|
+
* @throws Error when the duration cannot be parsed or is not positive
|
|
184
|
+
*/
|
|
185
|
+
export function parseRetentionDuration(context, field, value) {
|
|
186
|
+
const match = /^([0-9]+)\s*(m|h|d)$/.exec(value.trim());
|
|
187
|
+
const amount = match?.[1];
|
|
188
|
+
const suffix = match?.[2];
|
|
189
|
+
if (amount === undefined || suffix === undefined) {
|
|
190
|
+
throw new Error(`${context}: '${field}' must be a retention duration of minutes, hours or days ` +
|
|
191
|
+
`(e.g. '30d', '720h', '90m') — got ${JSON.stringify(value)}.`);
|
|
192
|
+
}
|
|
193
|
+
const parsed = Number(amount);
|
|
194
|
+
if (parsed < 1) {
|
|
195
|
+
throw new Error(`${context}: '${field}' must be at least 1 — got ${JSON.stringify(value)}.`);
|
|
196
|
+
}
|
|
197
|
+
const unit = RETENTION_UNITS[suffix];
|
|
198
|
+
if (unit === undefined) {
|
|
199
|
+
throw new Error(`${context}: '${field}' has an unsupported unit ${JSON.stringify(suffix)}.`);
|
|
200
|
+
}
|
|
201
|
+
return { amount: parsed, unit };
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Collapse a TTL clause read back from ClickHouse into its comparable form.
|
|
205
|
+
*
|
|
206
|
+
* The server's own rendering is already canonical apart from whitespace, so
|
|
207
|
+
* this only collapses runs of blanks and trims — enough to compare clauses
|
|
208
|
+
* across formatting differences without pretending to normalize SQL.
|
|
209
|
+
*
|
|
210
|
+
* @param rendered - A TTL clause as extracted from `engine_full`
|
|
211
|
+
* @returns The clause with whitespace runs collapsed to single spaces
|
|
212
|
+
*/
|
|
213
|
+
export function normalizeRenderedTtl(rendered) {
|
|
214
|
+
return rendered.replace(/\s+/g, ' ').trim();
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Whether a TTL clause read back from a live table already expresses the
|
|
218
|
+
* intended retention.
|
|
219
|
+
*
|
|
220
|
+
* This is the exact predicate the rendered CronJob script implements in shell
|
|
221
|
+
* (an equality test against {@link ResolvedRetentionEntry.ttlRenderings}); it
|
|
222
|
+
* exists as a function so the comparison semantics — in particular the
|
|
223
|
+
* near-miss cases a substring probe gets wrong — are directly testable.
|
|
224
|
+
*
|
|
225
|
+
* @param currentClause - TTL clause extracted from `system.tables.engine_full`
|
|
226
|
+
* @param entry - The resolved retention entry being converged
|
|
227
|
+
* @returns True when no `MODIFY TTL` is needed
|
|
228
|
+
*/
|
|
229
|
+
export function ttlAlreadyApplied(currentClause, entry) {
|
|
230
|
+
const normalized = normalizeRenderedTtl(currentClause);
|
|
231
|
+
return entry.ttlRenderings.includes(normalized);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Reject a collector component name that JavaScript's object model claims.
|
|
235
|
+
*
|
|
236
|
+
* Every name in `exporterNames` and `extensions` ends up as a MAPPING KEY in
|
|
237
|
+
* the rendered overlay, so `__proto__`, `constructor` and `prototype` are
|
|
238
|
+
* refused before they get there — see {@link assertSafeCollectorConfigKey} for
|
|
239
|
+
* the two silent failure modes. The error names the caller's own option path
|
|
240
|
+
* and the offending index.
|
|
241
|
+
*
|
|
242
|
+
* @param context - Entry point name for the error message
|
|
243
|
+
* @param field - The offending option, relative to `storage.persistentQueue`
|
|
244
|
+
* @param names - The supplied component names
|
|
245
|
+
* @throws Error when any name is an object-model member
|
|
246
|
+
*/
|
|
247
|
+
function assertQueueComponentNames(context, field, names) {
|
|
248
|
+
names.forEach((name, index) => {
|
|
249
|
+
try {
|
|
250
|
+
assertSafeCollectorConfigKey(name);
|
|
251
|
+
}
|
|
252
|
+
catch (cause) {
|
|
253
|
+
throw new Error(`${context}: 'storage.persistentQueue.${field}[${index}]' is ` +
|
|
254
|
+
`${JSON.stringify(name)}, which cannot name a collector component. ` +
|
|
255
|
+
`${cause instanceof Error ? cause.message : String(cause)}`);
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Resolve and validate the build-time storage options.
|
|
261
|
+
*
|
|
262
|
+
* @param context - Entry point name for every error message
|
|
263
|
+
* @param options - Build-time storage options (omit for the PVC default)
|
|
264
|
+
* @returns The resolved options, with retention expanded per table
|
|
265
|
+
* @throws Error when a retention duration is unparseable, when an
|
|
266
|
+
* S3-specific option is set on the PVC default, or when a queue component
|
|
267
|
+
* name is an object-model member (see {@link assertQueueComponentNames})
|
|
268
|
+
*/
|
|
269
|
+
export function resolveClickStackStorage(context, options) {
|
|
270
|
+
const mode = options?.mode ?? 'pvc';
|
|
271
|
+
if (mode === 'pvc' && (options?.diskType !== undefined || options?.policyName !== undefined)) {
|
|
272
|
+
throw new Error(`${context}: storage mode 'pvc' (the default) rejects 'storage.diskType' and ` +
|
|
273
|
+
`'storage.policyName' — they describe an object-storage-backed ClickHouse. Set ` +
|
|
274
|
+
`storage.mode: 's3' to declare one.`);
|
|
275
|
+
}
|
|
276
|
+
// LIVE FINDING (ClickHouse 25.7, kind + MinIO): a table on an
|
|
277
|
+
// `s3_plain_rewritable` policy rejects the retention DDL outright —
|
|
278
|
+
//
|
|
279
|
+
// Code: 344. DB::Exception: ALTER TABLE commands are not supported on
|
|
280
|
+
// immutable disk 's3', except for setting and comment alteration.
|
|
281
|
+
// (SUPPORT_IS_DISABLED)
|
|
282
|
+
//
|
|
283
|
+
// `SETTINGS materialize_ttl_after_modify = 0` does not help: it only skips
|
|
284
|
+
// the materialization MUTATION, and it is the metadata ALTER itself that the
|
|
285
|
+
// immutable metadata type refuses. The same statement against a table on the
|
|
286
|
+
// server's local policy succeeds, so this is specific to the disk type and
|
|
287
|
+
// not to the statement. Rendering the CronJob anyway would ship a job that
|
|
288
|
+
// CrashLoops forever while reporting a retention policy that is never
|
|
289
|
+
// applied, so the combination is rejected here instead.
|
|
290
|
+
if (options?.diskType === 's3_plain_rewritable' && options?.retention !== undefined) {
|
|
291
|
+
throw new Error(`${context}: 'storage.retention' cannot be applied to a ClickHouse whose ` +
|
|
292
|
+
`'storage.diskType' is 's3_plain_rewritable'. Retention converges through ` +
|
|
293
|
+
`\`ALTER TABLE … MODIFY TTL\`, and ClickHouse refuses every ALTER except settings and ` +
|
|
294
|
+
`comments on that immutable metadata type ("ALTER TABLE commands are not supported on ` +
|
|
295
|
+
`immutable disk", SUPPORT_IS_DISABLED) — so the CronJob would fail on every run while ` +
|
|
296
|
+
`reporting a retention policy that never takes effect. Use diskType: 's3' (with ` +
|
|
297
|
+
`storage.backup on the ClickHouse side) if you need TypeKro-managed TTL, or drop ` +
|
|
298
|
+
`'storage.retention' and keep the TTL the collector's own migrations create.`);
|
|
299
|
+
}
|
|
300
|
+
const retentionEntries = [];
|
|
301
|
+
for (const signal of ['logs', 'traces', 'metrics']) {
|
|
302
|
+
const duration = options?.retention?.[signal];
|
|
303
|
+
if (duration === undefined)
|
|
304
|
+
continue;
|
|
305
|
+
const { amount, unit } = parseRetentionDuration(context, `storage.retention.${signal}`, duration);
|
|
306
|
+
for (const target of CLICKSTACK_RETENTION_TABLES[signal]) {
|
|
307
|
+
retentionEntries.push({
|
|
308
|
+
...target,
|
|
309
|
+
signal,
|
|
310
|
+
duration,
|
|
311
|
+
// `toDateTime(...)` wraps the column deliberately: the collector's own
|
|
312
|
+
// migration renders its TTL as `toDateTime(Timestamp) + toIntervalDay(30)`
|
|
313
|
+
// (LIVE-VERIFIED against chart 3.2.0), and the timestamp columns are
|
|
314
|
+
// DateTime64. Emitting the same form keeps the stored expression — and
|
|
315
|
+
// therefore the idempotence probe below — directly comparable.
|
|
316
|
+
ttlExpression: `toDateTime(${target.column}) + INTERVAL ${amount} ${unit} DELETE`,
|
|
317
|
+
ttlRenderings: [
|
|
318
|
+
// Normalized AST rendering — exactly what ClickHouse stores and what
|
|
319
|
+
// `engine_full` / `create_table_query` return. The default `DELETE`
|
|
320
|
+
// action is not part of the rendered clause.
|
|
321
|
+
`toDateTime(${target.column}) + toInterval${unit.charAt(0)}${unit
|
|
322
|
+
.slice(1)
|
|
323
|
+
.toLowerCase()}(${amount})`,
|
|
324
|
+
// Source spelling, in case a release renders the clause verbatim.
|
|
325
|
+
`toDateTime(${target.column}) + INTERVAL ${amount} ${unit}`,
|
|
326
|
+
],
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
const queue = options?.persistentQueue;
|
|
331
|
+
const exporterNames = queue?.exporterNames ?? DEFAULT_QUEUE_EXPORTER_NAMES;
|
|
332
|
+
if (queue?.enabled === true && exporterNames.length === 0) {
|
|
333
|
+
throw new Error(`${context}: 'storage.persistentQueue.exporterNames' cannot be empty — the queue exists ` +
|
|
334
|
+
`to back an exporter's \`sending_queue\`, and an empty list would render a ` +
|
|
335
|
+
`\`file_storage\` extension that nothing sends through. Omit the option to use ` +
|
|
336
|
+
`${JSON.stringify(DEFAULT_QUEUE_EXPORTER_NAMES)}.`);
|
|
337
|
+
}
|
|
338
|
+
const queueExtensions = queue?.extensions ?? DEFAULT_QUEUE_EXTENSIONS;
|
|
339
|
+
if (queue?.enabled === true && !queueExtensions.includes(QUEUE_EXTENSION_NAME)) {
|
|
340
|
+
throw new Error(`${context}: 'storage.persistentQueue.extensions' must include ` +
|
|
341
|
+
`'${QUEUE_EXTENSION_NAME}' — the list REPLACES the supervisor's own ` +
|
|
342
|
+
`\`service.extensions\`, so leaving it out means the file_storage extension the ` +
|
|
343
|
+
`exporters reference is never started and the collector refuses the config. Got ` +
|
|
344
|
+
`${JSON.stringify([...queueExtensions])}.`);
|
|
345
|
+
}
|
|
346
|
+
if (queue?.enabled === true) {
|
|
347
|
+
// BOTH lists carry COMPONENT NAMES, and a component name becomes a mapping
|
|
348
|
+
// key in the rendered overlay — `exporters.<name>` directly, and an
|
|
349
|
+
// extension instance name under `extensions.<name>`. JavaScript reserves a
|
|
350
|
+
// few of those, and the failure was silent in both directions: a
|
|
351
|
+
// `__proto__` exporter name rendered as `exporters: {}` (the overlay clone
|
|
352
|
+
// re-parented the copy instead of copying the key) while the merge's
|
|
353
|
+
// `key in target` test could hand `Object.prototype` to the deep merge and
|
|
354
|
+
// mutate it process-wide. Rejected
|
|
355
|
+
// HERE, at the option that supplied the name, so the message names the
|
|
356
|
+
// caller's own path rather than a position inside a fragment. The merge
|
|
357
|
+
// itself re-checks every key independently — see
|
|
358
|
+
// {@link assertSafeCollectorConfigKey}.
|
|
359
|
+
assertQueueComponentNames(context, 'exporterNames', exporterNames);
|
|
360
|
+
assertQueueComponentNames(context, 'extensions', queueExtensions);
|
|
361
|
+
}
|
|
362
|
+
return {
|
|
363
|
+
mode,
|
|
364
|
+
...(options?.diskType !== undefined && { diskType: options.diskType }),
|
|
365
|
+
...(options?.policyName !== undefined && { policyName: options.policyName }),
|
|
366
|
+
...(options?.retention !== undefined && { retention: options.retention }),
|
|
367
|
+
retentionEntries,
|
|
368
|
+
retentionSchedule: options?.retentionSchedule ?? DEFAULT_RETENTION_SCHEDULE,
|
|
369
|
+
retentionImage: options?.retentionImage ?? DEFAULT_RETENTION_IMAGE,
|
|
370
|
+
...(queue?.enabled === true && {
|
|
371
|
+
persistentQueue: {
|
|
372
|
+
directory: queue.directory ?? DEFAULT_QUEUE_DIRECTORY,
|
|
373
|
+
// Always a real claim size: the ephemeral fallback is gone on purpose
|
|
374
|
+
// (see ClickStackPersistentQueueOptions.size).
|
|
375
|
+
size: queue.size ?? DEFAULT_QUEUE_SIZE,
|
|
376
|
+
...(queue.storageClassName !== undefined && {
|
|
377
|
+
storageClassName: queue.storageClassName,
|
|
378
|
+
}),
|
|
379
|
+
accessModes: [...QUEUE_ACCESS_MODES],
|
|
380
|
+
exporterNames,
|
|
381
|
+
extensions: queueExtensions,
|
|
382
|
+
},
|
|
383
|
+
}),
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Reject more than one gateway collector replica alongside a persistent queue.
|
|
388
|
+
*
|
|
389
|
+
* UNCONDITIONAL: `persistentQueue` means exactly one collector replica, and no
|
|
390
|
+
* volume choice changes that. The `file_storage` extension keeps the queue in a
|
|
391
|
+
* bbolt database, and bbolt takes an EXCLUSIVE FILE LOCK for the lifetime of
|
|
392
|
+
* the handle — the extension's README is explicit that one directory serves one
|
|
393
|
+
* collector instance, and collector-contrib issue #5894 is the report of the
|
|
394
|
+
* second instance hanging on that lock. So a second replica either blocks
|
|
395
|
+
* forever on `Open` or, where the lock does not hold across a node boundary,
|
|
396
|
+
* writes the same pages as the first.
|
|
397
|
+
*
|
|
398
|
+
* The claim's `ReadWriteOnce` mode is a second, weaker line of defence (extra
|
|
399
|
+
* Pods on other nodes stay `Pending` on `Multi-Attach`), not the reason.
|
|
400
|
+
* `ReadWriteMany` was previously accepted as a way to lift this guard; it is
|
|
401
|
+
* gone, because a shared filesystem hands both replicas the same locked
|
|
402
|
+
* database rather than giving each its own.
|
|
403
|
+
*
|
|
404
|
+
* PER-REPLICA STORAGE IS THE REAL ALTERNATIVE, and it is not modelled here:
|
|
405
|
+
* it needs the upstream chart's `mode: statefulset` with `volumeClaimTemplates`
|
|
406
|
+
* so every replica gets its OWN queue directory. This composition renders the
|
|
407
|
+
* gateway as the chart's default Deployment and mounts one standalone claim, so
|
|
408
|
+
* the error names that path as future work rather than pretending it exists.
|
|
409
|
+
*
|
|
410
|
+
* @param context - Entry point name for the error message
|
|
411
|
+
* @param resolved - Resolved storage options
|
|
412
|
+
* @param replicaCount - Collector replica count from the build-time chart
|
|
413
|
+
* values, when one was set
|
|
414
|
+
* @throws Error when a persistent queue is requested with more than one replica
|
|
415
|
+
*/
|
|
416
|
+
export function assertQueueReplicaCompatible(context, resolved, replicaCount) {
|
|
417
|
+
if (resolved.persistentQueue === undefined)
|
|
418
|
+
return;
|
|
419
|
+
if (typeof replicaCount !== 'number' || replicaCount <= 1)
|
|
420
|
+
return;
|
|
421
|
+
throw new Error(`${context}: 'storage.persistentQueue' requires exactly ONE gateway collector replica — ` +
|
|
422
|
+
`got values['otel-collector'].replicaCount = ${replicaCount}. The queue is a bbolt ` +
|
|
423
|
+
`database owned by the OTel 'file_storage' extension, and bbolt holds an exclusive file ` +
|
|
424
|
+
`lock on it: a second collector opening the same database blocks on that lock ` +
|
|
425
|
+
`(opentelemetry-collector-contrib issue #5894, and the filestorage README's "only one ` +
|
|
426
|
+
`collector instance per directory"), and loses the queue's integrity if the lock is not ` +
|
|
427
|
+
`honoured across nodes. A shared ReadWriteMany volume does NOT help — it hands both ` +
|
|
428
|
+
`replicas the same locked database. Drop to one replica. Giving every replica its own ` +
|
|
429
|
+
`queue would need the chart's 'mode: statefulset' with volumeClaimTemplates, which this ` +
|
|
430
|
+
`composition does not model today.`);
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Render the idempotent retention DDL script.
|
|
434
|
+
*
|
|
435
|
+
* IDEMPOTENCE, and why this is a CronJob rather than a one-shot Job: the OTel
|
|
436
|
+
* tables do not exist until the gateway collector's goose migrations have run,
|
|
437
|
+
* and TypeKro does not own their DDL — so the script waits for each table to
|
|
438
|
+
* appear, and re-checks on every run. It only issues `MODIFY TTL` when the
|
|
439
|
+
* table's current TTL clause is not already the intended one, so a converged
|
|
440
|
+
* cluster does no metadata churn.
|
|
441
|
+
*
|
|
442
|
+
* THE IDEMPOTENCE PROBE COMPARES WHOLE CLAUSES. It extracts the complete TTL
|
|
443
|
+
* clause out of `system.tables.engine_full` — everything between `TTL ` and
|
|
444
|
+
* the trailing ` SETTINGS …`, whitespace-collapsed — and tests it for EQUALITY
|
|
445
|
+
* against {@link ResolvedRetentionEntry.ttlRenderings}. A substring probe was
|
|
446
|
+
* wrong in both directions (see the doc on `ttlRenderings`), and the actual
|
|
447
|
+
* clause is echoed on a mismatch so a rendering change is visible in the Job
|
|
448
|
+
* log instead of showing up as silent per-run churn.
|
|
449
|
+
*
|
|
450
|
+
* Notes on the SQL: the extraction deliberately contains no backslash escapes
|
|
451
|
+
* and no `$` anchors — it strips the `SETTINGS` tail with `replaceRegexpOne`
|
|
452
|
+
* first and uses the POSIX class `[[:space:]]` — because the expression has to
|
|
453
|
+
* survive being nested inside a double-quoted shell command substitution.
|
|
454
|
+
*
|
|
455
|
+
* @param resolved - Resolved storage options carrying `retentionEntries`
|
|
456
|
+
* @returns A POSIX shell script for `sh -c`
|
|
457
|
+
*/
|
|
458
|
+
export function renderRetentionScript(resolved) {
|
|
459
|
+
const lines = [
|
|
460
|
+
'set -eu',
|
|
461
|
+
// The chart's ConfigMap/Secret supply the connection, so this works
|
|
462
|
+
// identically in inline and Secret-backed credential modes. The braced
|
|
463
|
+
// forms below are POSIX parameter expansion (suffix/prefix stripping and
|
|
464
|
+
// defaults) — the only places braces are actually required.
|
|
465
|
+
// biome-ignore lint/suspicious/noTemplateCurlyInString: POSIX shell suffix stripping
|
|
466
|
+
'HOST="${CLICKHOUSE_SERVER_ENDPOINT%%:*}"',
|
|
467
|
+
// biome-ignore lint/suspicious/noTemplateCurlyInString: POSIX shell prefix stripping
|
|
468
|
+
'PORT="${CLICKHOUSE_SERVER_ENDPOINT##*:}"',
|
|
469
|
+
// biome-ignore lint/suspicious/noTemplateCurlyInString: POSIX shell default value
|
|
470
|
+
'DB="${HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE:-default}"',
|
|
471
|
+
// biome-ignore lint/suspicious/noTemplateCurlyInString: POSIX shell default value
|
|
472
|
+
'USER="${CLICKHOUSE_USER:-default}"',
|
|
473
|
+
// biome-ignore lint/suspicious/noTemplateCurlyInString: POSIX shell default value
|
|
474
|
+
'PASSWORD="${CLICKHOUSE_PASSWORD:-}"',
|
|
475
|
+
// No port in the endpoint: the stripping above left it unchanged.
|
|
476
|
+
'if [ "$PORT" = "$CLICKHOUSE_SERVER_ENDPOINT" ]; then PORT=9000; fi',
|
|
477
|
+
'run_query() {',
|
|
478
|
+
' clickhouse-client --host "$HOST" --port "$PORT" --user "$USER"' +
|
|
479
|
+
' --password "$PASSWORD" --database "$DB" --query "$1"',
|
|
480
|
+
'}',
|
|
481
|
+
];
|
|
482
|
+
for (const entry of resolved.retentionEntries) {
|
|
483
|
+
const ttl = entry.ttlExpression;
|
|
484
|
+
// Whole-clause equality — one `[ "$CURRENT" != … ]` test per accepted
|
|
485
|
+
// rendering, so ANY difference (a shorter interval that is a prefix of the
|
|
486
|
+
// intended one, an extra WHERE/GROUP BY, a second TTL entry) is a
|
|
487
|
+
// mismatch and gets re-applied.
|
|
488
|
+
const mismatch = entry.ttlRenderings
|
|
489
|
+
.map((rendering) => `[ "$CURRENT" != "${rendering}" ]`)
|
|
490
|
+
.join(' && ');
|
|
491
|
+
lines.push('', `# ${entry.signal}: ${entry.table} -> ${entry.duration}`, `if [ "$(run_query "EXISTS TABLE \\\`${entry.table}\\\`")" = "1" ]; then`,
|
|
492
|
+
// Strip the ` SETTINGS …` tail, take everything after `TTL `, collapse
|
|
493
|
+
// whitespace. Empty when the table carries no TTL at all.
|
|
494
|
+
` CURRENT="$(run_query "SELECT trim(replaceRegexpAll(` +
|
|
495
|
+
`extract(replaceRegexpOne(engine_full, ' SETTINGS .*', ''), 'TTL (.*)'),` +
|
|
496
|
+
` '[[:space:]]+', ' '))` +
|
|
497
|
+
` FROM system.tables WHERE database = currentDatabase() AND name = '${entry.table}'")"`, ` if ${mismatch}; then`, ` echo "Applying TTL ${ttl} to ${entry.table} (current: [$CURRENT])"`,
|
|
498
|
+
// materialize_ttl_after_modify = 0: the materialization pass is a
|
|
499
|
+
// MUTATION, which s3_plain_rewritable does not support. Expiry still
|
|
500
|
+
// happens during merges.
|
|
501
|
+
` run_query "ALTER TABLE \\\`${entry.table}\\\` MODIFY TTL ${ttl}` +
|
|
502
|
+
` SETTINGS materialize_ttl_after_modify = 0"`, ' else', ` echo "TTL on ${entry.table} already matches ${entry.duration}"`, ' fi', 'else', ` echo "Table ${entry.table} does not exist yet; retention will be applied on a later run"`, 'fi');
|
|
503
|
+
}
|
|
504
|
+
lines.push('', 'echo "Retention convergence complete"', '');
|
|
505
|
+
return lines.join('\n');
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* The persistent queue's contribution to the collector-config overlay.
|
|
509
|
+
*
|
|
510
|
+
* ⚠️ A STRUCTURED FRAGMENT, NOT YAML TEXT, and that is the whole point. This
|
|
511
|
+
* used to return a YAML string that the values mapper CONCATENATED onto the
|
|
512
|
+
* ingest-pipeline string. Both opened a top-level `service:` key, so the
|
|
513
|
+
* rendered `custom.config.yaml` declared `service` twice and the OpAMP
|
|
514
|
+
* supervisor rejected the WHOLE file on every poll:
|
|
515
|
+
*
|
|
516
|
+
* Could not merge local config file: …/custom/custom.config.yaml
|
|
517
|
+
* yaml: unmarshal errors: line 18: mapping key "service" already defined at line 1
|
|
518
|
+
*
|
|
519
|
+
* The agent then ran with NEITHER the ingest pipelines NOR the queue, while
|
|
520
|
+
* the Pod still reported Ready off the supervisor's own `health_check` — so
|
|
521
|
+
* enabling the queue was a silent no-op that also took OTLP ingestion down.
|
|
522
|
+
* Fragments are merged by `mergeCollectorConfig` (see
|
|
523
|
+
* `utils/collector-config.ts`) and serialised exactly once, which makes a
|
|
524
|
+
* duplicate key unrepresentable.
|
|
525
|
+
*
|
|
526
|
+
* ⚠️ The YAML lists here REPLACE the supervisor's own lists (the chart's
|
|
527
|
+
* `customConfig` is a merge, not a deep list append) — see the warning on
|
|
528
|
+
* {@link ClickStackPersistentQueueOptions}. `service.extensions` is a sequence,
|
|
529
|
+
* so it UNIONS with any other fragment's contribution before that replacement
|
|
530
|
+
* happens.
|
|
531
|
+
*
|
|
532
|
+
* Every name in `exporterNames` gets its own `sending_queue.storage`. A name
|
|
533
|
+
* the agent does not define is inert rather than fatal — see
|
|
534
|
+
* {@link DEFAULT_QUEUE_EXPORTER_NAMES} for why it cannot be checked here.
|
|
535
|
+
*
|
|
536
|
+
* ⚠️ THE EXPORTER MAP IS BUILT KEY BY KEY, on a NULL-PROTOTYPE dictionary, and
|
|
537
|
+
* every name is re-checked. It used to be an `Object.fromEntries` over
|
|
538
|
+
* `exporterNames`, which is honest enough on its own — `fromEntries` DEFINES an
|
|
539
|
+
* own property, so it does not pollute — but the overlay merge then copied the
|
|
540
|
+
* map with `copy[key] = …` onto a plain `{}`, where assigning `__proto__` calls
|
|
541
|
+
* the inherited SETTER and re-parents the copy instead of adding a key. An
|
|
542
|
+
* `exporterNames: ['__proto__']` install therefore rendered `exporters: {}`: a
|
|
543
|
+
* queue that configured nothing, reported no error, and left the real exporter
|
|
544
|
+
* on its in-memory queue. `resolveClickStackStorage` rejects such a name at the
|
|
545
|
+
* option, and this function refuses it again so no caller holding a
|
|
546
|
+
* hand-built `ResolvedClickStackStorage` can route around that.
|
|
547
|
+
*
|
|
548
|
+
* @param queue - Resolved persistent-queue configuration
|
|
549
|
+
* @returns A fragment for `global.otelCollector.customConfig`
|
|
550
|
+
* @throws Error when a component name is a JavaScript object-model member
|
|
551
|
+
*/
|
|
552
|
+
export function persistentQueueConfigFragment(queue) {
|
|
553
|
+
const exporters = Object.create(null);
|
|
554
|
+
for (const exporterName of queue.exporterNames) {
|
|
555
|
+
assertSafeCollectorConfigKey(exporterName, ['exporters']);
|
|
556
|
+
// `defineProperty`, not assignment: on a prototype-less dictionary the two
|
|
557
|
+
// are equivalent, and spelling it out keeps the guarantee local — this line
|
|
558
|
+
// cannot become a setter call however the dictionary above is later built.
|
|
559
|
+
Object.defineProperty(exporters, exporterName, {
|
|
560
|
+
value: { sending_queue: { enabled: true, storage: QUEUE_EXTENSION_NAME } },
|
|
561
|
+
enumerable: true,
|
|
562
|
+
writable: true,
|
|
563
|
+
configurable: true,
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
for (const extensionName of queue.extensions) {
|
|
567
|
+
// A `service.extensions` entry is a sequence item here, but it NAMES an
|
|
568
|
+
// extension instance whose name is a mapping key under `extensions:` — the
|
|
569
|
+
// same guard applies, at the same construction time.
|
|
570
|
+
assertSafeCollectorConfigKey(extensionName, ['service', 'extensions']);
|
|
571
|
+
}
|
|
572
|
+
return {
|
|
573
|
+
extensions: {
|
|
574
|
+
[QUEUE_EXTENSION_NAME]: {
|
|
575
|
+
directory: queue.directory,
|
|
576
|
+
create_directory: true,
|
|
577
|
+
},
|
|
578
|
+
},
|
|
579
|
+
exporters,
|
|
580
|
+
service: { extensions: [...queue.extensions] },
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* Chart values that mount the queue's PersistentVolumeClaim on the collector.
|
|
585
|
+
*
|
|
586
|
+
* The claim is a STANDALONE PersistentVolumeClaim owned by the composition
|
|
587
|
+
* (rendered next to the retention CronJob) and referenced here by
|
|
588
|
+
* `claimName` — never an `emptyDir` and never a *generic ephemeral volume*.
|
|
589
|
+
* Kubernetes deletes a generic ephemeral volume's PVC together with the Pod
|
|
590
|
+
* that owns it, so an ephemeral claim would be destroyed by exactly the
|
|
591
|
+
* collector restart the queue exists to survive.
|
|
592
|
+
*
|
|
593
|
+
* The collector is also PINNED to one replica, unconditionally: the queue is a
|
|
594
|
+
* bbolt database under an exclusive file lock, so a second replica cannot open
|
|
595
|
+
* it at all — see {@link assertQueueReplicaCompatible}, which rejects a
|
|
596
|
+
* build-time `replicaCount` above 1 at construction. The pin makes that
|
|
597
|
+
* guarantee explicit in the rendered values against later drift.
|
|
598
|
+
*
|
|
599
|
+
* ⚠️ `replicaCount: 1` IS NOT ENOUGH ON ITS OWN, which is why
|
|
600
|
+
* `rollout.strategy: 'Recreate'` travels with it. One replica bounds the
|
|
601
|
+
* STEADY state, not the state DURING a rollout: the chart leaves the
|
|
602
|
+
* Deployment on Kubernetes' default `RollingUpdate` (values.yaml `rollout`,
|
|
603
|
+
* collector chart 0.146.x), whose default `maxSurge: 25%` rounds UP to one
|
|
604
|
+
* extra Pod. A rollout therefore creates the replacement Pod while the old one
|
|
605
|
+
* is still running and still holding both the claim and the queue, and that
|
|
606
|
+
* overlap fails in one of two ways depending on where the replacement lands:
|
|
607
|
+
*
|
|
608
|
+
* - **On another node — a stuck rollout.** The ReadWriteOnce claim is still
|
|
609
|
+
* attached to the old Pod's node, so the replacement never leaves
|
|
610
|
+
* `ContainerCreating` (`Multi-Attach error for volume`). `RollingUpdate`
|
|
611
|
+
* will not terminate the old Pod until the new one is Ready, and
|
|
612
|
+
* `maxUnavailable: 25%` of one replica rounds DOWN to zero, so nothing gives:
|
|
613
|
+
* the rollout DEADLOCKS until `progressDeadlineSeconds` expires.
|
|
614
|
+
* - **On the same node — a silent two-writer window.** The replacement starts,
|
|
615
|
+
* and its `file_storage` extension cannot take bbolt's exclusive lock while
|
|
616
|
+
* the old collector holds it. Readiness does not notice: it comes from the
|
|
617
|
+
* OpAMP supervisor's own `health_check`, not from the agent's extensions
|
|
618
|
+
* (the same reason the missing `custom-config` mount below stayed invisible),
|
|
619
|
+
* so the Pod reports Ready and the rollout "succeeds" over a queue the new
|
|
620
|
+
* collector could not open. LIVE-OBSERVED on a single-node cluster: under
|
|
621
|
+
* `RollingUpdate` the replacement went Ready in under 10s.
|
|
622
|
+
*
|
|
623
|
+
* `Recreate` removes the overlap entirely: the old Pod is deleted, its claim
|
|
624
|
+
* detaches and its lock is released, and only then is the replacement created.
|
|
625
|
+
*
|
|
626
|
+
* The cost is a brief gateway outage on every rollout, and the persistent
|
|
627
|
+
* queue is precisely what makes that cost acceptable: producers upstream of
|
|
628
|
+
* the gateway retry, and telemetry the gateway already accepted is on the
|
|
629
|
+
* claim rather than in the departing Pod's memory, so the replacement resumes
|
|
630
|
+
* draining the same queue instead of starting from an empty one.
|
|
631
|
+
*
|
|
632
|
+
* `rollout.rollingUpdate` needs no clearing here. The chart's Deployment
|
|
633
|
+
* template emits that block only under `if eq .Values.rollout.strategy
|
|
634
|
+
* "RollingUpdate"`, so `Recreate` drops it — which matters, because a
|
|
635
|
+
* Deployment carrying `strategy.type: Recreate` alongside a
|
|
636
|
+
* `strategy.rollingUpdate` block is rejected by the API server.
|
|
637
|
+
*
|
|
638
|
+
* ⚠️ THE CHART'S OWN `custom-config` VOLUME IS RE-EMITTED HERE, and must be:
|
|
639
|
+
* Helm REPLACES a list override instead of appending to it, and these are the
|
|
640
|
+
* lists through which the chart mounts the ConfigMap it renders from
|
|
641
|
+
* `global.otelCollector.customConfig` — the overlay that carries the ingest
|
|
642
|
+
* pipelines AND this queue's own `file_storage` wiring. Dropping it makes the
|
|
643
|
+
* OpAMP supervisor fail to read `custom.config.yaml` and never start the
|
|
644
|
+
* agent's receivers, with the Pod still Ready. See
|
|
645
|
+
* {@link CHART_CUSTOM_CONFIG_VOLUME_NAME} for the live evidence.
|
|
646
|
+
*
|
|
647
|
+
* @param queue - Resolved persistent-queue configuration
|
|
648
|
+
* @param claimName - Name of the PVC the composition creates
|
|
649
|
+
* ({@link clickStackQueueClaimName})
|
|
650
|
+
* @returns Values under the `otel-collector` subchart alias
|
|
651
|
+
*/
|
|
652
|
+
export function renderPersistentQueueValues(queue, claimName) {
|
|
653
|
+
return {
|
|
654
|
+
'otel-collector': {
|
|
655
|
+
extraVolumes: [
|
|
656
|
+
// The chart's own entry, re-emitted because Helm replaces the list.
|
|
657
|
+
{
|
|
658
|
+
name: CHART_CUSTOM_CONFIG_VOLUME_NAME,
|
|
659
|
+
configMap: { name: CHART_CUSTOM_CONFIG_CONFIG_MAP_NAME, optional: true },
|
|
660
|
+
},
|
|
661
|
+
{ name: QUEUE_VOLUME_NAME, persistentVolumeClaim: { claimName } },
|
|
662
|
+
],
|
|
663
|
+
extraVolumeMounts: [
|
|
664
|
+
{
|
|
665
|
+
name: CHART_CUSTOM_CONFIG_VOLUME_NAME,
|
|
666
|
+
mountPath: CHART_CUSTOM_CONFIG_MOUNT_PATH,
|
|
667
|
+
readOnly: true,
|
|
668
|
+
},
|
|
669
|
+
{ name: QUEUE_VOLUME_NAME, mountPath: queue.directory },
|
|
670
|
+
],
|
|
671
|
+
// Always pinned: the queue's bbolt database admits exactly one writer.
|
|
672
|
+
replicaCount: 1,
|
|
673
|
+
// …and one writer AT A TIME, which the replica count alone does not buy
|
|
674
|
+
// during a rollout. RollingUpdate surges a second Pod onto the same RWO
|
|
675
|
+
// claim and the same bbolt lock while the old one still holds both:
|
|
676
|
+
// Multi-Attach deadlock on another node, silent lock contention on the
|
|
677
|
+
// same one. Recreate drains first. The chart emits `rollingUpdate` only
|
|
678
|
+
// for the RollingUpdate branch, so there is nothing to clear.
|
|
679
|
+
rollout: { strategy: QUEUE_ROLLOUT_STRATEGY },
|
|
680
|
+
},
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Spec of the standalone PersistentVolumeClaim backing the collector queue.
|
|
685
|
+
*
|
|
686
|
+
* @param queue - Resolved persistent-queue configuration
|
|
687
|
+
* @returns A `V1PersistentVolumeClaim.spec` object
|
|
688
|
+
*/
|
|
689
|
+
export function renderPersistentQueueClaimSpec(queue) {
|
|
690
|
+
return {
|
|
691
|
+
accessModes: [...queue.accessModes],
|
|
692
|
+
resources: { requests: { storage: queue.size } },
|
|
693
|
+
...(queue.storageClassName !== undefined && {
|
|
694
|
+
storageClassName: queue.storageClassName,
|
|
695
|
+
}),
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
//# sourceMappingURL=storage.js.map
|