typekro 0.34.0 → 0.36.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/alchemy/clickhouse-schema/executor.d.ts +25 -0
- package/dist/alchemy/clickhouse-schema/executor.d.ts.map +1 -0
- package/dist/alchemy/clickhouse-schema/executor.js +144 -0
- package/dist/alchemy/clickhouse-schema/executor.js.map +1 -0
- package/dist/alchemy/clickhouse-schema/index.d.ts +12 -0
- package/dist/alchemy/clickhouse-schema/index.d.ts.map +1 -0
- package/dist/alchemy/clickhouse-schema/index.js +11 -0
- package/dist/alchemy/clickhouse-schema/index.js.map +1 -0
- package/dist/alchemy/clickhouse-schema/resource.d.ts +54 -0
- package/dist/alchemy/clickhouse-schema/resource.d.ts.map +1 -0
- package/dist/alchemy/clickhouse-schema/resource.js +158 -0
- package/dist/alchemy/clickhouse-schema/resource.js.map +1 -0
- package/dist/alchemy/clickhouse-schema/runner.d.ts +154 -0
- package/dist/alchemy/clickhouse-schema/runner.d.ts.map +1 -0
- package/dist/alchemy/clickhouse-schema/runner.js +613 -0
- package/dist/alchemy/clickhouse-schema/runner.js.map +1 -0
- package/dist/alchemy/clickhouse-schema/sql.d.ts +109 -0
- package/dist/alchemy/clickhouse-schema/sql.d.ts.map +1 -0
- package/dist/alchemy/clickhouse-schema/sql.js +368 -0
- package/dist/alchemy/clickhouse-schema/sql.js.map +1 -0
- package/dist/alchemy/clickhouse-schema/types.d.ts +394 -0
- package/dist/alchemy/clickhouse-schema/types.d.ts.map +1 -0
- package/dist/alchemy/clickhouse-schema/types.js +370 -0
- package/dist/alchemy/clickhouse-schema/types.js.map +1 -0
- package/dist/alchemy/index.d.ts +1 -0
- package/dist/alchemy/index.d.ts.map +1 -1
- package/dist/alchemy/index.js +2 -0
- package/dist/alchemy/index.js.map +1 -1
- package/dist/alchemy/kro-delete.d.ts +7 -0
- package/dist/alchemy/kro-delete.d.ts.map +1 -1
- package/dist/alchemy/kro-delete.js +28 -4
- package/dist/alchemy/kro-delete.js.map +1 -1
- package/dist/alchemy/resource-registration.d.ts +9 -2
- package/dist/alchemy/resource-registration.d.ts.map +1 -1
- package/dist/alchemy/resource-registration.js +117 -33
- package/dist/alchemy/resource-registration.js.map +1 -1
- package/dist/core/deployment/k8s-helpers.d.ts +77 -1
- package/dist/core/deployment/k8s-helpers.d.ts.map +1 -1
- package/dist/core/deployment/k8s-helpers.js +298 -17
- package/dist/core/deployment/k8s-helpers.js.map +1 -1
- package/dist/core/deployment/kro-artifact-binding-migration.d.ts +17 -6
- package/dist/core/deployment/kro-artifact-binding-migration.d.ts.map +1 -1
- package/dist/core/deployment/kro-artifact-binding-migration.js +16 -2
- package/dist/core/deployment/kro-artifact-binding-migration.js.map +1 -1
- package/dist/core/deployment/kro-namespace-teardown.d.ts +15 -1
- package/dist/core/deployment/kro-namespace-teardown.d.ts.map +1 -1
- package/dist/core/deployment/kro-namespace-teardown.js +34 -9
- package/dist/core/deployment/kro-namespace-teardown.js.map +1 -1
- package/dist/core/deployment/kro-readiness.d.ts +35 -0
- package/dist/core/deployment/kro-readiness.d.ts.map +1 -1
- package/dist/core/deployment/kro-readiness.js +201 -25
- package/dist/core/deployment/kro-readiness.js.map +1 -1
- package/dist/core/deployment/poll-timeout.d.ts +80 -2
- package/dist/core/deployment/poll-timeout.d.ts.map +1 -1
- package/dist/core/deployment/poll-timeout.js +164 -4
- package/dist/core/deployment/poll-timeout.js.map +1 -1
- package/dist/core/kubernetes/bun-http-library.d.ts +24 -0
- package/dist/core/kubernetes/bun-http-library.d.ts.map +1 -1
- package/dist/core/kubernetes/bun-http-library.js +146 -19
- package/dist/core/kubernetes/bun-http-library.js.map +1 -1
- package/dist/core/kubernetes/errors.d.ts +9 -0
- package/dist/core/kubernetes/errors.d.ts.map +1 -1
- package/dist/core/kubernetes/errors.js +7 -3
- package/dist/core/kubernetes/errors.js.map +1 -1
- package/dist/factories/clickhouse/compositions/clickhouse-cluster.d.ts +24 -2
- package/dist/factories/clickhouse/compositions/clickhouse-cluster.d.ts.map +1 -1
- package/dist/factories/clickhouse/compositions/clickhouse-cluster.js +24 -2
- package/dist/factories/clickhouse/compositions/clickhouse-cluster.js.map +1 -1
- package/dist/factories/clickhouse/resources/keeper.d.ts +61 -0
- package/dist/factories/clickhouse/resources/keeper.d.ts.map +1 -1
- package/dist/factories/clickhouse/resources/keeper.js +216 -2
- package/dist/factories/clickhouse/resources/keeper.js.map +1 -1
- package/dist/factories/clickhouse/resources/s3-backup.d.ts.map +1 -1
- package/dist/factories/clickhouse/resources/s3-backup.js +4 -3
- package/dist/factories/clickhouse/resources/s3-backup.js.map +1 -1
- package/dist/factories/clickhouse/types.d.ts +3 -2
- package/dist/factories/clickhouse/types.d.ts.map +1 -1
- package/dist/factories/clickhouse/types.js +28 -1
- package/dist/factories/clickhouse/types.js.map +1 -1
- package/dist/factories/clickhouse/utils/validation.d.ts +133 -10
- package/dist/factories/clickhouse/utils/validation.d.ts.map +1 -1
- package/dist/factories/clickhouse/utils/validation.js +165 -18
- package/dist/factories/clickhouse/utils/validation.js.map +1 -1
- package/dist/factories/clickstack/compositions/clickstack-bootstrap.d.ts +15 -1
- package/dist/factories/clickstack/compositions/clickstack-bootstrap.d.ts.map +1 -1
- package/dist/factories/clickstack/compositions/clickstack-bootstrap.js +15 -1
- package/dist/factories/clickstack/compositions/clickstack-bootstrap.js.map +1 -1
- package/dist/factories/rook/types.d.ts +16 -16
- package/package.json +1 -1
|
@@ -10,9 +10,10 @@
|
|
|
10
10
|
* - Custom status fields populated from the RGD status schema
|
|
11
11
|
*/
|
|
12
12
|
import { DEFAULT_FAST_POLL_INTERVAL, DEFAULT_HTTP_READ_TIMEOUT, DEFAULT_POLL_INTERVAL, } from '../config/defaults.js';
|
|
13
|
-
import { CRDInstanceError, DeploymentTimeoutError
|
|
13
|
+
import { CRDInstanceError, DeploymentTimeoutError } from '../errors.js';
|
|
14
14
|
import { getComponentLogger } from '../logging/index.js';
|
|
15
|
-
import {
|
|
15
|
+
import { classifyReadError } from './k8s-helpers.js';
|
|
16
|
+
import { callWithTimeout, perCallTimeout } from './poll-timeout.js';
|
|
16
17
|
function abortableDelay(ms, abortSignal) {
|
|
17
18
|
abortSignal?.throwIfAborted();
|
|
18
19
|
if (!abortSignal)
|
|
@@ -29,6 +30,23 @@ function abortableDelay(ms, abortSignal) {
|
|
|
29
30
|
abortSignal.addEventListener('abort', onAbort, { once: true });
|
|
30
31
|
});
|
|
31
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Sleep between polls WITHOUT overshooting the caller's deadline.
|
|
35
|
+
*
|
|
36
|
+
* A bare `abortableDelay(pollInterval)` can carry the wait up to a full poll interval PAST the
|
|
37
|
+
* declared `timeout` — a 5s budget polled every 2s could return at 7s — because the `while`
|
|
38
|
+
* condition is only re-checked after the sleep has already run to completion. Capping the sleep to
|
|
39
|
+
* whatever is left of the budget keeps the declared timeout the real upper bound, so a caller that
|
|
40
|
+
* sizes a deploy against it is not silently given more time than it asked for.
|
|
41
|
+
*
|
|
42
|
+
* @returns `false` when the budget is already spent, meaning the caller should stop polling.
|
|
43
|
+
*/
|
|
44
|
+
async function delayWithinBudget(ms, remaining, abortSignal) {
|
|
45
|
+
if (remaining <= 0)
|
|
46
|
+
return false;
|
|
47
|
+
await abortableDelay(Math.min(ms, remaining), abortSignal);
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
32
50
|
/**
|
|
33
51
|
* Wait for a Kro custom resource instance to become ready.
|
|
34
52
|
*
|
|
@@ -38,6 +56,41 @@ function abortableDelay(ms, abortSignal) {
|
|
|
38
56
|
* and has observed the current instance generation when KRO reports generations
|
|
39
57
|
* 3. Either custom status fields are populated OR the RGD declares no status schema
|
|
40
58
|
*
|
|
59
|
+
* A TERMINAL instance state (`FAILED`/`ERROR`) is checked first, on the instance read alone, before
|
|
60
|
+
* the RGD lookup below, and only when the failure evidence belongs to the CURRENT
|
|
61
|
+
* `metadata.generation` — Kubernetes keeps the status subresource across spec updates, so on an
|
|
62
|
+
* update the previous deployment's verdict can still be on the object while the new generation is
|
|
63
|
+
* about to reconcile. A current terminal state carries the most actionable message this function can
|
|
64
|
+
* return and must not be buried behind lookup retries; a stale one is history and falls through to
|
|
65
|
+
* normal polling, still bounded by the overall deadline.
|
|
66
|
+
*
|
|
67
|
+
* RGD STATUS-SCHEMA LOOKUP POLICY. Step 3 needs the ResourceGraphDefinition's declared status schema.
|
|
68
|
+
* An UNCERTAIN read of that schema is never converted into an EMPTY schema: "we did not learn what
|
|
69
|
+
* this instance's status should contain" must not become "this instance has no custom status", which
|
|
70
|
+
* is what declares an ACTIVE/synced instance ready without validating any of its expected fields.
|
|
71
|
+
* Being uncertain is not, however, a reason to retry forever. Failures are classified with the
|
|
72
|
+
* repo's shared retry policy, {@link classifyReadError}:
|
|
73
|
+
*
|
|
74
|
+
* - RETRYABLE — `object-not-found` (the RGD is missing or not yet created) and `transient` (5xx,
|
|
75
|
+
* rate limiting, a wedged request, a dropped socket, a DNS blip) — ABANDONS the iteration: neither
|
|
76
|
+
* ready nor permissive. The loop polls again, so the caller's overall `timeout` stays the single
|
|
77
|
+
* authority on how long to keep trying, and one blip is ridden out rather than failing the deploy.
|
|
78
|
+
* A lookup that never succeeds simply never satisfies step 3, and the wait ends in the overall
|
|
79
|
+
* {@link DeploymentTimeoutError}, whose message carries the last lookup failure so the diagnosis
|
|
80
|
+
* is not lost.
|
|
81
|
+
* - DETERMINISTIC — `permission-denied` (401/403), `unknown-resource-type` (the RGD API resource is
|
|
82
|
+
* not served), `invalid-request` (400/405/422), `tls-configuration-error` (an expired, self-signed
|
|
83
|
+
* or misnamed server certificate, an untrusted CA) and `not-a-kubernetes-error` (a `TypeError`
|
|
84
|
+
* from a programming bug, a client signature mismatch) — FAILS FAST with the original error. Each reads
|
|
85
|
+
* identically on every attempt, so polling it only spends the budget and then reports a timeout
|
|
86
|
+
* that hides the real cause. RBAC is the canonical member: every other 401/403 in this codebase,
|
|
87
|
+
* including the instance read in this same loop, already fails fast.
|
|
88
|
+
*
|
|
89
|
+
* `object-not-found` is strict rather than permissive for the same reason the whole policy is: the
|
|
90
|
+
* RGD name this poll looks up is the name the compiler emitted
|
|
91
|
+
* (`convertToKubernetesName(composition.name)`, threaded through the deployment plan), so a 404
|
|
92
|
+
* means the RGD is missing or not yet created, not that the instance has no status schema.
|
|
93
|
+
*
|
|
41
94
|
* @throws {CRDInstanceError} if the instance enters a FAILED or ERROR state
|
|
42
95
|
* @throws {DeploymentTimeoutError} if the timeout is exceeded
|
|
43
96
|
*/
|
|
@@ -46,8 +99,32 @@ export async function waitForKroInstanceReady(options) {
|
|
|
46
99
|
const logger = getComponentLogger('kro-readiness');
|
|
47
100
|
const readinessLogger = logger.child({ instanceName, rgdName });
|
|
48
101
|
const startTime = Date.now();
|
|
102
|
+
/**
|
|
103
|
+
* The last RGD status-schema lookup that failed and was retried, as `classifyReadError`'s
|
|
104
|
+
* Kubernetes-aware `detail`. Folded into the overall timeout message: without it a persistently
|
|
105
|
+
* wedged lookup reports only "not ready in time" and the actionable diagnosis (a wedged request /
|
|
106
|
+
* a premature close, and its cause) is lost.
|
|
107
|
+
*
|
|
108
|
+
* The DETAIL rather than `ensureError(error).message`, because the client surfaces a Status-shaped
|
|
109
|
+
* rejection as a bare object: `ensureError({ statusCode: 503, body: { message: … } })` stringifies
|
|
110
|
+
* to `[object Object]`, which would put exactly that in the deadline diagnosis. `detail` falls
|
|
111
|
+
* back through the Status body and the formatted API error instead.
|
|
112
|
+
*/
|
|
113
|
+
let lastLookupDetail;
|
|
114
|
+
/** The error object behind {@link lastLookupDetail}, attached to the deadline error as its cause. */
|
|
115
|
+
let lastLookupCause;
|
|
116
|
+
/** Lookup failure messages already logged, so a retry loop warns once per distinct message. */
|
|
117
|
+
const warnedLookupFailures = new Set();
|
|
49
118
|
while (Date.now() - startTime < timeout) {
|
|
50
119
|
abortSignal?.throwIfAborted();
|
|
120
|
+
/**
|
|
121
|
+
* Set immediately before the RGD status-schema lookup re-throws a DETERMINISTIC failure, so the
|
|
122
|
+
* catch below lets it out. That catch's job is to swallow a 404 on the INSTANCE read ("not
|
|
123
|
+
* created yet, keep waiting"); without this flag it would also swallow the lookup's own
|
|
124
|
+
* fail-fast 404 — the one that means the ResourceGraphDefinition API resource is not served at
|
|
125
|
+
* all — and poll to the deadline on an error that can never change.
|
|
126
|
+
*/
|
|
127
|
+
let fatalLookupError = false;
|
|
51
128
|
try {
|
|
52
129
|
// Bound the read so a wedged/expired kubeconfig exec credential rejects (and is re-thrown below)
|
|
53
130
|
// instead of hanging the poll forever — see poll-timeout.ts. A ≤0 budget means the deadline is
|
|
@@ -69,15 +146,59 @@ export async function waitForKroInstanceReady(options) {
|
|
|
69
146
|
const status = instance.status;
|
|
70
147
|
if (!status) {
|
|
71
148
|
readinessLogger.debug('No status found yet, continuing to wait', { instanceName });
|
|
72
|
-
await
|
|
149
|
+
if (!(await delayWithinBudget(DEFAULT_POLL_INTERVAL, timeout - (Date.now() - startTime), abortSignal))) {
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
73
152
|
continue;
|
|
74
153
|
}
|
|
75
154
|
const state = status.state;
|
|
76
155
|
const conditions = status.conditions || [];
|
|
156
|
+
const generation = instance.metadata?.generation;
|
|
157
|
+
// TERMINAL STATE IS CHECKED FIRST, BEFORE ANY RGD LOOKUP — BUT ONLY WHEN IT IS CURRENT.
|
|
158
|
+
//
|
|
159
|
+
// Kro v0.8.x uses "ERROR", v0.3.x uses "FAILED". Either way the instance is done: no amount of
|
|
160
|
+
// further polling changes it, and the condition message is the single most actionable thing
|
|
161
|
+
// this function can hand the caller. The check therefore runs on the instance read alone —
|
|
162
|
+
// the RGD status-schema lookup below cannot make a failed instance succeed, and under the
|
|
163
|
+
// strict lookup policy (every non-retryable failure fails fast, everything else retries) a
|
|
164
|
+
// lookup that is itself broken would otherwise bury this message behind retries until the
|
|
165
|
+
// deadline, turning a precise CRDInstanceError into a generic DeploymentTimeoutError.
|
|
166
|
+
//
|
|
167
|
+
// GENERATION AWARENESS. Kubernetes keeps the status subresource across spec updates, so on an
|
|
168
|
+
// UPDATE the very first read can legitimately return `generation: 7` alongside the PREVIOUS
|
|
169
|
+
// deployment's verdict — `state: FAILED`, `Ready=False` with `observedGeneration: 6` and that
|
|
170
|
+
// deployment's message — while generation 7 is about to reconcile perfectly well. KRO
|
|
171
|
+
// documents `observedGeneration < metadata.generation` as "not yet processed", so a terminal
|
|
172
|
+
// state is only authoritative when the failure evidence is current: a `False` condition that
|
|
173
|
+
// has observed this generation. Absent that evidence the state is stale history; it falls
|
|
174
|
+
// through to normal polling and the outer deadline still bounds the wait.
|
|
175
|
+
//
|
|
176
|
+
// Backward compatible by construction: an instance with no `metadata.generation`, or
|
|
177
|
+
// conditions from an older KRO that carry no `observedGeneration` at all, has no way to be
|
|
178
|
+
// stale, so the terminal state stays authoritative exactly as before.
|
|
179
|
+
if (state === 'FAILED' || state === 'ERROR') {
|
|
180
|
+
const failedCondition = conditions.find((c) => c.status === 'False' &&
|
|
181
|
+
(generation === undefined ||
|
|
182
|
+
c.observedGeneration === undefined ||
|
|
183
|
+
c.observedGeneration >= generation));
|
|
184
|
+
const hasGenerationAwareConditions = conditions.some((c) => c.observedGeneration !== undefined);
|
|
185
|
+
const terminalStateIsCurrent = failedCondition !== undefined ||
|
|
186
|
+
generation === undefined ||
|
|
187
|
+
!hasGenerationAwareConditions;
|
|
188
|
+
if (terminalStateIsCurrent) {
|
|
189
|
+
const errorMessage = failedCondition?.message || 'Unknown error';
|
|
190
|
+
throw new CRDInstanceError(`Kro instance deployment failed (state=${state}): ${errorMessage}`, apiVersion, kind, instanceName, 'creation');
|
|
191
|
+
}
|
|
192
|
+
readinessLogger.debug('Terminal state belongs to an earlier generation — treating it as stale and continuing to poll', {
|
|
193
|
+
instanceName,
|
|
194
|
+
state,
|
|
195
|
+
generation,
|
|
196
|
+
conditionObservedGenerations: conditions.map((c) => c.observedGeneration),
|
|
197
|
+
});
|
|
198
|
+
}
|
|
77
199
|
// Support both Kro v0.3.x (InstanceSynced) and v0.8.x (Ready) conditions
|
|
78
200
|
const syncedCondition = conditions.find((c) => c.type === 'InstanceSynced');
|
|
79
201
|
const readyCondition = conditions.find((c) => c.type === 'Ready');
|
|
80
|
-
const generation = instance.metadata?.generation;
|
|
81
202
|
const conditionIsCurrent = (condition) => condition?.status === 'True' &&
|
|
82
203
|
(generation === undefined ||
|
|
83
204
|
condition.observedGeneration === undefined ||
|
|
@@ -107,6 +228,11 @@ export async function waitForKroInstanceReady(options) {
|
|
|
107
228
|
const rgdStatusSchema = rgd.spec?.schema?.status ?? {};
|
|
108
229
|
expectedStatusKeys = Object.keys(rgdStatusSchema).filter((key) => !basicKroFields.includes(key));
|
|
109
230
|
expectedCustomStatusFields = expectedStatusKeys.length > 0;
|
|
231
|
+
// The schema HAS now been read, so any earlier failure is spent history. Leaving it set
|
|
232
|
+
// would misattribute a later timeout — one caused by the projected status never becoming
|
|
233
|
+
// ready — to a lookup that has since been answered.
|
|
234
|
+
lastLookupDetail = undefined;
|
|
235
|
+
lastLookupCause = undefined;
|
|
110
236
|
readinessLogger.debug('ResourceGraphDefinition status schema check', {
|
|
111
237
|
rgdName,
|
|
112
238
|
rgdStatusKeys: expectedStatusKeys,
|
|
@@ -114,19 +240,60 @@ export async function waitForKroInstanceReady(options) {
|
|
|
114
240
|
});
|
|
115
241
|
}
|
|
116
242
|
catch (error) {
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
|
|
243
|
+
// An UNCERTAIN read must never be converted into an empty schema. The old code fell through
|
|
244
|
+
// to `expectedCustomStatusFields = false` — "the RGD declares no custom status" — for every
|
|
245
|
+
// failure alike, so any request that did not produce an answer let an ACTIVE/synced instance
|
|
246
|
+
// be declared ready WITHOUT validating the status fields it was supposed to have. The
|
|
247
|
+
// question is not which error class this is, it is whether the server actually ANSWERED.
|
|
248
|
+
//
|
|
249
|
+
// WHAT IT IS NOT is a reason to retry FOREVER. Retrying every failure alike — which is what
|
|
250
|
+
// "fail fast only on forbidden" amounted to — spends the entire readiness budget on errors
|
|
251
|
+
// that will read identically on every attempt (an HTTP 400/405/422, a client signature
|
|
252
|
+
// mismatch, a plain `TypeError` from a programming bug) and then reports a
|
|
253
|
+
// DeploymentTimeoutError that HIDES them. `classifyReadError` is the file-local retry
|
|
254
|
+
// policy this repo already applies to the same question elsewhere (see the external-
|
|
255
|
+
// reference read in `engine.ts`), so use it here rather than growing a second one:
|
|
256
|
+
// object-not-found and transient retry; unknown-resource-type, permission-denied,
|
|
257
|
+
// invalid-request and not-a-kubernetes-error fail fast with the REAL error.
|
|
258
|
+
//
|
|
259
|
+
// It is used ALONE, with no local carve-out, because it now recognises the timeout and
|
|
260
|
+
// transport shapes this loop depends on: a bare `RequestTimeoutError` from the socket timer,
|
|
261
|
+
// a `PollTimeoutError` from the deadline wrapper and a `PrematureCloseError` from a
|
|
262
|
+
// mid-response disconnect all classify as `transient` (see `classifyReadErrorKind`). One
|
|
263
|
+
// classifier, one taxonomy — a carve-out here would have to be kept in sync with it forever.
|
|
264
|
+
const assessment = classifyReadError(error);
|
|
265
|
+
if (!assessment.retryable) {
|
|
266
|
+
// RBAC (401/403) is the canonical case — the repo fails fast on it everywhere else,
|
|
267
|
+
// including the instance read in this very loop — but a malformed request or a kind the
|
|
268
|
+
// cluster does not serve is just as fixed. Waiting cannot change any of them.
|
|
269
|
+
fatalLookupError = true;
|
|
122
270
|
throw error;
|
|
123
271
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
//
|
|
129
|
-
|
|
272
|
+
// Retryable: an absent RGD (404 for the object) or a transient fault (5xx, rate limiting, a
|
|
273
|
+
// wedged request, a dropped socket). We did not learn the schema, so abandon this iteration
|
|
274
|
+
// — neither ready nor permissive — and poll again, leaving the caller's overall `timeout`
|
|
275
|
+
// as the single authority on how long to keep trying. One transient blip is what a poll
|
|
276
|
+
// loop exists to ride out; a persistent failure ends in the overall DeploymentTimeoutError,
|
|
277
|
+
// carrying this message.
|
|
278
|
+
lastLookupDetail = assessment.detail;
|
|
279
|
+
// Keep the ORIGINAL thrown value, not an `ensureError` coercion: a bare Kubernetes `Status`
|
|
280
|
+
// object would coerce to `Error('[object Object]')` and lose `statusCode` / `body` for callers.
|
|
281
|
+
lastLookupCause = error;
|
|
282
|
+
if (!warnedLookupFailures.has(lastLookupDetail)) {
|
|
283
|
+
warnedLookupFailures.add(lastLookupDetail);
|
|
284
|
+
readinessLogger.warn('ResourceGraphDefinition status-schema lookup did not produce an answer — retrying until the readiness deadline', {
|
|
285
|
+
rgdName,
|
|
286
|
+
classification: assessment.classification,
|
|
287
|
+
reason: assessment.summary,
|
|
288
|
+
error: lastLookupDetail,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
// Honour the poll interval before retrying: a premature close can reject in milliseconds,
|
|
292
|
+
// so continuing straight to the top of the loop would spin.
|
|
293
|
+
if (!(await delayWithinBudget(pollInterval, timeout - (Date.now() - startTime), abortSignal))) {
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
continue;
|
|
130
297
|
}
|
|
131
298
|
readinessLogger.debug('Kro instance status check', {
|
|
132
299
|
instanceName,
|
|
@@ -177,12 +344,6 @@ export async function waitForKroInstanceReady(options) {
|
|
|
177
344
|
});
|
|
178
345
|
return;
|
|
179
346
|
}
|
|
180
|
-
// Check for failure states (Kro v0.8.x uses "ERROR", v0.3.x uses "FAILED")
|
|
181
|
-
if (state === 'FAILED' || state === 'ERROR') {
|
|
182
|
-
const failedCondition = conditions.find((c) => c.status === 'False');
|
|
183
|
-
const errorMessage = failedCondition?.message || 'Unknown error';
|
|
184
|
-
throw new CRDInstanceError(`Kro instance deployment failed (state=${state}): ${errorMessage}`, apiVersion, kind, instanceName, 'creation');
|
|
185
|
-
}
|
|
186
347
|
readinessLogger.debug('Kro instance not ready yet, continuing to wait', {
|
|
187
348
|
instanceName,
|
|
188
349
|
state,
|
|
@@ -194,8 +355,9 @@ export async function waitForKroInstanceReady(options) {
|
|
|
194
355
|
});
|
|
195
356
|
}
|
|
196
357
|
catch (error) {
|
|
197
|
-
// Re-throw CRDInstanceError as-is
|
|
198
|
-
|
|
358
|
+
// Re-throw CRDInstanceError as-is, and likewise a deterministic RGD-lookup failure that the
|
|
359
|
+
// lookup already decided is fatal — the 404 swallow below is for the INSTANCE read only.
|
|
360
|
+
if (error instanceof CRDInstanceError || fatalLookupError) {
|
|
199
361
|
throw error;
|
|
200
362
|
}
|
|
201
363
|
const k8sError = error;
|
|
@@ -213,9 +375,23 @@ export async function waitForKroInstanceReady(options) {
|
|
|
213
375
|
readinessLogger.debug('Instance not found yet, continuing to wait', { instanceName });
|
|
214
376
|
}
|
|
215
377
|
// Wait before checking again
|
|
216
|
-
await
|
|
378
|
+
if (!(await delayWithinBudget(pollInterval, timeout - (Date.now() - startTime), abortSignal))) {
|
|
379
|
+
break;
|
|
380
|
+
}
|
|
217
381
|
}
|
|
218
382
|
const elapsed = Date.now() - startTime;
|
|
219
|
-
|
|
383
|
+
// A lookup that never succeeded is the most actionable thing known about this timeout — without it
|
|
384
|
+
// the message reports only "not ready in time" and the wedged-request diagnosis is lost. It is
|
|
385
|
+
// cleared as soon as a later lookup succeeds, so this only ever describes a lookup that was still
|
|
386
|
+
// failing when the budget ran out.
|
|
387
|
+
const lookupDiagnosis = lastLookupDetail
|
|
388
|
+
? ` The ResourceGraphDefinition status-schema lookup could not be read, so readiness could not be confirmed; its last failure was: ${lastLookupDetail}`
|
|
389
|
+
: '';
|
|
390
|
+
const timeoutError = new DeploymentTimeoutError(`Timeout waiting for Kro instance ${instanceName} to be ready after ${elapsed}ms (timeout: ${timeout}ms).${factoryContext ? ` This usually means the Kro controller is not running or the RGD deployment failed. Check Kro controller logs: kubectl logs -n kro-system deployment/kro` : ''}${lookupDiagnosis}`, kind, instanceName, timeout, 'instance-readiness');
|
|
391
|
+
// The message carries the readable detail; the original rejection stays reachable as the cause so
|
|
392
|
+
// a caller that inspects `statusCode` / `body` still can.
|
|
393
|
+
if (lastLookupCause !== undefined)
|
|
394
|
+
timeoutError.cause = lastLookupCause;
|
|
395
|
+
throw timeoutError;
|
|
220
396
|
}
|
|
221
397
|
//# sourceMappingURL=kro-readiness.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kro-readiness.js","sourceRoot":"","sources":["../../../src/core/deployment/kro-readiness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EACL,0BAA0B,EAC1B,yBAAyB,EACzB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,
|
|
1
|
+
{"version":3,"file":"kro-readiness.js","sourceRoot":"","sources":["../../../src/core/deployment/kro-readiness.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,9 +19,26 @@
|
|
|
19
19
|
* exec-auth failure mode is to avoid per-request exec auth during polling (e.g. a pre-minted bearer token
|
|
20
20
|
* in the kubeconfig), so no credential subprocess is spawned in the first place.
|
|
21
21
|
*/
|
|
22
|
-
/**
|
|
23
|
-
|
|
22
|
+
/**
|
|
23
|
+
* A Kubernetes request that did not return within its budget — whichever layer noticed first.
|
|
24
|
+
*
|
|
25
|
+
* TWO layers can time the same request out, and callers must not have to care which won. The Bun
|
|
26
|
+
* HTTP library arms its socket timer synchronously while the request is being issued; a wrapper
|
|
27
|
+
* added by {@link withCallDeadline} arms its timer afterwards. With equal budgets the socket timer
|
|
28
|
+
* therefore fires FIRST, so a gate that recognised only the wrapper's error would treat a genuine
|
|
29
|
+
* timeout as an ordinary failure — and a gate that fails OPEN on ordinary failures would silently
|
|
30
|
+
* skip its assertion. Both layers raise this type; {@link isRequestTimeoutError} recognises it.
|
|
31
|
+
*/
|
|
32
|
+
export declare class RequestTimeoutError extends Error {
|
|
24
33
|
readonly timeoutMs: number;
|
|
34
|
+
/** Structural marker, so recognition survives duplicate module instances where `instanceof` does not. */
|
|
35
|
+
readonly isRequestTimeout: true;
|
|
36
|
+
constructor(message: string, timeoutMs: number);
|
|
37
|
+
}
|
|
38
|
+
/** True for a timeout raised by EITHER timing layer — the socket's or a {@link withCallDeadline} wrapper's. */
|
|
39
|
+
export declare function isRequestTimeoutError(error: unknown): error is RequestTimeoutError;
|
|
40
|
+
/** Thrown when a readiness-poll API call exceeds its per-call budget (distinguishable so callers can fail fast vs. retry). */
|
|
41
|
+
export declare class PollTimeoutError extends RequestTimeoutError {
|
|
25
42
|
constructor(label: string, timeoutMs: number);
|
|
26
43
|
}
|
|
27
44
|
/**
|
|
@@ -42,4 +59,65 @@ export declare function callWithTimeout<T>(op: () => Promise<T>, timeoutMs: numb
|
|
|
42
59
|
* {@link callWithTimeout}.
|
|
43
60
|
*/
|
|
44
61
|
export declare function perCallTimeout(remainingMs: number, capMs: number): number;
|
|
62
|
+
/**
|
|
63
|
+
* The per-verb request budget {@link withCallDeadline} applies. Reads are expected to be quick;
|
|
64
|
+
* creates and updates may sit behind admission webhooks; deletes may wait on finalizers — the same
|
|
65
|
+
* split the repo's HTTP defaults already make, so a caller's configured `httpTimeouts` is honored
|
|
66
|
+
* per verb instead of being flattened onto the read budget. `create` and `update` are kept APART
|
|
67
|
+
* because `HttpTimeoutConfig` exposes them separately: collapsing them into one write budget makes
|
|
68
|
+
* one of the two configured values unreachable.
|
|
69
|
+
*/
|
|
70
|
+
export interface CallDeadlineBudget {
|
|
71
|
+
/** GET / LIST and anything not classified as a create, an update or a delete. */
|
|
72
|
+
readonly read: number;
|
|
73
|
+
/** POST — `create*`. */
|
|
74
|
+
readonly create: number;
|
|
75
|
+
/** PUT / PATCH — `replace*`, `patch*`, server-side apply. */
|
|
76
|
+
readonly update: number;
|
|
77
|
+
/** DELETE. */
|
|
78
|
+
readonly delete: number;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Derive a per-verb budget from a caller's {@link HttpTimeoutConfig}-shaped options, each verb
|
|
82
|
+
* capped by `capMs` (normally the deployment timeout) so one request can never outlive the
|
|
83
|
+
* operation it belongs to. Non-positive / non-finite values fall back to the repo defaults —
|
|
84
|
+
* notably `timeout: 0`, which is NOT nullish and would otherwise collapse every budget to zero.
|
|
85
|
+
*/
|
|
86
|
+
export declare function callDeadlineBudget(timeouts: {
|
|
87
|
+
readonly default?: number | undefined;
|
|
88
|
+
readonly create?: number | undefined;
|
|
89
|
+
readonly update?: number | undefined;
|
|
90
|
+
readonly delete?: number | undefined;
|
|
91
|
+
} | undefined, capMs?: number): CallDeadlineBudget;
|
|
92
|
+
/**
|
|
93
|
+
* Classify a client method by name so it is bounded by its own verb's budget, matching the split the
|
|
94
|
+
* HTTP layer already makes by method (POST → create, PUT/PATCH → update, DELETE → delete). Anything
|
|
95
|
+
* else — `read`, `list`, `get*`, `listClusterCustomObject`, and any method a future client version
|
|
96
|
+
* adds — is treated as a READ, the shortest budget. Erring toward the short budget is deliberate: a
|
|
97
|
+
* misclassified call fails fast and visibly rather than hanging. A combined name (`createOrReplace`)
|
|
98
|
+
* resolves to `create`, the verb such a helper attempts first.
|
|
99
|
+
*/
|
|
100
|
+
export declare function callDeadlineVerb(method: string): keyof CallDeadlineBudget;
|
|
101
|
+
/**
|
|
102
|
+
* Wrap a Kubernetes API client so every request it issues is bounded by its verb's budget.
|
|
103
|
+
*
|
|
104
|
+
* Readiness polls already bound their own calls (see {@link callWithTimeout}); everything a handler
|
|
105
|
+
* does AROUND a deploy — drift checks, safety gates, CRD migrations, teardown — historically did
|
|
106
|
+
* not, so a single wedged request (a hung exec credential, a half-open socket, an API server that
|
|
107
|
+
* accepts the connection and never answers) hangs the whole reconcile with no log line and no
|
|
108
|
+
* error. Bounding at the client makes each of those calls reject with a {@link PollTimeoutError}
|
|
109
|
+
* naming the client and the method.
|
|
110
|
+
*
|
|
111
|
+
* EVERY function-valued property is wrapped, not an allow-list of known method names: a client
|
|
112
|
+
* method this module has never heard of must not silently escape the bound. A wrapped call whose
|
|
113
|
+
* return value is not thenable is handed back untouched, so synchronous helpers keep working.
|
|
114
|
+
*
|
|
115
|
+
* Same SCOPE / LIMITATION as {@link callWithTimeout}: this bounds the caller's `await`, it does not
|
|
116
|
+
* cancel the in-flight request or kill a wedged exec-auth subprocess.
|
|
117
|
+
*/
|
|
118
|
+
export declare function withCallDeadline<T extends object>(api: T, options: {
|
|
119
|
+
readonly budget: CallDeadlineBudget;
|
|
120
|
+
readonly label: string;
|
|
121
|
+
readonly abortSignal?: AbortSignal;
|
|
122
|
+
}): T;
|
|
45
123
|
//# sourceMappingURL=poll-timeout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"poll-timeout.d.ts","sourceRoot":"","sources":["../../../src/core/deployment/poll-timeout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;
|
|
1
|
+
{"version":3,"file":"poll-timeout.d.ts","sourceRoot":"","sources":["../../../src/core/deployment/poll-timeout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAQH;;;;;;;;;GASG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,yGAAyG;IACzG,QAAQ,CAAC,gBAAgB,EAAG,IAAI,CAAU;gBAC9B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;CAK/C;AAED,+GAA+G;AAC/G,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,mBAAmB,CAOlF;AAED,8HAA8H;AAC9H,qBAAa,gBAAiB,SAAQ,mBAAmB;gBAC3C,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;CAS7C;AAED;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CAAC,CAAC,EACrC,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,WAAW,GACxB,OAAO,CAAC,CAAC,CAAC,CAuBZ;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,iFAAiF;IACjF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wBAAwB;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,6DAA6D;IAC7D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,cAAc;IACd,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAOD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EACJ;IACE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC,GACD,SAAS,EACb,KAAK,CAAC,EAAE,MAAM,GACb,kBAAkB,CAYpB;AASD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,kBAAkB,CAKzE;AAsDD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,EAC/C,GAAG,EAAE,CAAC,EACN,OAAO,EAAE;IACP,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;CACpC,GACA,CAAC,CA0BH"}
|