typekro 0.33.10 → 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/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/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/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,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cluster API capability resolution.
|
|
3
|
+
*
|
|
4
|
+
* Some resources can only be rendered once the target cluster has said which
|
|
5
|
+
* group version it actually serves for a kind. `MutatingAdmissionPolicy` is the
|
|
6
|
+
* motivating case: beta on Kubernetes 1.34/1.35
|
|
7
|
+
* (`admissionregistration.k8s.io/v1beta1`), GA from 1.36
|
|
8
|
+
* (`admissionregistration.k8s.io/v1`), never both on the same server, and
|
|
9
|
+
* absent entirely below 1.34. Guessing produces an apply failure for the whole
|
|
10
|
+
* graph, so nothing here ever guesses: a capability is either resolved against
|
|
11
|
+
* a cluster or reported as unresolved, and the caller skips the resource.
|
|
12
|
+
*
|
|
13
|
+
* "Unresolved" is itself two different things, and they are kept apart. The
|
|
14
|
+
* cluster answering "I do not serve that" is a fact worth caching and worth
|
|
15
|
+
* telling the user. Failing to reach the cluster at all is not a fact about the
|
|
16
|
+
* cluster, and reporting it as one — then caching it for five minutes — is how
|
|
17
|
+
* a transient RBAC or network error turns into a confident lie. Hence the
|
|
18
|
+
* three-way {@link ClusterCapabilityResolution}.
|
|
19
|
+
*
|
|
20
|
+
* Two pieces make that work:
|
|
21
|
+
*
|
|
22
|
+
* - {@link resolveClusterCapability} runs discovery once per cluster and caches
|
|
23
|
+
* the answer under the **cluster's identity**, never globally. A process that
|
|
24
|
+
* talks to two clusters — a test suite with two fakes, multi-cluster
|
|
25
|
+
* tooling — gets an independent answer for each.
|
|
26
|
+
* - {@link runWithDeployTarget} publishes the cluster a deployment is currently
|
|
27
|
+
* targeting, so synchronous code further down (a composition body re-executed
|
|
28
|
+
* at deploy time) can read the answer resolved for *that* cluster without
|
|
29
|
+
* threading a `KubeConfig` through every call.
|
|
30
|
+
*/
|
|
31
|
+
import type * as k8s from '@kubernetes/client-node';
|
|
32
|
+
import { type ApiReadFailure } from '../deployment/k8s-helpers.js';
|
|
33
|
+
/**
|
|
34
|
+
* A kind whose served group version has to come from the cluster.
|
|
35
|
+
*
|
|
36
|
+
* `versions` is bare version names in preference order — the first one the
|
|
37
|
+
* cluster serves the kind at wins.
|
|
38
|
+
*/
|
|
39
|
+
export interface ClusterCapabilityRequirement {
|
|
40
|
+
/** Stable id; forms half of the cache key (the cluster identity is the other half). */
|
|
41
|
+
id: string;
|
|
42
|
+
group: string;
|
|
43
|
+
kind: string;
|
|
44
|
+
versions: readonly string[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Why discovery could not answer. `notFound` is excluded on purpose: a 404 *is*
|
|
48
|
+
* an answer ("not served"), everything here is the absence of one.
|
|
49
|
+
*/
|
|
50
|
+
export type DiscoveryFailure = Exclude<ApiReadFailure, 'notFound'>;
|
|
51
|
+
/**
|
|
52
|
+
* The outcome of asking a cluster about a kind.
|
|
53
|
+
*
|
|
54
|
+
* Three-way, not two-way, because "the cluster does not serve this" and "we
|
|
55
|
+
* could not find out" have opposite consequences: the first is a durable fact
|
|
56
|
+
* worth caching and reporting to the user, the second is a transient failure
|
|
57
|
+
* that must never be reported as a fact about the cluster.
|
|
58
|
+
*/
|
|
59
|
+
export type ClusterCapabilityResolution = {
|
|
60
|
+
status: 'served';
|
|
61
|
+
apiVersion: string;
|
|
62
|
+
} | {
|
|
63
|
+
status: 'unserved';
|
|
64
|
+
reason: string;
|
|
65
|
+
} | {
|
|
66
|
+
status: 'unknown';
|
|
67
|
+
reason: string;
|
|
68
|
+
failure: DiscoveryFailure;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* What a single `GET /apis/<group>/<version>` told us.
|
|
72
|
+
*
|
|
73
|
+
* - `served` — the server answered with a resource list; `kinds` is what it holds.
|
|
74
|
+
* - `unserved` — the server answered 404: this group version is definitively not served.
|
|
75
|
+
* - `unknown` — no answer (unreachable, RBAC, timeout, TLS). Says nothing about the cluster.
|
|
76
|
+
*/
|
|
77
|
+
export type ApiGroupProbe = {
|
|
78
|
+
status: 'served';
|
|
79
|
+
kinds: readonly string[];
|
|
80
|
+
} | {
|
|
81
|
+
status: 'unserved';
|
|
82
|
+
} | {
|
|
83
|
+
status: 'unknown';
|
|
84
|
+
failure: DiscoveryFailure;
|
|
85
|
+
message: string;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* The one cluster call capability resolution needs.
|
|
89
|
+
*
|
|
90
|
+
* Narrow on purpose: a test supplies a fake with a literal map of group
|
|
91
|
+
* versions to kinds and never touches `@kubernetes/client-node`.
|
|
92
|
+
*/
|
|
93
|
+
export interface ApiGroupDiscovery {
|
|
94
|
+
/** What the cluster says about `<group>/<version>`. */
|
|
95
|
+
servedKinds(group: string, version: string): Promise<ApiGroupProbe>;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* A stable fingerprint for the cluster a `KubeConfig` currently points at.
|
|
99
|
+
*
|
|
100
|
+
* Server URL plus CA material plus the context's cluster name: two kubeconfigs
|
|
101
|
+
* that reach the same API server with the same trust root are the same cluster,
|
|
102
|
+
* and two contexts that differ in any of those are not. Returns `undefined`
|
|
103
|
+
* when the config names no current cluster — there is nothing to key on, so
|
|
104
|
+
* nothing may be cached.
|
|
105
|
+
*/
|
|
106
|
+
export declare function clusterIdentity(kubeConfig: k8s.KubeConfig): string | undefined;
|
|
107
|
+
/** How long a resolved capability stays good. A cluster can be upgraded under us. */
|
|
108
|
+
export declare const CLUSTER_CAPABILITY_CACHE_TTL_MS: number;
|
|
109
|
+
/**
|
|
110
|
+
* How long an `unknown` outcome is retained — a **failure note**, not an answer.
|
|
111
|
+
*
|
|
112
|
+
* An `unknown` is recorded so that the build which follows a resolve step in the
|
|
113
|
+
* same deployment can say *why* it has no capability ("discovery failed: RBAC")
|
|
114
|
+
* instead of the far weaker "no cluster was asked". It is deliberately not an
|
|
115
|
+
* answer: {@link resolveClusterCapability} treats a stored `unknown` as a cache
|
|
116
|
+
* miss and re-probes, so a transient failure never suppresses the next real
|
|
117
|
+
* attempt, and this short lifetime bounds how long the note can linger at all.
|
|
118
|
+
*/
|
|
119
|
+
export declare const CLUSTER_CAPABILITY_UNKNOWN_CACHE_TTL_MS: number;
|
|
120
|
+
/** Ceiling on cached entries so long-lived multi-cluster tooling cannot grow unbounded. */
|
|
121
|
+
export declare const CLUSTER_CAPABILITY_CACHE_MAX_ENTRIES = 64;
|
|
122
|
+
/**
|
|
123
|
+
* Read a previously resolved capability without touching the cluster.
|
|
124
|
+
*
|
|
125
|
+
* May return an `unknown` entry: the reporting path *wants* to see that
|
|
126
|
+
* discovery was attempted and failed, so it can say so rather than claim the
|
|
127
|
+
* cluster lacks the API. {@link resolveClusterCapability} ignores those entries.
|
|
128
|
+
*/
|
|
129
|
+
export declare function getCachedClusterCapability(requirement: ClusterCapabilityRequirement, clusterId: string): ClusterCapabilityResolution | undefined;
|
|
130
|
+
/** Drop every cached capability. Test seam. */
|
|
131
|
+
export declare function resetClusterCapabilityCache(): void;
|
|
132
|
+
/** Number of live cache entries. Test seam for the bounded-lifetime contract. */
|
|
133
|
+
export declare function clusterCapabilityCacheSize(): number;
|
|
134
|
+
/**
|
|
135
|
+
* Discovery backed by a real cluster.
|
|
136
|
+
*
|
|
137
|
+
* `GET /apis/<group>/<version>` is the definitive test, and is why this is
|
|
138
|
+
* discovery rather than a list call: 1.32 and 1.33 serve
|
|
139
|
+
* `admissionregistration.k8s.io/v1` for webhook configurations while not
|
|
140
|
+
* serving `MutatingAdmissionPolicy` at all, so "the group version exists" is
|
|
141
|
+
* not the same question as "the kind is served".
|
|
142
|
+
*/
|
|
143
|
+
export declare function kubeConfigApiGroupDiscovery(kubeConfig: k8s.KubeConfig): ApiGroupDiscovery;
|
|
144
|
+
/**
|
|
145
|
+
* Ask a cluster which group version serves a kind, memoized per cluster.
|
|
146
|
+
*
|
|
147
|
+
* Never falls back to a preferred or assumed version, and never turns a
|
|
148
|
+
* discovery failure into a claim about the cluster:
|
|
149
|
+
*
|
|
150
|
+
* - `served` — a candidate version's resource list contains the kind.
|
|
151
|
+
* - `unserved` — every candidate was *answered for* (404, or a 200 list without
|
|
152
|
+
* the kind) and none serves it. A durable fact; cached for the full TTL.
|
|
153
|
+
* - `unknown` — no candidate served the kind and at least one could not be
|
|
154
|
+
* checked. The kind may well be served at the version we could not reach, so
|
|
155
|
+
* nothing may be concluded. Retained only as a short-lived failure note, and
|
|
156
|
+
* treated as a cache miss by the next call.
|
|
157
|
+
*/
|
|
158
|
+
export declare function resolveClusterCapability(requirement: ClusterCapabilityRequirement, options: {
|
|
159
|
+
clusterId: string;
|
|
160
|
+
discovery: ApiGroupDiscovery;
|
|
161
|
+
/** Skip the cache read. The write still happens. */
|
|
162
|
+
refresh?: boolean;
|
|
163
|
+
ttlMs?: number;
|
|
164
|
+
/** Lifetime for an `unknown` failure note. */
|
|
165
|
+
unknownTtlMs?: number;
|
|
166
|
+
}): Promise<ClusterCapabilityResolution>;
|
|
167
|
+
/** Register a requirement to be resolved before each deployment. Idempotent. */
|
|
168
|
+
export declare function registerDeployTimeCapability(requirement: ClusterCapabilityRequirement): void;
|
|
169
|
+
/** Every registered deploy-time requirement. */
|
|
170
|
+
export declare function listDeployTimeCapabilities(): ClusterCapabilityRequirement[];
|
|
171
|
+
/**
|
|
172
|
+
* Resolve every registered requirement against a cluster and return that
|
|
173
|
+
* cluster's identity, or `undefined` when the config names no cluster (nothing
|
|
174
|
+
* was resolved, and callers must treat every capability as unavailable).
|
|
175
|
+
*
|
|
176
|
+
* Resolution failures are not fatal: a requirement that cannot be resolved
|
|
177
|
+
* comes back `unknown`, which makes the caller skip the resource just as
|
|
178
|
+
* `unserved` does — the whole point of the seam is that an unverified API is
|
|
179
|
+
* never assumed to be present. The two are kept distinct so the caller can say
|
|
180
|
+
* which happened rather than blaming the cluster for a network error.
|
|
181
|
+
*/
|
|
182
|
+
export declare function resolveDeployTimeCapabilities(kubeConfig: k8s.KubeConfig, options?: {
|
|
183
|
+
discovery?: ApiGroupDiscovery;
|
|
184
|
+
}): Promise<string | undefined>;
|
|
185
|
+
/**
|
|
186
|
+
* Run `fn` with `clusterId` published as the cluster this deployment targets.
|
|
187
|
+
*
|
|
188
|
+
* Synchronous code inside — notably a composition body re-executed at deploy
|
|
189
|
+
* time — can then read capabilities resolved for exactly that cluster. Nested
|
|
190
|
+
* and concurrent deployments to different clusters do not see each other's
|
|
191
|
+
* target.
|
|
192
|
+
*/
|
|
193
|
+
export declare function runWithDeployTarget<T>(clusterId: string, fn: () => T): T;
|
|
194
|
+
/** The cluster the current deployment targets, if any. */
|
|
195
|
+
export declare function getCurrentDeployTarget(): string | undefined;
|
|
196
|
+
//# sourceMappingURL=api-capability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-capability.d.ts","sourceRoot":"","sources":["../../../src/core/kubernetes/api-capability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH,OAAO,KAAK,KAAK,GAAG,MAAM,yBAAyB,CAAC;AACpD,OAAO,EACL,KAAK,cAAc,EAIpB,MAAM,8BAA8B,CAAC;AAMtC;;;;;GAKG;AACH,MAAM,WAAW,4BAA4B;IAC3C,uFAAuF;IACvF,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,OAAO,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;AAEnE;;;;;;;GAOG;AACH,MAAM,MAAM,2BAA2B,GACnC;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAErE;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAC9C;IAAE,MAAM,EAAE,UAAU,CAAA;CAAE,GACtB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtE;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,uDAAuD;IACvD,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CACrE;AAMD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,GAAG,CAAC,UAAU,GAAG,MAAM,GAAG,SAAS,CAkB9E;AAMD,qFAAqF;AACrF,eAAO,MAAM,+BAA+B,QAAgB,CAAC;AAE7D;;;;;;;;;GASG;AACH,eAAO,MAAM,uCAAuC,QAAY,CAAC;AAEjE,2FAA2F;AAC3F,eAAO,MAAM,oCAAoC,KAAK,CAAC;AA8CvD;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,4BAA4B,EACzC,SAAS,EAAE,MAAM,GAChB,2BAA2B,GAAG,SAAS,CAEzC;AAED,+CAA+C;AAC/C,wBAAgB,2BAA2B,IAAI,IAAI,CAElD;AAED,iFAAiF;AACjF,wBAAgB,0BAA0B,IAAI,MAAM,CAEnD;AAWD;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,GAAG,CAAC,UAAU,GAAG,iBAAiB,CAsCzF;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,wBAAwB,CAC5C,WAAW,EAAE,4BAA4B,EACzC,OAAO,EAAE;IACP,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,iBAAiB,CAAC;IAC7B,oDAAoD;IACpD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GACA,OAAO,CAAC,2BAA2B,CAAC,CA2DtC;AAiBD,gFAAgF;AAChF,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,4BAA4B,GAAG,IAAI,CAE5F;AAED,gDAAgD;AAChD,wBAAgB,0BAA0B,IAAI,4BAA4B,EAAE,CAE3E;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,6BAA6B,CACjD,UAAU,EAAE,GAAG,CAAC,UAAU,EAC1B,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,iBAAiB,CAAA;CAAO,GAC9C,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAY7B;AAQD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAExE;AAED,0DAA0D;AAC1D,wBAAgB,sBAAsB,IAAI,MAAM,GAAG,SAAS,CAE3D"}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cluster API capability resolution.
|
|
3
|
+
*
|
|
4
|
+
* Some resources can only be rendered once the target cluster has said which
|
|
5
|
+
* group version it actually serves for a kind. `MutatingAdmissionPolicy` is the
|
|
6
|
+
* motivating case: beta on Kubernetes 1.34/1.35
|
|
7
|
+
* (`admissionregistration.k8s.io/v1beta1`), GA from 1.36
|
|
8
|
+
* (`admissionregistration.k8s.io/v1`), never both on the same server, and
|
|
9
|
+
* absent entirely below 1.34. Guessing produces an apply failure for the whole
|
|
10
|
+
* graph, so nothing here ever guesses: a capability is either resolved against
|
|
11
|
+
* a cluster or reported as unresolved, and the caller skips the resource.
|
|
12
|
+
*
|
|
13
|
+
* "Unresolved" is itself two different things, and they are kept apart. The
|
|
14
|
+
* cluster answering "I do not serve that" is a fact worth caching and worth
|
|
15
|
+
* telling the user. Failing to reach the cluster at all is not a fact about the
|
|
16
|
+
* cluster, and reporting it as one — then caching it for five minutes — is how
|
|
17
|
+
* a transient RBAC or network error turns into a confident lie. Hence the
|
|
18
|
+
* three-way {@link ClusterCapabilityResolution}.
|
|
19
|
+
*
|
|
20
|
+
* Two pieces make that work:
|
|
21
|
+
*
|
|
22
|
+
* - {@link resolveClusterCapability} runs discovery once per cluster and caches
|
|
23
|
+
* the answer under the **cluster's identity**, never globally. A process that
|
|
24
|
+
* talks to two clusters — a test suite with two fakes, multi-cluster
|
|
25
|
+
* tooling — gets an independent answer for each.
|
|
26
|
+
* - {@link runWithDeployTarget} publishes the cluster a deployment is currently
|
|
27
|
+
* targeting, so synchronous code further down (a composition body re-executed
|
|
28
|
+
* at deploy time) can read the answer resolved for *that* cluster without
|
|
29
|
+
* threading a `KubeConfig` through every call.
|
|
30
|
+
*/
|
|
31
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
32
|
+
import { createHash } from 'node:crypto';
|
|
33
|
+
import { classifyApiReadError, describeApiReadError, isNotFoundError, } from '../deployment/k8s-helpers.js';
|
|
34
|
+
import { getComponentLogger } from '../logging/index.js';
|
|
35
|
+
import { createBunCompatibleApiClient } from './bun-api-client.js';
|
|
36
|
+
const logger = getComponentLogger('api-capability');
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// Cluster identity
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
/**
|
|
41
|
+
* A stable fingerprint for the cluster a `KubeConfig` currently points at.
|
|
42
|
+
*
|
|
43
|
+
* Server URL plus CA material plus the context's cluster name: two kubeconfigs
|
|
44
|
+
* that reach the same API server with the same trust root are the same cluster,
|
|
45
|
+
* and two contexts that differ in any of those are not. Returns `undefined`
|
|
46
|
+
* when the config names no current cluster — there is nothing to key on, so
|
|
47
|
+
* nothing may be cached.
|
|
48
|
+
*/
|
|
49
|
+
export function clusterIdentity(kubeConfig) {
|
|
50
|
+
let cluster;
|
|
51
|
+
try {
|
|
52
|
+
cluster = kubeConfig.getCurrentCluster();
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
if (!cluster?.server)
|
|
58
|
+
return undefined;
|
|
59
|
+
const material = [
|
|
60
|
+
cluster.name ?? '',
|
|
61
|
+
cluster.server,
|
|
62
|
+
cluster.caData ?? '',
|
|
63
|
+
cluster.caFile ?? '',
|
|
64
|
+
String(cluster.skipTLSVerify ?? false),
|
|
65
|
+
].join('|');
|
|
66
|
+
return createHash('sha256').update(material).digest('hex').slice(0, 32);
|
|
67
|
+
}
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// Cache
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
/** How long a resolved capability stays good. A cluster can be upgraded under us. */
|
|
72
|
+
export const CLUSTER_CAPABILITY_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
73
|
+
/**
|
|
74
|
+
* How long an `unknown` outcome is retained — a **failure note**, not an answer.
|
|
75
|
+
*
|
|
76
|
+
* An `unknown` is recorded so that the build which follows a resolve step in the
|
|
77
|
+
* same deployment can say *why* it has no capability ("discovery failed: RBAC")
|
|
78
|
+
* instead of the far weaker "no cluster was asked". It is deliberately not an
|
|
79
|
+
* answer: {@link resolveClusterCapability} treats a stored `unknown` as a cache
|
|
80
|
+
* miss and re-probes, so a transient failure never suppresses the next real
|
|
81
|
+
* attempt, and this short lifetime bounds how long the note can linger at all.
|
|
82
|
+
*/
|
|
83
|
+
export const CLUSTER_CAPABILITY_UNKNOWN_CACHE_TTL_MS = 10 * 1000;
|
|
84
|
+
/** Ceiling on cached entries so long-lived multi-cluster tooling cannot grow unbounded. */
|
|
85
|
+
export const CLUSTER_CAPABILITY_CACHE_MAX_ENTRIES = 64;
|
|
86
|
+
/** Keyed by `<cluster identity>|<requirement id>` — never by requirement alone. */
|
|
87
|
+
const cache = new Map();
|
|
88
|
+
function cacheKey(clusterId, requirementId) {
|
|
89
|
+
return `${clusterId}|${requirementId}`;
|
|
90
|
+
}
|
|
91
|
+
function readCache(clusterId, requirementId) {
|
|
92
|
+
const key = cacheKey(clusterId, requirementId);
|
|
93
|
+
const entry = cache.get(key);
|
|
94
|
+
if (!entry)
|
|
95
|
+
return undefined;
|
|
96
|
+
if (entry.expiresAt <= Date.now()) {
|
|
97
|
+
cache.delete(key);
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
return entry.resolution;
|
|
101
|
+
}
|
|
102
|
+
function writeCache(clusterId, requirementId, resolution, ttlMs) {
|
|
103
|
+
const key = cacheKey(clusterId, requirementId);
|
|
104
|
+
// Re-insert so iteration order is insertion recency; the oldest entry is the
|
|
105
|
+
// first key Map yields.
|
|
106
|
+
cache.delete(key);
|
|
107
|
+
cache.set(key, { resolution, expiresAt: Date.now() + ttlMs });
|
|
108
|
+
while (cache.size > CLUSTER_CAPABILITY_CACHE_MAX_ENTRIES) {
|
|
109
|
+
const oldest = cache.keys().next();
|
|
110
|
+
if (oldest.done)
|
|
111
|
+
break;
|
|
112
|
+
cache.delete(oldest.value);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Read a previously resolved capability without touching the cluster.
|
|
117
|
+
*
|
|
118
|
+
* May return an `unknown` entry: the reporting path *wants* to see that
|
|
119
|
+
* discovery was attempted and failed, so it can say so rather than claim the
|
|
120
|
+
* cluster lacks the API. {@link resolveClusterCapability} ignores those entries.
|
|
121
|
+
*/
|
|
122
|
+
export function getCachedClusterCapability(requirement, clusterId) {
|
|
123
|
+
return readCache(clusterId, requirement.id);
|
|
124
|
+
}
|
|
125
|
+
/** Drop every cached capability. Test seam. */
|
|
126
|
+
export function resetClusterCapabilityCache() {
|
|
127
|
+
cache.clear();
|
|
128
|
+
}
|
|
129
|
+
/** Number of live cache entries. Test seam for the bounded-lifetime contract. */
|
|
130
|
+
export function clusterCapabilityCacheSize() {
|
|
131
|
+
return cache.size;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Discovery backed by a real cluster.
|
|
135
|
+
*
|
|
136
|
+
* `GET /apis/<group>/<version>` is the definitive test, and is why this is
|
|
137
|
+
* discovery rather than a list call: 1.32 and 1.33 serve
|
|
138
|
+
* `admissionregistration.k8s.io/v1` for webhook configurations while not
|
|
139
|
+
* serving `MutatingAdmissionPolicy` at all, so "the group version exists" is
|
|
140
|
+
* not the same question as "the kind is served".
|
|
141
|
+
*/
|
|
142
|
+
export function kubeConfigApiGroupDiscovery(kubeConfig) {
|
|
143
|
+
return {
|
|
144
|
+
async servedKinds(group, version) {
|
|
145
|
+
try {
|
|
146
|
+
const clientNode = await import('@kubernetes/client-node');
|
|
147
|
+
const api = createBunCompatibleApiClient(kubeConfig, clientNode.CustomObjectsApi);
|
|
148
|
+
const list = await api.getAPIResources({ group, version });
|
|
149
|
+
return {
|
|
150
|
+
status: 'served',
|
|
151
|
+
kinds: (list.resources ?? [])
|
|
152
|
+
.filter((resource) => typeof resource.name === 'string' && !resource.name.includes('/'))
|
|
153
|
+
.map((resource) => resource.kind)
|
|
154
|
+
.filter((kind) => typeof kind === 'string'),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
// Only a 404 is an answer. The server was asked and said this group
|
|
159
|
+
// version does not exist, which is a durable fact about the cluster.
|
|
160
|
+
if (isNotFoundError(error)) {
|
|
161
|
+
logger.debug('API group version is not served', { group, version });
|
|
162
|
+
return { status: 'unserved' };
|
|
163
|
+
}
|
|
164
|
+
// Everything else — unreachable server, RBAC, timeout, TLS — means the
|
|
165
|
+
// question never reached the server. Reporting that as "not served"
|
|
166
|
+
// would put a false claim about the cluster in front of the user (and,
|
|
167
|
+
// before this split, into a five-minute cache).
|
|
168
|
+
const failure = classifyApiReadError(error);
|
|
169
|
+
const message = describeApiReadError(error);
|
|
170
|
+
logger.debug('API group version discovery failed', { group, version, failure, message });
|
|
171
|
+
return { status: 'unknown', failure, message };
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
// ---------------------------------------------------------------------------
|
|
177
|
+
// Resolution
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
/**
|
|
180
|
+
* Ask a cluster which group version serves a kind, memoized per cluster.
|
|
181
|
+
*
|
|
182
|
+
* Never falls back to a preferred or assumed version, and never turns a
|
|
183
|
+
* discovery failure into a claim about the cluster:
|
|
184
|
+
*
|
|
185
|
+
* - `served` — a candidate version's resource list contains the kind.
|
|
186
|
+
* - `unserved` — every candidate was *answered for* (404, or a 200 list without
|
|
187
|
+
* the kind) and none serves it. A durable fact; cached for the full TTL.
|
|
188
|
+
* - `unknown` — no candidate served the kind and at least one could not be
|
|
189
|
+
* checked. The kind may well be served at the version we could not reach, so
|
|
190
|
+
* nothing may be concluded. Retained only as a short-lived failure note, and
|
|
191
|
+
* treated as a cache miss by the next call.
|
|
192
|
+
*/
|
|
193
|
+
export async function resolveClusterCapability(requirement, options) {
|
|
194
|
+
const { clusterId, discovery, refresh = false, ttlMs = CLUSTER_CAPABILITY_CACHE_TTL_MS, unknownTtlMs = CLUSTER_CAPABILITY_UNKNOWN_CACHE_TTL_MS, } = options;
|
|
195
|
+
if (!refresh) {
|
|
196
|
+
const cached = readCache(clusterId, requirement.id);
|
|
197
|
+
// A stored `unknown` is a note about a past failure, never an answer, so it
|
|
198
|
+
// must not short-circuit a fresh attempt.
|
|
199
|
+
if (cached && cached.status !== 'unknown')
|
|
200
|
+
return cached;
|
|
201
|
+
}
|
|
202
|
+
const groupVersions = requirement.versions.map((version) => `${requirement.group}/${version}`);
|
|
203
|
+
const failures = [];
|
|
204
|
+
let resolution;
|
|
205
|
+
for (const version of requirement.versions) {
|
|
206
|
+
const probe = await discovery.servedKinds(requirement.group, version);
|
|
207
|
+
if (probe.status === 'served' && probe.kinds.includes(requirement.kind)) {
|
|
208
|
+
resolution = { status: 'served', apiVersion: `${requirement.group}/${version}` };
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
if (probe.status === 'unknown') {
|
|
212
|
+
failures.push({
|
|
213
|
+
groupVersion: `${requirement.group}/${version}`,
|
|
214
|
+
failure: probe.failure,
|
|
215
|
+
message: probe.message,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (!resolution) {
|
|
220
|
+
const firstFailure = failures[0];
|
|
221
|
+
resolution = firstFailure
|
|
222
|
+
? {
|
|
223
|
+
status: 'unknown',
|
|
224
|
+
failure: firstFailure.failure,
|
|
225
|
+
reason: `${requirement.kind} discovery against the cluster failed for ` +
|
|
226
|
+
`${failures.map((entry) => entry.groupVersion).join(', ')} ` +
|
|
227
|
+
`(${firstFailure.message}), so whether the cluster serves the kind is unknown`,
|
|
228
|
+
}
|
|
229
|
+
: {
|
|
230
|
+
status: 'unserved',
|
|
231
|
+
reason: `the cluster does not serve ${requirement.kind} at any of ${groupVersions.join(', ')}`,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
writeCache(clusterId, requirement.id, resolution, resolution.status === 'unknown' ? unknownTtlMs : ttlMs);
|
|
235
|
+
return resolution;
|
|
236
|
+
}
|
|
237
|
+
// ---------------------------------------------------------------------------
|
|
238
|
+
// Deploy-time registry
|
|
239
|
+
// ---------------------------------------------------------------------------
|
|
240
|
+
/**
|
|
241
|
+
* Requirements the deployment path resolves before it materializes a graph.
|
|
242
|
+
*
|
|
243
|
+
* A module that renders a capability-gated resource registers its requirement
|
|
244
|
+
* on load; the direct deployment path resolves whatever is registered against
|
|
245
|
+
* the cluster it is about to deploy to. Keeping the list here rather than in
|
|
246
|
+
* the deployment layer is what stops the engine from having to know about any
|
|
247
|
+
* particular kind.
|
|
248
|
+
*/
|
|
249
|
+
const deployTimeRequirements = new Map();
|
|
250
|
+
/** Register a requirement to be resolved before each deployment. Idempotent. */
|
|
251
|
+
export function registerDeployTimeCapability(requirement) {
|
|
252
|
+
deployTimeRequirements.set(requirement.id, requirement);
|
|
253
|
+
}
|
|
254
|
+
/** Every registered deploy-time requirement. */
|
|
255
|
+
export function listDeployTimeCapabilities() {
|
|
256
|
+
return [...deployTimeRequirements.values()];
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Resolve every registered requirement against a cluster and return that
|
|
260
|
+
* cluster's identity, or `undefined` when the config names no cluster (nothing
|
|
261
|
+
* was resolved, and callers must treat every capability as unavailable).
|
|
262
|
+
*
|
|
263
|
+
* Resolution failures are not fatal: a requirement that cannot be resolved
|
|
264
|
+
* comes back `unknown`, which makes the caller skip the resource just as
|
|
265
|
+
* `unserved` does — the whole point of the seam is that an unverified API is
|
|
266
|
+
* never assumed to be present. The two are kept distinct so the caller can say
|
|
267
|
+
* which happened rather than blaming the cluster for a network error.
|
|
268
|
+
*/
|
|
269
|
+
export async function resolveDeployTimeCapabilities(kubeConfig, options = {}) {
|
|
270
|
+
const clusterId = clusterIdentity(kubeConfig);
|
|
271
|
+
if (!clusterId)
|
|
272
|
+
return undefined;
|
|
273
|
+
const requirements = listDeployTimeCapabilities();
|
|
274
|
+
if (requirements.length === 0)
|
|
275
|
+
return clusterId;
|
|
276
|
+
const discovery = options.discovery ?? kubeConfigApiGroupDiscovery(kubeConfig);
|
|
277
|
+
for (const requirement of requirements) {
|
|
278
|
+
await resolveClusterCapability(requirement, { clusterId, discovery });
|
|
279
|
+
}
|
|
280
|
+
return clusterId;
|
|
281
|
+
}
|
|
282
|
+
// ---------------------------------------------------------------------------
|
|
283
|
+
// Deploy target context
|
|
284
|
+
// ---------------------------------------------------------------------------
|
|
285
|
+
const DEPLOY_TARGET = new AsyncLocalStorage();
|
|
286
|
+
/**
|
|
287
|
+
* Run `fn` with `clusterId` published as the cluster this deployment targets.
|
|
288
|
+
*
|
|
289
|
+
* Synchronous code inside — notably a composition body re-executed at deploy
|
|
290
|
+
* time — can then read capabilities resolved for exactly that cluster. Nested
|
|
291
|
+
* and concurrent deployments to different clusters do not see each other's
|
|
292
|
+
* target.
|
|
293
|
+
*/
|
|
294
|
+
export function runWithDeployTarget(clusterId, fn) {
|
|
295
|
+
return DEPLOY_TARGET.run(clusterId, fn);
|
|
296
|
+
}
|
|
297
|
+
/** The cluster the current deployment targets, if any. */
|
|
298
|
+
export function getCurrentDeployTarget() {
|
|
299
|
+
return DEPLOY_TARGET.getStore();
|
|
300
|
+
}
|
|
301
|
+
//# sourceMappingURL=api-capability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-capability.js","sourceRoot":"","sources":["../../../src/core/kubernetes/api-capability.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
* - Error handling utilities for consistent error management
|
|
9
9
|
*/
|
|
10
10
|
export { KubernetesApi } from './api.js';
|
|
11
|
+
export type { ApiGroupDiscovery, ApiGroupProbe, ClusterCapabilityRequirement, ClusterCapabilityResolution, DiscoveryFailure, } from './api-capability.js';
|
|
12
|
+
export { CLUSTER_CAPABILITY_CACHE_MAX_ENTRIES, CLUSTER_CAPABILITY_CACHE_TTL_MS, CLUSTER_CAPABILITY_UNKNOWN_CACHE_TTL_MS, clusterCapabilityCacheSize, clusterIdentity, getCachedClusterCapability, getCurrentDeployTarget, kubeConfigApiGroupDiscovery, listDeployTimeCapabilities, registerDeployTimeCapability, resetClusterCapabilityCache, resolveClusterCapability, resolveDeployTimeCapabilities, runWithDeployTarget, } from './api-capability.js';
|
|
11
13
|
export { createBunCompatibleApiClient, createBunCompatibleApiextensionsV1Api, createBunCompatibleAppsV1Api, createBunCompatibleBatchV1Api, createBunCompatibleCoreV1Api, createBunCompatibleCustomObjectsApi, createBunCompatibleKubernetesObjectApi, createBunCompatibleNetworkingV1Api, createBunCompatibleRbacAuthorizationV1Api, createBunCompatibleStorageV1Api, } from './bun-api-client.js';
|
|
12
14
|
export type { HttpTimeoutConfig } from './bun-http-library.js';
|
|
13
15
|
export { BunCompatibleHttpLibrary, getHttpLibraryForRuntime, isBunRuntime, } from './bun-http-library.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/kubernetes/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EACL,4BAA4B,EAC5B,qCAAqC,EACrC,4BAA4B,EAC5B,6BAA6B,EAC7B,4BAA4B,EAC5B,mCAAmC,EACnC,sCAAsC,EACtC,kCAAkC,EAClC,yCAAyC,EACzC,+BAA+B,GAChC,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAI/D,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,YAAY,GACb,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,wBAAwB,EACxB,kBAAkB,EAClB,2BAA2B,EAC3B,4BAA4B,EAC5B,qBAAqB,EACrB,sBAAsB,EACtB,YAAY,GACb,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,8BAA8B,EAC9B,4CAA4C,EAC5C,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,OAAO,EACP,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/kubernetes/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,YAAY,EACV,iBAAiB,EACjB,aAAa,EACb,4BAA4B,EAC5B,2BAA2B,EAC3B,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,oCAAoC,EACpC,+BAA+B,EAC/B,uCAAuC,EACvC,0BAA0B,EAC1B,eAAe,EACf,0BAA0B,EAC1B,sBAAsB,EACtB,2BAA2B,EAC3B,0BAA0B,EAC1B,4BAA4B,EAC5B,2BAA2B,EAC3B,wBAAwB,EACxB,6BAA6B,EAC7B,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,4BAA4B,EAC5B,qCAAqC,EACrC,4BAA4B,EAC5B,6BAA6B,EAC7B,4BAA4B,EAC5B,mCAAmC,EACnC,sCAAsC,EACtC,kCAAkC,EAClC,yCAAyC,EACzC,+BAA+B,GAChC,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAI/D,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,YAAY,GACb,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,wBAAwB,EACxB,kBAAkB,EAClB,2BAA2B,EAC3B,4BAA4B,EAC5B,qBAAqB,EACrB,sBAAsB,EACtB,YAAY,GACb,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,8BAA8B,EAC9B,4CAA4C,EAC5C,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,OAAO,EACP,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC"}
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
// API utilities
|
|
11
11
|
export { KubernetesApi } from './api.js';
|
|
12
|
+
// Cluster API capability resolution — group versions are discovered, never assumed
|
|
13
|
+
export { CLUSTER_CAPABILITY_CACHE_MAX_ENTRIES, CLUSTER_CAPABILITY_CACHE_TTL_MS, CLUSTER_CAPABILITY_UNKNOWN_CACHE_TTL_MS, clusterCapabilityCacheSize, clusterIdentity, getCachedClusterCapability, getCurrentDeployTarget, kubeConfigApiGroupDiscovery, listDeployTimeCapabilities, registerDeployTimeCapability, resetClusterCapabilityCache, resolveClusterCapability, resolveDeployTimeCapabilities, runWithDeployTarget, } from './api-capability.js';
|
|
12
14
|
export { createBunCompatibleApiClient, createBunCompatibleApiextensionsV1Api, createBunCompatibleAppsV1Api, createBunCompatibleBatchV1Api, createBunCompatibleCoreV1Api, createBunCompatibleCustomObjectsApi, createBunCompatibleKubernetesObjectApi, createBunCompatibleNetworkingV1Api, createBunCompatibleRbacAuthorizationV1Api, createBunCompatibleStorageV1Api, } from './bun-api-client.js';
|
|
13
15
|
// Bun compatibility utilities
|
|
14
16
|
// These provide workarounds for Bun's fetch TLS issues
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/kubernetes/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,gBAAgB;AAChB,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/kubernetes/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,gBAAgB;AAChB,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAQzC,mFAAmF;AACnF,OAAO,EACL,oCAAoC,EACpC,+BAA+B,EAC/B,uCAAuC,EACvC,0BAA0B,EAC1B,eAAe,EACf,0BAA0B,EAC1B,sBAAsB,EACtB,2BAA2B,EAC3B,0BAA0B,EAC1B,4BAA4B,EAC5B,2BAA2B,EAC3B,wBAAwB,EACxB,6BAA6B,EAC7B,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,4BAA4B,EAC5B,qCAAqC,EACrC,4BAA4B,EAC5B,6BAA6B,EAC7B,4BAA4B,EAC5B,mCAAmC,EACnC,sCAAsC,EACtC,kCAAkC,EAClC,yCAAyC,EACzC,+BAA+B,GAChC,MAAM,qBAAqB,CAAC;AAE7B,8BAA8B;AAC9B,uDAAuD;AACvD,mDAAmD;AACnD,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,YAAY,GACb,MAAM,uBAAuB,CAAC;AAU/B,oCAAoC;AACpC,OAAO,EACL,8BAA8B,EAC9B,4CAA4C,EAC5C,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,sBAAsB,CAAC;AAE9B,2BAA2B;AAC3B,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAKrB,cAAc;AACd,OAAO,EACL,OAAO,EACP,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kubernetes and Helm name-length limits, and the derivation that turns them
|
|
3
|
+
* into a bound on the name a caller hands a composition.
|
|
4
|
+
*
|
|
5
|
+
* A composition rarely uses `spec.name` verbatim and nothing else: it — or the
|
|
6
|
+
* chart it installs, or a controller downstream of it — derives further object
|
|
7
|
+
* names from it by appending a suffix (`<name>-udp`) or by counting up from it
|
|
8
|
+
* (`<name>-<ordinal>`). Each of those derived names has to satisfy a limit of
|
|
9
|
+
* its own, so the real bound on `spec.name` is `min(limit - reserved)` across
|
|
10
|
+
* every name the composition can produce.
|
|
11
|
+
*
|
|
12
|
+
* Writing that minimum into a schema as a literal (`'string <= 40'`) hides
|
|
13
|
+
* which name produced it, so nobody can tell whether the number is still right
|
|
14
|
+
* after a chart bump adds a longer suffix. {@link deriveNameLengthLimit} takes
|
|
15
|
+
* the derived names instead and computes the bound, keeping the reasoning in
|
|
16
|
+
* the source and putting the binding constraint into the validation message.
|
|
17
|
+
*
|
|
18
|
+
* **Only names that can actually FAIL belong in a derivation.** A name the API
|
|
19
|
+
* server produces through `metadata.generateName` — a ReplicaSet's Pods, a
|
|
20
|
+
* Job's Pods — cannot fail on a long prefix: the generator truncates the base
|
|
21
|
+
* to `MaxGeneratedNameLength = 63 - 5` before appending its random suffix, so
|
|
22
|
+
* the result is always within the limit no matter how long the prefix was. See
|
|
23
|
+
* `staging/src/k8s.io/apiserver/pkg/storage/names/generate.go` in
|
|
24
|
+
* kubernetes/kubernetes. Reserving room for a suffix Kubernetes will truncate
|
|
25
|
+
* anyway only makes the schema reject names that would have worked.
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* RFC 1123 (and RFC 1035) DNS label limit.
|
|
29
|
+
*
|
|
30
|
+
* The ceiling for a Service name, for the hostname a Pod gets from its name,
|
|
31
|
+
* and for every `metadata.name` a controller turns into a label.
|
|
32
|
+
*/
|
|
33
|
+
export declare const DNS_LABEL_MAX_LENGTH = 63;
|
|
34
|
+
/**
|
|
35
|
+
* RFC 1123 DNS subdomain limit — the general `metadata.name` ceiling for
|
|
36
|
+
* objects whose names are not required to be labels.
|
|
37
|
+
*/
|
|
38
|
+
export declare const DNS_SUBDOMAIN_MAX_LENGTH = 253;
|
|
39
|
+
/**
|
|
40
|
+
* Helm's release-name limit (`releaseNameMaxLen`, `helm.sh/helm/v3/pkg/action`).
|
|
41
|
+
*
|
|
42
|
+
* Tighter than the DNS label limit because Helm reserves room for the suffixes
|
|
43
|
+
* it appends to a release's own bookkeeping Secrets
|
|
44
|
+
* (`sh.helm.release.v1.<release>.v<revision>`).
|
|
45
|
+
*/
|
|
46
|
+
export declare const HELM_RELEASE_NAME_MAX_LENGTH = 53;
|
|
47
|
+
/** One name a composition derives from the name its caller supplies. */
|
|
48
|
+
export interface GeneratedNameConstraint {
|
|
49
|
+
/**
|
|
50
|
+
* What the derived name is and who generates it, e.g.
|
|
51
|
+
* `'<name>-udp (the chart\'s UDP Service)'`. Quoted in the validation
|
|
52
|
+
* message when this constraint is the binding one.
|
|
53
|
+
*/
|
|
54
|
+
readonly describedAs: string;
|
|
55
|
+
/** Literal suffix appended to the caller's name. Omit when there is none. */
|
|
56
|
+
readonly suffix?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Characters a controller appends on top of {@link suffix} that are not a
|
|
59
|
+
* literal — a StatefulSet ordinal, a revision counter, a timestamp.
|
|
60
|
+
*
|
|
61
|
+
* Count characters only where an over-long result would be REJECTED. Names
|
|
62
|
+
* the API server builds with `metadata.generateName` do not qualify: its
|
|
63
|
+
* generator truncates the base to `MaxGeneratedNameLength = 63 - 5` first
|
|
64
|
+
* (`staging/src/k8s.io/apiserver/pkg/storage/names/generate.go`), so those
|
|
65
|
+
* names always fit and reserving for them only over-constrains the caller.
|
|
66
|
+
*/
|
|
67
|
+
readonly generatedChars?: number;
|
|
68
|
+
/** Length limit the derived name has to satisfy. */
|
|
69
|
+
readonly limit: number;
|
|
70
|
+
}
|
|
71
|
+
/** The bound {@link deriveNameLengthLimit} computed, and why. */
|
|
72
|
+
export interface DerivedNameLimit {
|
|
73
|
+
/** Longest name a caller may supply. */
|
|
74
|
+
readonly maxLength: number;
|
|
75
|
+
/** The constraint that produced {@link maxLength}. */
|
|
76
|
+
readonly binding: GeneratedNameConstraint;
|
|
77
|
+
/**
|
|
78
|
+
* Validation message naming the limit and the constraint behind it, ready to
|
|
79
|
+
* hand to ArkType's `.configure({ message })`.
|
|
80
|
+
*/
|
|
81
|
+
readonly message: string;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Compute the longest name a caller may supply, given every name derived from
|
|
85
|
+
* it.
|
|
86
|
+
*
|
|
87
|
+
* Ties go to the constraint declared first, so list the constraints in the
|
|
88
|
+
* order a reader should meet them.
|
|
89
|
+
*
|
|
90
|
+
* @param constraints - Every name the composition (or its chart, or a
|
|
91
|
+
* controller downstream of it) derives from the caller's name. Include the
|
|
92
|
+
* bare name itself as a constraint with no suffix wherever it is used as-is
|
|
93
|
+
* under a limit of its own — a Helm release name, say.
|
|
94
|
+
* @returns The bound, the constraint that produced it, and a message naming
|
|
95
|
+
* both.
|
|
96
|
+
* @throws If `constraints` is empty, or if a constraint reserves at least as
|
|
97
|
+
* many characters as its own limit, which would leave no name at all.
|
|
98
|
+
*/
|
|
99
|
+
export declare function deriveNameLengthLimit(constraints: readonly GeneratedNameConstraint[]): DerivedNameLimit;
|
|
100
|
+
//# sourceMappingURL=naming.d.ts.map
|