@tablation/crew 0.5.0 → 0.6.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/cli.js +56 -10
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -578,7 +578,8 @@ var SHIP_KEYS = /* @__PURE__ */ new Set([
|
|
|
578
578
|
"relayHost",
|
|
579
579
|
"relayPort",
|
|
580
580
|
"relayHttpPort",
|
|
581
|
-
"relayPublicDomain"
|
|
581
|
+
"relayPublicDomain",
|
|
582
|
+
"passengerImage"
|
|
582
583
|
]);
|
|
583
584
|
var ROUTE_KEYS = /* @__PURE__ */ new Set([
|
|
584
585
|
"route",
|
|
@@ -912,7 +913,8 @@ Create the first of those:
|
|
|
912
913
|
// 2222 matches the relay's own RELAY_SSH_PORT default (crew-relay README).
|
|
913
914
|
relayPort: shipRaw.relayPort !== void 0 ? Number(shipRaw.relayPort) : 2222,
|
|
914
915
|
relayHttpPort: shipRaw.relayHttpPort !== void 0 ? Number(shipRaw.relayHttpPort) : 443,
|
|
915
|
-
relayPublicDomain: shipRaw.relayPublicDomain ? String(shipRaw.relayPublicDomain) : void 0
|
|
916
|
+
relayPublicDomain: shipRaw.relayPublicDomain ? String(shipRaw.relayPublicDomain) : void 0,
|
|
917
|
+
passengerImage: shipRaw.passengerImage ? String(shipRaw.passengerImage) : void 0
|
|
916
918
|
},
|
|
917
919
|
routes,
|
|
918
920
|
crewHome,
|
|
@@ -7775,7 +7777,21 @@ function dockerAvailable(exec = realExec) {
|
|
|
7775
7777
|
return false;
|
|
7776
7778
|
}
|
|
7777
7779
|
}
|
|
7778
|
-
var
|
|
7780
|
+
var PASSENGER_IMAGE_REPO = "tablation/crew-passenger-mcp";
|
|
7781
|
+
function passengerImageRef(cfg) {
|
|
7782
|
+
return process.env.CREW_PASSENGER_IMAGE || cfg.ship.passengerImage || `${PASSENGER_IMAGE_REPO}:${crewVersion(cfg.crewHome)}`;
|
|
7783
|
+
}
|
|
7784
|
+
function imagePresent(image, exec = realExec) {
|
|
7785
|
+
try {
|
|
7786
|
+
exec("docker", ["image", "inspect", image]);
|
|
7787
|
+
return true;
|
|
7788
|
+
} catch {
|
|
7789
|
+
return false;
|
|
7790
|
+
}
|
|
7791
|
+
}
|
|
7792
|
+
function ensureImage(image, exec = realExec) {
|
|
7793
|
+
if (!imagePresent(image, exec)) exec("docker", ["pull", image]);
|
|
7794
|
+
}
|
|
7779
7795
|
function containerNameFor(workspaceId) {
|
|
7780
7796
|
return `crew-passenger-${workspaceId}`;
|
|
7781
7797
|
}
|
|
@@ -7783,12 +7799,13 @@ function portFor(workspaceId, base = 28765, span = 1e3) {
|
|
|
7783
7799
|
const digest = createHash4("sha256").update(workspaceId).digest();
|
|
7784
7800
|
return base + digest.readUInt32BE(0) % span;
|
|
7785
7801
|
}
|
|
7786
|
-
function mountsDigest(mounts) {
|
|
7802
|
+
function mountsDigest(mounts, image) {
|
|
7787
7803
|
const sorted2 = [...mounts].sort((a, b) => a.containerPath.localeCompare(b.containerPath));
|
|
7788
|
-
return createHash4("sha256").update(JSON.stringify(sorted2)).digest("hex").slice(0, 16);
|
|
7804
|
+
return createHash4("sha256").update(JSON.stringify({ mounts: sorted2, image })).digest("hex").slice(0, 16);
|
|
7789
7805
|
}
|
|
7790
7806
|
function planContainers(cfg) {
|
|
7791
7807
|
const byWorkspace = /* @__PURE__ */ new Map();
|
|
7808
|
+
const image = passengerImageRef(cfg);
|
|
7792
7809
|
for (const route of cfg.routes) {
|
|
7793
7810
|
if (!route.enabled || !route.hostPassengers || !route.resolved?.workspaceId) continue;
|
|
7794
7811
|
const workspaceId = route.resolved.workspaceId;
|
|
@@ -7804,8 +7821,9 @@ function planContainers(cfg) {
|
|
|
7804
7821
|
workspaceId,
|
|
7805
7822
|
containerName: containerNameFor(workspaceId),
|
|
7806
7823
|
port: portFor(workspaceId),
|
|
7824
|
+
image,
|
|
7807
7825
|
mounts: mountList,
|
|
7808
|
-
mountsHash: mountsDigest(mountList)
|
|
7826
|
+
mountsHash: mountsDigest(mountList, image)
|
|
7809
7827
|
};
|
|
7810
7828
|
});
|
|
7811
7829
|
}
|
|
@@ -7861,7 +7879,7 @@ function startContainer(plan, tablationApiBaseUrl, sync, exec = realExec) {
|
|
|
7861
7879
|
);
|
|
7862
7880
|
}
|
|
7863
7881
|
for (const m of plan.mounts) args.push("-v", `${m.hostPath}:${m.containerPath}:ro`);
|
|
7864
|
-
args.push(
|
|
7882
|
+
args.push(plan.image);
|
|
7865
7883
|
exec("docker", args);
|
|
7866
7884
|
}
|
|
7867
7885
|
function syncPassengerContainers(cfg, tablationApiBaseUrl, exec = realExec, syncEndpoints = /* @__PURE__ */ new Map()) {
|
|
@@ -7872,19 +7890,27 @@ function syncPassengerContainers(cfg, tablationApiBaseUrl, exec = realExec, sync
|
|
|
7872
7890
|
const started = [];
|
|
7873
7891
|
const recreated = [];
|
|
7874
7892
|
const stopped = [];
|
|
7893
|
+
const ensured = /* @__PURE__ */ new Set();
|
|
7894
|
+
const start = (plan, sync) => {
|
|
7895
|
+
if (!ensured.has(plan.image)) {
|
|
7896
|
+
ensureImage(plan.image, exec);
|
|
7897
|
+
ensured.add(plan.image);
|
|
7898
|
+
}
|
|
7899
|
+
startContainer(plan, tablationApiBaseUrl, sync, exec);
|
|
7900
|
+
};
|
|
7875
7901
|
for (const plan of plans) {
|
|
7876
7902
|
const sync = syncEndpoints.get(plan.workspaceId);
|
|
7877
7903
|
const current = existingByName.get(plan.containerName);
|
|
7878
7904
|
if (!current) {
|
|
7879
|
-
|
|
7905
|
+
start(plan, sync);
|
|
7880
7906
|
started.push(plan.containerName);
|
|
7881
7907
|
} else if (!current.running) {
|
|
7882
7908
|
stopContainer(plan.containerName, exec);
|
|
7883
|
-
|
|
7909
|
+
start(plan, sync);
|
|
7884
7910
|
started.push(plan.containerName);
|
|
7885
7911
|
} else if (currentMountsHash(plan.containerName, exec) !== plan.mountsHash) {
|
|
7886
7912
|
stopContainer(plan.containerName, exec);
|
|
7887
|
-
|
|
7913
|
+
start(plan, sync);
|
|
7888
7914
|
recreated.push(plan.containerName);
|
|
7889
7915
|
}
|
|
7890
7916
|
}
|
|
@@ -9129,6 +9155,23 @@ if (command === "passenger-sync-daemon") {
|
|
|
9129
9155
|
process.stderr.write("crew install: no scheduler support yet for Windows (Task Scheduler is planned, not built)\n");
|
|
9130
9156
|
process.exit(2);
|
|
9131
9157
|
}
|
|
9158
|
+
if (!dryRun && cfg.routes.some((r) => r.enabled && r.hostPassengers) && dockerAvailable()) {
|
|
9159
|
+
const image = passengerImageRef(cfg);
|
|
9160
|
+
if (imagePresent(image)) {
|
|
9161
|
+
process.stdout.write(`Host Passengers image ${image} is already present
|
|
9162
|
+
`);
|
|
9163
|
+
} else {
|
|
9164
|
+
process.stdout.write(`pulling Host Passengers image ${image}
|
|
9165
|
+
`);
|
|
9166
|
+
try {
|
|
9167
|
+
ensureImage(image);
|
|
9168
|
+
} catch (e) {
|
|
9169
|
+
process.stderr.write(`crew install: could not pull Host Passengers image ${image}: ${e.message}
|
|
9170
|
+
`);
|
|
9171
|
+
process.exitCode = 1;
|
|
9172
|
+
}
|
|
9173
|
+
}
|
|
9174
|
+
}
|
|
9132
9175
|
const hasSystemd = detectSystemd();
|
|
9133
9176
|
for (const job of ["run", "release", "passengers"]) {
|
|
9134
9177
|
const plan = planInstall(cfg.ship, CREW_HOME, host, hasSystemd, job);
|
|
@@ -11253,10 +11296,13 @@ git: ${gitPath ? `OK (${gitPath})` : "NOT FOUND on the scheduler P
|
|
|
11253
11296
|
} else {
|
|
11254
11297
|
const dockerOk = dockerAvailable();
|
|
11255
11298
|
const keygenOk = sshKeygenAvailable();
|
|
11299
|
+
const image = passengerImageRef(cfg);
|
|
11300
|
+
const imageOk = dockerOk && imagePresent(image);
|
|
11256
11301
|
process.stdout.write(
|
|
11257
11302
|
`host passengers: ON for ${passengerRoutes.map((r) => r.route).join(", ")}
|
|
11258
11303
|
docker: ${dockerOk ? "OK" : "NOT AVAILABLE"}
|
|
11259
11304
|
ssh-keygen: ${keygenOk ? "OK" : "NOT AVAILABLE"}
|
|
11305
|
+
image: ${image} (${imageOk ? "present" : "missing"})
|
|
11260
11306
|
relay host: ${cfg.ship.relayHost ? `${cfg.ship.relayHost}:${cfg.ship.relayPort}` : "not set (ship.relayHost) \u2014 containers will run with no tunnel"}
|
|
11261
11307
|
`
|
|
11262
11308
|
);
|
package/package.json
CHANGED