hammerkit 2.0.0-next.1 → 2.0.0-next.3
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.
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.evictKeptClaims = exports.sweepKeptClaims = exports.expireKeptClaims = exports.recordClaimState = exports.forgetClaimState = exports.useClaimState = exports.isKeptClaim = exports.getClaimName = exports.EXPIRES_ANNOTATION = exports.STATE_ANNOTATION = exports.KEPT_BY_LABEL = exports.VOLUME_SCOPE_LABEL = void 0;
|
|
3
|
+
exports.evictKeptClaims = exports.sweepKeptClaims = exports.expireKeptClaims = exports.recordClaimState = exports.forgetClaimState = exports.rememberedClaimState = exports.useClaimState = exports.isKeptClaim = exports.getClaimName = exports.EXPIRES_ANNOTATION = exports.STATE_ANNOTATION = exports.KEPT_BY_LABEL = exports.VOLUME_SCOPE_LABEL = void 0;
|
|
4
4
|
const crypto_1 = require("crypto");
|
|
5
5
|
const apply_1 = require("./apply");
|
|
6
6
|
const sleep_1 = require("../utils/sleep");
|
|
@@ -98,6 +98,17 @@ async function annotate(instance, namespace, name, annotations) {
|
|
|
98
98
|
throw e;
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
|
+
// The state key of the outputs whose folder is whole in the claim of a task of a service run
|
|
102
|
+
// (see getStateFilesDir), null when it names none. The run's namespace is its own, and only
|
|
103
|
+
// the run writes to the claim: it forgets the state before it writes, records it after.
|
|
104
|
+
async function rememberedClaimState(instance, kubernetes, name) {
|
|
105
|
+
const claim = await readClaim(instance, kubernetes.namespace, name);
|
|
106
|
+
if (!claim || claim.metadata?.deletionTimestamp) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
return claim.metadata?.annotations?.[exports.STATE_ANNOTATION] ?? null;
|
|
110
|
+
}
|
|
111
|
+
exports.rememberedClaimState = rememberedClaimState;
|
|
101
112
|
// Before a task writes to its kept claim: the outputs in it stop being those of a state.
|
|
102
113
|
// Whether the claim was there, with what an earlier run left in it.
|
|
103
114
|
function forgetClaimState(instance, kubernetes, name) {
|
|
@@ -170,6 +170,9 @@ function kubernetesTaskRuntime(task, kubernetes) {
|
|
|
170
170
|
// on a server that keeps them, the task's claim stays after the run with the state of its
|
|
171
171
|
// outputs, and the next run of the same source mounts them as they are (see kept-claims)
|
|
172
172
|
const kept = (0, kept_claims_1.isKeptClaim)(task, kubernetes);
|
|
173
|
+
// on a service run, the claim names the last state whose folder is whole (see
|
|
174
|
+
// rememberedClaimState): a wake or a move at that state mounts it without an upload
|
|
175
|
+
const remembers = kept || !!kubernetes.server?.serviceRun;
|
|
173
176
|
const claim = (0, volumes_1.getVolumeName)(task, kubernetes);
|
|
174
177
|
return {
|
|
175
178
|
initialize() {
|
|
@@ -182,6 +185,16 @@ function kubernetesTaskRuntime(task, kubernetes) {
|
|
|
182
185
|
stateKey &&
|
|
183
186
|
(await (0, ensure_persistent_data_1.getStateDirsInUse)(instance, kubernetes.namespace, claim)).has((0, volumes_1.getStateFilesDir)(stateKey))) {
|
|
184
187
|
task.status.write('info', `${task.name}: services of the run use its outputs of this state, they stay`);
|
|
188
|
+
await (0, kept_claims_1.recordClaimState)(instance, kubernetes, claim, stateKey);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (remembers && !kept) {
|
|
192
|
+
// the folder of the state is written now: until it is whole, the claim names no state
|
|
193
|
+
await (0, kept_claims_1.forgetClaimState)(instance, kubernetes, claim);
|
|
194
|
+
await (0, restore_kubernetes_data_1.restoreKubernetesData)(task, kubernetes, instance, environment, path, { stateKey });
|
|
195
|
+
if (stateKey) {
|
|
196
|
+
await (0, kept_claims_1.recordClaimState)(instance, kubernetes, claim, stateKey);
|
|
197
|
+
}
|
|
185
198
|
return;
|
|
186
199
|
}
|
|
187
200
|
if (!kept) {
|
|
@@ -231,11 +244,14 @@ function kubernetesTaskRuntime(task, kubernetes) {
|
|
|
231
244
|
try {
|
|
232
245
|
if (files && (await (0, ensure_persistent_data_1.getStateDirsInUse)(instance, kubernetes.namespace, claim)).has(files.dir)) {
|
|
233
246
|
task.status.write('info', `${task.name}: services of the run use its outputs of this state, they stay`);
|
|
247
|
+
await (0, kept_claims_1.recordClaimState)(instance, kubernetes, claim, options.stateKey);
|
|
234
248
|
return;
|
|
235
249
|
}
|
|
236
250
|
// the task writes to it now: what it holds stops being the outputs of a state, and
|
|
237
|
-
// goes, as a new claim would hold nothing
|
|
238
|
-
|
|
251
|
+
// goes, as a new claim would hold nothing (on a service run, the folders of other
|
|
252
|
+
// states that no pod mounts go)
|
|
253
|
+
const forgotten = remembers && (await (0, kept_claims_1.forgetClaimState)(instance, kubernetes, claim));
|
|
254
|
+
const reset = kept && forgotten;
|
|
239
255
|
await (0, ensure_persistent_data_1.ensurePersistentData)(instance, kubernetes, environment, task, persistence, { reset, files });
|
|
240
256
|
}
|
|
241
257
|
catch (e) {
|
|
@@ -415,7 +431,7 @@ function kubernetesTaskRuntime(task, kubernetes) {
|
|
|
415
431
|
}
|
|
416
432
|
// the finished job stays for its state, the values it read need not
|
|
417
433
|
await removeTaskSecrets(instance, kubernetes, task);
|
|
418
|
-
if (
|
|
434
|
+
if (remembers) {
|
|
419
435
|
await (0, kept_claims_1.recordClaimState)(instance, kubernetes, claim, options.stateKey);
|
|
420
436
|
}
|
|
421
437
|
}
|
|
@@ -471,6 +487,13 @@ function kubernetesTaskRuntime(task, kubernetes) {
|
|
|
471
487
|
// the server removes the Jobs of a run at its end, the claim says
|
|
472
488
|
return (0, kept_claims_1.useClaimState)(instance, kubernetes, claim);
|
|
473
489
|
}
|
|
490
|
+
if (remembers) {
|
|
491
|
+
// a service run that sleeps loses its Jobs but keeps its claims, the claim says
|
|
492
|
+
const remembered = await (0, kept_claims_1.rememberedClaimState)(instance, kubernetes, claim);
|
|
493
|
+
if (remembered) {
|
|
494
|
+
return remembered;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
474
497
|
const jobs = await instance.batchApi.listNamespacedJob({
|
|
475
498
|
namespace: kubernetes.namespace,
|
|
476
499
|
labelSelector: (0, resources_1.getItemSelector)(task, kubernetes),
|
|
@@ -31,7 +31,7 @@ exports.hostServerSchema = zod_1.z
|
|
|
31
31
|
.strict();
|
|
32
32
|
// A command that prints the token for a server instead of a login, see token-source.ts.
|
|
33
33
|
// It is bound to the url and issuer it was registered for, like a sign-in, and lives
|
|
34
|
-
// beside `servers` rather than in it: hammerkit before
|
|
34
|
+
// beside `servers` rather than in it: hammerkit before 2.0 refuses unknown keys of a
|
|
35
35
|
// server, but keeps unknown top-level keys. It is only ever read from the host config,
|
|
36
36
|
// a build file can't name one.
|
|
37
37
|
const tokenCommandSchema = zod_1.z
|
|
@@ -221,7 +221,7 @@ function registerWorkCommands(remote, context) {
|
|
|
221
221
|
}
|
|
222
222
|
return { version, proposed };
|
|
223
223
|
};
|
|
224
|
-
// what publishing the bundle would do, undefined from a server that can't say (before
|
|
224
|
+
// what publishing the bundle would do, undefined from a server that can't say (before 2.0)
|
|
225
225
|
const planBundle = async (server, token, bundle) => {
|
|
226
226
|
try {
|
|
227
227
|
return (await (0, server_client_1.callServer)(server, token, 'POST', '/v1/definitions/plan', bundle)).body;
|
|
@@ -271,7 +271,7 @@ function registerWorkCommands(remote, context) {
|
|
|
271
271
|
if (!environment.prompt) {
|
|
272
272
|
throw new Error(`${notPublished}, publish it first with: hammerkit remote publish ${serverName}, or pass --publish`);
|
|
273
273
|
}
|
|
274
|
-
// a server before
|
|
274
|
+
// a server before 2.0 can't say what publishing would do: it is asked all the same,
|
|
275
275
|
// and refuses then what the caller may not do
|
|
276
276
|
const planned = await planBundle(server, token, local);
|
|
277
277
|
if (planned && planned.outcome === null) {
|
|
@@ -322,7 +322,7 @@ function registerWorkCommands(remote, context) {
|
|
|
322
322
|
const { name: serverName, server, token } = await connect(name);
|
|
323
323
|
const answer = await (0, server_client_1.callServer)(server, token, 'POST', '/v1/definitions/plan', bundle).catch((e) => {
|
|
324
324
|
throw e instanceof server_client_1.ServerError && e.status === 404
|
|
325
|
-
? new Error(`${serverName} can't check a build file without publishing it, it needs hammerkit
|
|
325
|
+
? new Error(`${serverName} can't check a build file without publishing it, it needs hammerkit 2.0`)
|
|
326
326
|
: e;
|
|
327
327
|
});
|
|
328
328
|
const planned = answer.body;
|
package/package.json
CHANGED