openship 0.6.8 → 0.6.9
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/{chunk-5I3COAFH.js → chunk-634DDFT5.js} +1 -1
- package/dist/{chunk-RCMERVBL.js → chunk-FCGJN5Q5.js} +2 -2
- package/dist/{host-channel-preflight-OMCZMMKR.js → host-channel-preflight-OI2TRHSG.js} +1 -1
- package/dist/index.js +15 -15
- package/dist/server/index.js +168 -17
- package/dist/{up-HQS7IR7H.js → up-RC5ZQIAD.js} +2 -2
- package/package.json +1 -1
|
@@ -1627,7 +1627,7 @@ function operatorEnvPassthrough(managed, prev) {
|
|
|
1627
1627
|
}
|
|
1628
1628
|
var PRESERVED_ENV_HEADER = "# Preserved from your existing .env \u2014 set by you, not by `openship up` (#485).";
|
|
1629
1629
|
function resolveImageVersion(opts) {
|
|
1630
|
-
return opts.version?.trim() || process.env.OPENSHIP_VERSION?.trim() || (true ? "0.6.
|
|
1630
|
+
return opts.version?.trim() || process.env.OPENSHIP_VERSION?.trim() || (true ? "0.6.9" : "latest");
|
|
1631
1631
|
}
|
|
1632
1632
|
function managedEnvLines(opts, host, cfg, prev) {
|
|
1633
1633
|
const lines = [
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
resolvePorts,
|
|
29
29
|
sourceBuildDir,
|
|
30
30
|
verifyHostChannel
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-634DDFT5.js";
|
|
32
32
|
import {
|
|
33
33
|
bootstrapAdmin,
|
|
34
34
|
importMigratedSites,
|
|
@@ -1564,7 +1564,7 @@ async function runForeground(opts, source) {
|
|
|
1564
1564
|
const uiSpinner = ora("Preparing the dashboard\u2026").start();
|
|
1565
1565
|
try {
|
|
1566
1566
|
const bundle = await ensureDashboard({
|
|
1567
|
-
tag: source ? "local" : opts.uiVersion || `v${"0.6.
|
|
1567
|
+
tag: source ? "local" : opts.uiVersion || `v${"0.6.9"}`,
|
|
1568
1568
|
onProgress: (received, total) => {
|
|
1569
1569
|
if (total) {
|
|
1570
1570
|
uiSpinner.text = `Downloading dashboard\u2026 ${Math.round(received / total * 100)}%`;
|
package/dist/index.js
CHANGED
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
stop,
|
|
27
27
|
upCommand,
|
|
28
28
|
writeCliInstall
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-FCGJN5Q5.js";
|
|
30
30
|
import {
|
|
31
31
|
composeDown,
|
|
32
32
|
composeInternalToken,
|
|
@@ -60,7 +60,7 @@ import {
|
|
|
60
60
|
sourceBuildDir,
|
|
61
61
|
storedApiPort,
|
|
62
62
|
storedDashboardPort
|
|
63
|
-
} from "./chunk-
|
|
63
|
+
} from "./chunk-634DDFT5.js";
|
|
64
64
|
import {
|
|
65
65
|
bootstrapAdmin,
|
|
66
66
|
detectPublicIp,
|
|
@@ -313,7 +313,7 @@ function getDashboardUrl(name) {
|
|
|
313
313
|
}
|
|
314
314
|
|
|
315
315
|
// src/lib/api-client.ts
|
|
316
|
-
var USER_AGENT = `openship-cli/${true ? "0.6.
|
|
316
|
+
var USER_AGENT = `openship-cli/${true ? "0.6.9" : "dev"}`;
|
|
317
317
|
function getApiUrl2() {
|
|
318
318
|
return `${getApiUrl()}/api`;
|
|
319
319
|
}
|
|
@@ -1109,7 +1109,7 @@ function dockerNameRunning(nameFilter) {
|
|
|
1109
1109
|
return r.stdout.trim().length > 0;
|
|
1110
1110
|
}
|
|
1111
1111
|
async function hostControlCheck(api) {
|
|
1112
|
-
const { checkHostChannel } = await import("./host-channel-preflight-
|
|
1112
|
+
const { checkHostChannel } = await import("./host-channel-preflight-OI2TRHSG.js");
|
|
1113
1113
|
return hostControlRow(await checkHostChannel().catch(() => null), api);
|
|
1114
1114
|
}
|
|
1115
1115
|
var NEVER_PROVISIONED_DETAIL = `never provisioned \u2014 run \`${HOST_CHANNEL_PROVISION_COMMAND}\``;
|
|
@@ -1514,7 +1514,7 @@ async function interactiveDoctor() {
|
|
|
1514
1514
|
continue;
|
|
1515
1515
|
}
|
|
1516
1516
|
if (action2 === "host-control") {
|
|
1517
|
-
const { verifyHostChannel } = await import("./host-channel-preflight-
|
|
1517
|
+
const { verifyHostChannel } = await import("./host-channel-preflight-OI2TRHSG.js");
|
|
1518
1518
|
const report3 = await verifyHostChannel().catch(() => null);
|
|
1519
1519
|
if (report3?.status === "fixed") log2.success("Host control is reachable now.");
|
|
1520
1520
|
else if (report3?.status === "ok") log2.success("Host control was already reachable.");
|
|
@@ -4576,7 +4576,7 @@ function printMonitoringNextSteps() {
|
|
|
4576
4576
|
info(" openship edge analytics -p <project> per-domain analytics");
|
|
4577
4577
|
}
|
|
4578
4578
|
async function runMonitoringInstall(opts) {
|
|
4579
|
-
const up = await import("./up-
|
|
4579
|
+
const up = await import("./up-RC5ZQIAD.js");
|
|
4580
4580
|
let adminName = opts.adminName;
|
|
4581
4581
|
let adminEmail = opts.adminEmail;
|
|
4582
4582
|
let adminPassword = opts.adminPassword;
|
|
@@ -6733,7 +6733,7 @@ function applyOnlyArgv(selfArgs, json) {
|
|
|
6733
6733
|
// src/commands/update.ts
|
|
6734
6734
|
async function verifyHostChannelAfterUpdate() {
|
|
6735
6735
|
if (isJsonMode()) return;
|
|
6736
|
-
const { verifyHostChannel } = await import("./host-channel-preflight-
|
|
6736
|
+
const { verifyHostChannel } = await import("./host-channel-preflight-OI2TRHSG.js");
|
|
6737
6737
|
await verifyHostChannel().catch(() => {
|
|
6738
6738
|
});
|
|
6739
6739
|
}
|
|
@@ -6810,7 +6810,7 @@ async function runSourceUpdate(source, opts) {
|
|
|
6810
6810
|
}
|
|
6811
6811
|
var REINSTALL_HINT = "curl -fsSL https://get.openship.io | sh";
|
|
6812
6812
|
async function runTarballUpdate(install, opts) {
|
|
6813
|
-
const current = "0.6.
|
|
6813
|
+
const current = "0.6.9";
|
|
6814
6814
|
let latest;
|
|
6815
6815
|
try {
|
|
6816
6816
|
latest = (await resolveLatestTag()).replace(/^v/, "");
|
|
@@ -6894,7 +6894,7 @@ var updateCommand = new Command26("update").description("Update the Openship CLI
|
|
|
6894
6894
|
if (source) return runSourceUpdate(source, opts);
|
|
6895
6895
|
const cliInstall = readCliInstall();
|
|
6896
6896
|
if (cliInstall?.method === "tarball") return runTarballUpdate(cliInstall, opts);
|
|
6897
|
-
const current = "0.6.
|
|
6897
|
+
const current = "0.6.9";
|
|
6898
6898
|
let latest;
|
|
6899
6899
|
try {
|
|
6900
6900
|
latest = (await resolveLatestTag()).replace(/^v/, "");
|
|
@@ -7502,7 +7502,7 @@ async function runWizard() {
|
|
|
7502
7502
|
}
|
|
7503
7503
|
}
|
|
7504
7504
|
}
|
|
7505
|
-
const uiTag = `v${"0.6.
|
|
7505
|
+
const uiTag = `v${"0.6.9"}`;
|
|
7506
7506
|
if (method === "bare") {
|
|
7507
7507
|
const dl = spinner4();
|
|
7508
7508
|
dl.start("Pulling the Openship dist from GitHub");
|
|
@@ -7562,7 +7562,7 @@ async function runWizard() {
|
|
|
7562
7562
|
const dashboardPort = String(ports.dashboard);
|
|
7563
7563
|
const moved = portMoveNotice(ports, composeTrustedOriginUrls());
|
|
7564
7564
|
if (moved.length) log5.info(moved.join("\n"));
|
|
7565
|
-
if (!pinnedImagesReady({ version: "0.6.
|
|
7565
|
+
if (!pinnedImagesReady({ version: "0.6.9" })) {
|
|
7566
7566
|
cancel4("The pinned Openship image tag isn't in the registry yet \u2014 nothing on this box was changed.");
|
|
7567
7567
|
process.exit(1);
|
|
7568
7568
|
}
|
|
@@ -7586,7 +7586,7 @@ async function runWizard() {
|
|
|
7586
7586
|
dashboardPort,
|
|
7587
7587
|
publicUrl,
|
|
7588
7588
|
trustProxy: behindProxy,
|
|
7589
|
-
version: "0.6.
|
|
7589
|
+
version: "0.6.9",
|
|
7590
7590
|
noHostControl: !allowHostControl
|
|
7591
7591
|
});
|
|
7592
7592
|
if (!fetched.ok) {
|
|
@@ -7615,7 +7615,7 @@ async function runWizard() {
|
|
|
7615
7615
|
dashboardPort,
|
|
7616
7616
|
publicUrl,
|
|
7617
7617
|
trustProxy: behindProxy,
|
|
7618
|
-
version: "0.6.
|
|
7618
|
+
version: "0.6.9",
|
|
7619
7619
|
noHostControl: !allowHostControl
|
|
7620
7620
|
});
|
|
7621
7621
|
if (!up.ok) {
|
|
@@ -7716,7 +7716,7 @@ async function runWizard() {
|
|
|
7716
7716
|
if (result.liveUrl) liveUrl2 = result.liveUrl;
|
|
7717
7717
|
else if (!result.domainRegistered) liveUrl2 = `http://localhost:${started.dashPort}`;
|
|
7718
7718
|
for (const w of result.warnings) log5.warn(w);
|
|
7719
|
-
const { verifyHostChannel } = await import("./host-channel-preflight-
|
|
7719
|
+
const { verifyHostChannel } = await import("./host-channel-preflight-OI2TRHSG.js");
|
|
7720
7720
|
await verifyHostChannel().catch(() => {
|
|
7721
7721
|
});
|
|
7722
7722
|
finishSetup({
|
|
@@ -7995,7 +7995,7 @@ function attachCompletion(program2) {
|
|
|
7995
7995
|
|
|
7996
7996
|
// src/index.ts
|
|
7997
7997
|
var program = new Command28();
|
|
7998
|
-
program.name("openship").description("Openship CLI \u2014 install, run, and manage Openship from your terminal").version("0.6.
|
|
7998
|
+
program.name("openship").description("Openship CLI \u2014 install, run, and manage Openship from your terminal").version("0.6.9").option("--json", "Machine-readable JSON output (stdout data only)").hook("preAction", (thisCommand) => {
|
|
7999
7999
|
if (thisCommand.opts().json) setJsonMode(true);
|
|
8000
8000
|
}).action(async () => {
|
|
8001
8001
|
const installed = serviceStatus().installed || readInstallMethod() === "compose";
|
package/dist/server/index.js
CHANGED
|
@@ -123865,6 +123865,27 @@ function toComposeSpec(s4) {
|
|
|
123865
123865
|
advanced
|
|
123866
123866
|
};
|
|
123867
123867
|
}
|
|
123868
|
+
function isComposeProvenanceUpgrade(baseInput, nextInput) {
|
|
123869
|
+
const base = toComposeSpec(baseInput);
|
|
123870
|
+
const next = toComposeSpec(nextInput);
|
|
123871
|
+
const baseAdvanced = { ...base.advanced ?? {} };
|
|
123872
|
+
const nextAdvanced = { ...next.advanced ?? {} };
|
|
123873
|
+
const markerKeys = ["environmentTemplateKeys", "buildArgTemplateKeys"];
|
|
123874
|
+
const addsMarker = markerKeys.some((key) => !Object.hasOwn(baseAdvanced, key) && Object.hasOwn(nextAdvanced, key));
|
|
123875
|
+
if (!addsMarker)
|
|
123876
|
+
return false;
|
|
123877
|
+
for (const key of markerKeys) {
|
|
123878
|
+
delete baseAdvanced[key];
|
|
123879
|
+
delete nextAdvanced[key];
|
|
123880
|
+
}
|
|
123881
|
+
const envKeys = (value) => Object.keys(value).sort();
|
|
123882
|
+
const comparable = (spec, advanced) => ({
|
|
123883
|
+
...spec,
|
|
123884
|
+
environment: envKeys(spec.environment ?? {}),
|
|
123885
|
+
advanced
|
|
123886
|
+
});
|
|
123887
|
+
return JSON.stringify(canonicalize(comparable(base, baseAdvanced))) === JSON.stringify(canonicalize(comparable(next, nextAdvanced)));
|
|
123888
|
+
}
|
|
123868
123889
|
function composeWritePatch(parsed, stored, composeAuthoritative = false) {
|
|
123869
123890
|
const hasBuildArgMarker = Object.hasOwn(parsed.advanced ?? {}, "buildArgTemplateKeys");
|
|
123870
123891
|
const suppliedBuildArgCount = Object.keys(parsed.buildArgs ?? {}).length;
|
|
@@ -124216,6 +124237,10 @@ function createServiceRepo(db3) {
|
|
|
124216
124237
|
});
|
|
124217
124238
|
continue;
|
|
124218
124239
|
}
|
|
124240
|
+
if (isComposeProvenanceUpgrade(base, theirs)) {
|
|
124241
|
+
await this.update(ex.id, { importedSpec: theirs, driftSpec: null });
|
|
124242
|
+
continue;
|
|
124243
|
+
}
|
|
124219
124244
|
if (composeSpecsEqual(theirs, base)) {
|
|
124220
124245
|
if (!Object.hasOwn(base, "buildArgs")) {
|
|
124221
124246
|
await this.update(ex.id, { importedSpec: theirs, driftSpec: null });
|
|
@@ -214575,7 +214600,7 @@ var package_default;
|
|
|
214575
214600
|
var init_package = __esm(() => {
|
|
214576
214601
|
package_default = {
|
|
214577
214602
|
name: "@repo/api",
|
|
214578
|
-
version: "0.6.
|
|
214603
|
+
version: "0.6.9",
|
|
214579
214604
|
license: "Apache-2.0",
|
|
214580
214605
|
private: true,
|
|
214581
214606
|
type: "module",
|
|
@@ -275257,6 +275282,9 @@ async function allocateAndReservePinnedHostPort(input) {
|
|
|
275257
275282
|
avoid,
|
|
275258
275283
|
reuseOccupiedPreferred: reusable ? ownsReusablePinnedHostPort(input.claims, reusable) && !avoid.has(reusable.port) : false
|
|
275259
275284
|
});
|
|
275285
|
+
if (input.lockPreferred && preferred !== undefined && allocation.port !== preferred) {
|
|
275286
|
+
throw new Error(`Refusing to change the locked host port for ${input.lockPreferred.ownerLabel} from ` + `${preferred} to ${allocation.port} during a same-server redeploy. ` + `The existing workload and routes were left unchanged.`);
|
|
275287
|
+
}
|
|
275260
275288
|
const claim2 = await reserveTargetPinnedHostPort(input.target, {
|
|
275261
275289
|
...input.owner,
|
|
275262
275290
|
containerPort: previousClaim ? previousClaim.containerPort : input.owner.containerPort,
|
|
@@ -282279,6 +282307,9 @@ var init_deployment_class2 = __esm(() => {
|
|
|
282279
282307
|
});
|
|
282280
282308
|
|
|
282281
282309
|
// ../api/src/modules/services/live-state.ts
|
|
282310
|
+
function liveMatchTiersForDeployment(meta6) {
|
|
282311
|
+
return meta6?.adopt === true ? undefined : OWNED_CONTAINER_TIERS;
|
|
282312
|
+
}
|
|
282282
282313
|
function canonicalServiceContainerName(slug, serviceName) {
|
|
282283
282314
|
if (!slug || !serviceName)
|
|
282284
282315
|
return null;
|
|
@@ -282401,8 +282432,9 @@ function describeLiveState(services, live, matches) {
|
|
|
282401
282432
|
return `${svc.name} → ${name2 ? displayName(name2) : m4.containerId.slice(0, 12)} (${m4.status}, by ${m4.matchedBy})${dupes}`;
|
|
282402
282433
|
});
|
|
282403
282434
|
}
|
|
282404
|
-
var UNMATCHED, displayName = (c2) => c2.names[0] ?? c2.id.slice(0, 12);
|
|
282435
|
+
var OWNED_CONTAINER_TIERS, UNMATCHED, displayName = (c2) => c2.names[0] ?? c2.id.slice(0, 12);
|
|
282405
282436
|
var init_live_state = __esm(() => {
|
|
282437
|
+
OWNED_CONTAINER_TIERS = ["label", "name", "trackedId"];
|
|
282406
282438
|
UNMATCHED = {
|
|
282407
282439
|
containerId: null,
|
|
282408
282440
|
status: "stopped",
|
|
@@ -298886,6 +298918,16 @@ function upstreamHostPortFor(args2) {
|
|
|
298886
298918
|
return pinned.get(port) ?? (sameService && port === primaryPort && resultHostPort ? resultHostPort : undefined);
|
|
298887
298919
|
}
|
|
298888
298920
|
|
|
298921
|
+
// ../api/src/modules/deployments/compose/foreign-compose-collision.ts
|
|
298922
|
+
function findForeignComposeCollisions(input) {
|
|
298923
|
+
const services = new Set(input.serviceNames);
|
|
298924
|
+
const tracked = new Set(input.trackedContainerIds ?? []);
|
|
298925
|
+
return input.containers.filter((container) => !tracked.has(container.id) && container.composeProject === input.slug && !!container.composeService && services.has(container.composeService)).map((container) => ({
|
|
298926
|
+
serviceName: container.composeService,
|
|
298927
|
+
containerName: container.names[0] ?? container.id.slice(0, 12)
|
|
298928
|
+
}));
|
|
298929
|
+
}
|
|
298930
|
+
|
|
298889
298931
|
// ../api/src/modules/deployments/compose/deploy.service.ts
|
|
298890
298932
|
function composeDeployMadeNoChanges(result) {
|
|
298891
298933
|
return result.status === "ready" && result.summary.total > 0 && result.summary.deployed === 0 && result.summary.failed === 0 && !result.summary.mutated;
|
|
@@ -299301,8 +299343,27 @@ async function deployComposeServicesUnlocked(project2, dep, runtime, logger4, op
|
|
|
299301
299343
|
`, "info");
|
|
299302
299344
|
}
|
|
299303
299345
|
const previousServiceDeps = project2.activeDeploymentId ? await repos.service.listByDeployment(project2.activeDeploymentId) : [];
|
|
299346
|
+
const activeDeployment = project2.activeDeploymentId ? await repos.deployment.findById(project2.activeDeploymentId) : null;
|
|
299347
|
+
const activeServerId = (activeDeployment?.meta ?? {}).serverId ?? null;
|
|
299348
|
+
const targetServerId = opts?.serverId ?? null;
|
|
299349
|
+
const lockCarriedHostPorts = activeDeployment !== null && activeServerId === targetServerId;
|
|
299304
299350
|
const previousByServiceId = new Map(previousServiceDeps.map((row) => [row.serviceId, row]));
|
|
299305
299351
|
const enabledServiceIds = new Set(enabled.map((svc) => svc.id));
|
|
299352
|
+
const activeMeta = activeDeployment?.meta ?? {};
|
|
299353
|
+
if (activeMeta.adopt !== true && runtime.supports("hostContainerQuery") && runtime.listAllContainers) {
|
|
299354
|
+
const collisions = findForeignComposeCollisions({
|
|
299355
|
+
slug: project2.slug,
|
|
299356
|
+
serviceNames: enabled.map((service2) => service2.name),
|
|
299357
|
+
containers: await runtime.listAllContainers(),
|
|
299358
|
+
trackedContainerIds: previousServiceDeps.map((row) => row.containerId).filter((id2) => !!id2)
|
|
299359
|
+
});
|
|
299360
|
+
if (collisions.length > 0) {
|
|
299361
|
+
throw new DeployError(`Refusing to create a parallel stack: Docker Compose already runs ${collisions.map((collision) => `${collision.serviceName} (${collision.containerName})`).join(", ")} under project name "${project2.slug}". Import/adopt that stack, remove it explicitly, or choose a different project slug before deploying.`, "FOREIGN_COMPOSE_STACK", {
|
|
299362
|
+
projectSlug: project2.slug,
|
|
299363
|
+
collisions
|
|
299364
|
+
});
|
|
299365
|
+
}
|
|
299366
|
+
}
|
|
299306
299367
|
let keepSetPromise = null;
|
|
299307
299368
|
const retentionKeepSet = () => {
|
|
299308
299369
|
keepSetPromise ??= computeKeepSet(project2).catch(() => new Set);
|
|
@@ -299909,13 +299970,14 @@ async function deployComposeServicesUnlocked(project2, dep, runtime, logger4, op
|
|
|
299909
299970
|
cachedPreferred,
|
|
299910
299971
|
allowLegacyContainerPort: containerPort === primaryRoutedPort,
|
|
299911
299972
|
additionalAvoid: allocatedHostPorts,
|
|
299973
|
+
lockPreferred: lockCarriedHostPorts ? { ownerLabel: svc.name } : undefined,
|
|
299912
299974
|
allocate: (allocationOptions) => allocateHostPort(opts.executor, allocationOptions)
|
|
299913
299975
|
});
|
|
299914
299976
|
serviceHostPortAllocations.push(allocation);
|
|
299915
299977
|
const carried2 = allocation.preferred;
|
|
299916
299978
|
const hostPort = allocation.port;
|
|
299917
299979
|
if (carried2 && hostPort !== carried2) {
|
|
299918
|
-
logger4.log(`
|
|
299980
|
+
logger4.log(`Project moved hosts: ${svc.name} uses ${hostPort} instead of ${carried2}.
|
|
299919
299981
|
`);
|
|
299920
299982
|
}
|
|
299921
299983
|
if (!allocation.scanned) {
|
|
@@ -302445,7 +302507,8 @@ async function getActiveServiceContainers(ctx2, projectId) {
|
|
|
302445
302507
|
live: containers,
|
|
302446
302508
|
projectId,
|
|
302447
302509
|
slug: project2.slug,
|
|
302448
|
-
trackedIds
|
|
302510
|
+
trackedIds,
|
|
302511
|
+
tiers: liveMatchTiersForDeployment(dep.meta)
|
|
302449
302512
|
});
|
|
302450
302513
|
return services.filter((svc) => svc.enabled !== false || matches.get(svc.id)?.containerId).map((svc) => {
|
|
302451
302514
|
const m4 = matches.get(svc.id);
|
|
@@ -315757,7 +315820,11 @@ async function connect3(sub) {
|
|
|
315757
315820
|
sub.connecting = false;
|
|
315758
315821
|
}
|
|
315759
315822
|
}
|
|
315760
|
-
function onEvent(sub,
|
|
315823
|
+
function onEvent(sub, event) {
|
|
315824
|
+
if (!isTrackedHealthContainer(sub.key, event.containerId))
|
|
315825
|
+
return;
|
|
315826
|
+
if (!["die", "oom", "restart", "start", "unhealthy", "healthy", "destroy"].includes(event.action))
|
|
315827
|
+
return;
|
|
315761
315828
|
if (Date.now() - sub.lastRunAt >= MIN_RUN_GAP_MS)
|
|
315762
315829
|
sub.followUpsLeft = MAX_FOLLOW_UPS;
|
|
315763
315830
|
schedule(sub);
|
|
@@ -315891,6 +315958,12 @@ var init_container_events = __esm(async () => {
|
|
|
315891
315958
|
});
|
|
315892
315959
|
|
|
315893
315960
|
// ../api/src/modules/monitoring/health-watch.ts
|
|
315961
|
+
function listWorkloadHealthSnapshots(organizationId) {
|
|
315962
|
+
return [...HEALTH_SNAPSHOTS.values()].filter((row) => row.organizationId === organizationId);
|
|
315963
|
+
}
|
|
315964
|
+
function isTrackedHealthContainer(groupKey, containerId) {
|
|
315965
|
+
return TRACKED_CONTAINERS.get(groupKey)?.has(containerId) ?? false;
|
|
315966
|
+
}
|
|
315894
315967
|
function memoryKey(projectId, serviceKey) {
|
|
315895
315968
|
return `${projectId}:${serviceKey}`;
|
|
315896
315969
|
}
|
|
@@ -316072,6 +316145,10 @@ async function sweepOnce(opts) {
|
|
|
316072
316145
|
summary.stale++;
|
|
316073
316146
|
MEMORY.delete(key);
|
|
316074
316147
|
}
|
|
316148
|
+
for (const [key, row] of HEALTH_SNAPSHOTS) {
|
|
316149
|
+
if (!visited2.has(key) && settled(row.projectId))
|
|
316150
|
+
HEALTH_SNAPSHOTS.delete(key);
|
|
316151
|
+
}
|
|
316075
316152
|
for (const key of MEMORY.keys()) {
|
|
316076
316153
|
if (visited2.has(key))
|
|
316077
316154
|
continue;
|
|
@@ -316187,6 +316264,7 @@ async function readServerGroup(ctx2, first, target) {
|
|
|
316187
316264
|
});
|
|
316188
316265
|
}
|
|
316189
316266
|
}
|
|
316267
|
+
TRACKED_CONTAINERS.set(watchGroupKey(serverId, organizationId), new Set(pending.map((entry) => entry.workload.containerId)));
|
|
316190
316268
|
pending.sort((a2, b3) => inspectRank(a2.container) - inspectRank(b3.container));
|
|
316191
316269
|
await mapWithLimit(pending, INSPECT_CONCURRENCY, async ({ candidate, workload, container }) => {
|
|
316192
316270
|
if (handle2.abandoned)
|
|
@@ -316257,6 +316335,8 @@ async function resolveWorkloads(candidate, services, live) {
|
|
|
316257
316335
|
});
|
|
316258
316336
|
const workloads = [];
|
|
316259
316337
|
for (const service2 of services) {
|
|
316338
|
+
if (service2.advanced?.monitoringEnabled === false)
|
|
316339
|
+
continue;
|
|
316260
316340
|
const hint = hints.get(service2.id);
|
|
316261
316341
|
if (!hint)
|
|
316262
316342
|
continue;
|
|
@@ -316315,6 +316395,19 @@ async function evaluate(args2) {
|
|
|
316315
316395
|
expectRunning: workload.expectRunning,
|
|
316316
316396
|
createdTicks: sameContainer ? previous?.createdTicks ?? 0 : 0
|
|
316317
316397
|
}) : missingContainerVerdict(workload);
|
|
316398
|
+
HEALTH_SNAPSHOTS.set(key, {
|
|
316399
|
+
organizationId: candidate.project.organizationId,
|
|
316400
|
+
projectId: candidate.project.id,
|
|
316401
|
+
projectName: candidate.project.name,
|
|
316402
|
+
projectSlug: candidate.project.slug,
|
|
316403
|
+
serviceId: workload.serviceId,
|
|
316404
|
+
serviceKey: workload.serviceKey,
|
|
316405
|
+
serviceName: workload.serviceName,
|
|
316406
|
+
serverId: candidate.serverId,
|
|
316407
|
+
containerId: workload.containerId,
|
|
316408
|
+
state: verdict.clear === "unknown" ? "unknown" : verdict.kind ?? "healthy",
|
|
316409
|
+
observedAt: new Date(nowMs).toISOString()
|
|
316410
|
+
});
|
|
316318
316411
|
if (verdict.clear === "unknown") {
|
|
316319
316412
|
summary.indeterminate++;
|
|
316320
316413
|
const carried = previous && sameContainer ? previous : {
|
|
@@ -316418,7 +316511,7 @@ async function pruneResolvedIncidents() {
|
|
|
316418
316511
|
const cutoff = new Date(Date.now() - INCIDENT_RETENTION_DAYS * 24 * 60 * 60 * 1000);
|
|
316419
316512
|
return { deleted: await repos.serviceIncident.deleteResolvedOlderThan(cutoff) };
|
|
316420
316513
|
}
|
|
316421
|
-
var AGREE_TICKS = 2, MIN_CONFIRM_GAP_MS = 4000, RESTART_WINDOW_MS = 45000, RESTART_STALE_MS, DEPLOY_GRACE_MS, SERVER_CONCURRENCY = 4, GROUP_DEADLINE_MS = 90000, GROUP_DEADLINE_REASON, INSPECT_CONCURRENCY = 8, MAX_INSPECTS_PER_SERVER = 120, LOG_TAIL_LINES = 12, FLAP_WINDOW_MS, RECOVERY_HOLD_MS, SINGLE_APP_KEY = "__app__", MEMORY, LOCAL_SERVER_KEY = "__local__", sweepChain, KNOWN_STATES, INCIDENT_RETENTION_DAYS = 30;
|
|
316514
|
+
var AGREE_TICKS = 2, MIN_CONFIRM_GAP_MS = 4000, RESTART_WINDOW_MS = 45000, RESTART_STALE_MS, DEPLOY_GRACE_MS, SERVER_CONCURRENCY = 4, GROUP_DEADLINE_MS = 90000, GROUP_DEADLINE_REASON, INSPECT_CONCURRENCY = 8, MAX_INSPECTS_PER_SERVER = 120, LOG_TAIL_LINES = 12, FLAP_WINDOW_MS, RECOVERY_HOLD_MS, SINGLE_APP_KEY = "__app__", MEMORY, HEALTH_SNAPSHOTS, TRACKED_CONTAINERS, LOCAL_SERVER_KEY = "__local__", sweepChain, KNOWN_STATES, INCIDENT_RETENTION_DAYS = 30;
|
|
316422
316515
|
var init_health_watch = __esm(async () => {
|
|
316423
316516
|
init_src2();
|
|
316424
316517
|
init_src();
|
|
@@ -316437,6 +316530,8 @@ var init_health_watch = __esm(async () => {
|
|
|
316437
316530
|
FLAP_WINDOW_MS = 10 * 60000;
|
|
316438
316531
|
RECOVERY_HOLD_MS = 2 * 60000;
|
|
316439
316532
|
MEMORY = new Map;
|
|
316533
|
+
HEALTH_SNAPSHOTS = new Map;
|
|
316534
|
+
TRACKED_CONTAINERS = new Map;
|
|
316440
316535
|
sweepChain = Promise.resolve();
|
|
316441
316536
|
KNOWN_STATES = new Set([
|
|
316442
316537
|
"created",
|
|
@@ -344050,6 +344145,11 @@ async function loadNames(organizationId) {
|
|
|
344050
344145
|
}
|
|
344051
344146
|
|
|
344052
344147
|
// ../api/src/modules/issues/issues.controller.ts
|
|
344148
|
+
init_env();
|
|
344149
|
+
await __promiseAll([
|
|
344150
|
+
init_health_watch(),
|
|
344151
|
+
init_src3()
|
|
344152
|
+
]);
|
|
344053
344153
|
async function listIssues(c2) {
|
|
344054
344154
|
const ctx2 = getRequestContext(c2);
|
|
344055
344155
|
const status = c2.req.query("status") === "resolved" ? "resolved" : "open";
|
|
@@ -344061,30 +344161,72 @@ async function issuesSummary(c2) {
|
|
|
344061
344161
|
const { counts } = await listOrganizationIssues(ctx2);
|
|
344062
344162
|
return c2.json({ data: counts });
|
|
344063
344163
|
}
|
|
344164
|
+
async function healthSnapshot(c2) {
|
|
344165
|
+
const ctx2 = getRequestContext(c2);
|
|
344166
|
+
const [rows, job2, servers2] = await Promise.all([
|
|
344167
|
+
Promise.resolve(listWorkloadHealthSnapshots(ctx2.organizationId)),
|
|
344168
|
+
repos.job.findByKey("services:health-watch"),
|
|
344169
|
+
repos.server.listByOrganization(ctx2.organizationId)
|
|
344170
|
+
]);
|
|
344171
|
+
const serverNames = new Map(servers2.map((server) => [server.id, server.name ?? server.sshHost]));
|
|
344172
|
+
return c2.json({
|
|
344173
|
+
data: rows.map((row) => ({
|
|
344174
|
+
...row,
|
|
344175
|
+
serverName: row.serverId ? serverNames.get(row.serverId) ?? row.serverId : "This server"
|
|
344176
|
+
})),
|
|
344177
|
+
watching: job2?.enabled ?? false,
|
|
344178
|
+
watcher: {
|
|
344179
|
+
key: "services:health-watch",
|
|
344180
|
+
schedule: job2?.cronExpression ?? null,
|
|
344181
|
+
eventsEnabled: !env.OPENSHIP_DISABLE_CONTAINER_EVENTS
|
|
344182
|
+
}
|
|
344183
|
+
});
|
|
344184
|
+
}
|
|
344064
344185
|
var RESCAN_JOBS = [
|
|
344065
344186
|
"services:health-watch",
|
|
344066
344187
|
"infra:scan",
|
|
344067
344188
|
"domains:verify-pending",
|
|
344068
344189
|
"updates:scan"
|
|
344069
344190
|
];
|
|
344191
|
+
var activeRescan = null;
|
|
344192
|
+
function rescanStatus(c2) {
|
|
344193
|
+
return c2.json({ data: activeRescan });
|
|
344194
|
+
}
|
|
344070
344195
|
async function rescanIssues(c2) {
|
|
344196
|
+
if (activeRescan?.status === "running")
|
|
344197
|
+
return c2.json({ data: activeRescan }, 202);
|
|
344071
344198
|
const available = RESCAN_JOBS.filter((key) => {
|
|
344072
344199
|
const def = SYSTEM_JOB_BY_KEY.get(key);
|
|
344073
344200
|
return !def?.available || def.available();
|
|
344074
344201
|
});
|
|
344075
344202
|
const skipped = RESCAN_JOBS.filter((key) => !available.includes(key));
|
|
344076
|
-
|
|
344077
|
-
|
|
344078
|
-
|
|
344079
|
-
|
|
344080
|
-
|
|
344081
|
-
|
|
344082
|
-
|
|
344083
|
-
|
|
344084
|
-
|
|
344203
|
+
activeRescan = {
|
|
344204
|
+
id: crypto.randomUUID(),
|
|
344205
|
+
status: "running",
|
|
344206
|
+
startedAt: new Date().toISOString(),
|
|
344207
|
+
stages: RESCAN_JOBS.map((key) => ({
|
|
344208
|
+
key,
|
|
344209
|
+
status: skipped.includes(key) ? "skipped" : "pending"
|
|
344210
|
+
}))
|
|
344211
|
+
};
|
|
344212
|
+
const session5 = activeRescan;
|
|
344213
|
+
Promise.all(available.map(async (key) => {
|
|
344214
|
+
const stage = session5.stages.find((item) => item.key === key);
|
|
344215
|
+
stage.status = "running";
|
|
344216
|
+
try {
|
|
344217
|
+
const result = await runJobNow(key);
|
|
344218
|
+
stage.status = "completed";
|
|
344219
|
+
stage.summary = result.summary ?? {};
|
|
344220
|
+
} catch (err2) {
|
|
344221
|
+
stage.status = "failed";
|
|
344222
|
+
stage.error = err2?.message ?? "failed";
|
|
344223
|
+
}
|
|
344224
|
+
})).finally(() => {
|
|
344225
|
+
session5.status = "completed";
|
|
344226
|
+
session5.finishedAt = new Date().toISOString();
|
|
344085
344227
|
});
|
|
344086
|
-
c2.set("auditAfter", {
|
|
344087
|
-
return c2.json({ data:
|
|
344228
|
+
c2.set("auditAfter", { scanSessionId: session5.id, stages: available, skipped });
|
|
344229
|
+
return c2.json({ data: session5 }, 202);
|
|
344088
344230
|
}
|
|
344089
344231
|
|
|
344090
344232
|
// ../api/src/modules/issues/issues.routes.ts
|
|
@@ -344104,6 +344246,13 @@ r11.get("/summary", {
|
|
|
344104
344246
|
description: "Counts only from the same feed as GET /issues: {outage, actionRequired, advisory, total}. Use for a quick health verdict; read GET /issues for the rows and their fixes."
|
|
344105
344247
|
}
|
|
344106
344248
|
}, issuesSummary);
|
|
344249
|
+
r11.get("/health", {
|
|
344250
|
+
tag: "project:list",
|
|
344251
|
+
localOnly: true,
|
|
344252
|
+
mcp: {
|
|
344253
|
+
description: "Latest health-watch snapshot for every expected workload in the organization. Cached only: this read performs no Docker polling. Includes healthy, unhealthy, crash-looping, down and unknown states plus watcher enabled status."
|
|
344254
|
+
}
|
|
344255
|
+
}, healthSnapshot);
|
|
344107
344256
|
r11.post("/rescan", {
|
|
344108
344257
|
tag: "job:write",
|
|
344109
344258
|
collection: true,
|
|
@@ -344112,6 +344261,7 @@ r11.post("/rescan", {
|
|
|
344112
344261
|
description: "Run the checkers behind GET /issues immediately (health watch, managed-container scan, pending domain verification, update scan) instead of waiting for their schedules, then re-read GET /issues. Returns which jobs ran, which were skipped as not applicable to this platform, and which failed. Adds no new probing — these are the same scheduled jobs, recorded in the jobs history as manual runs. Self-hosted only."
|
|
344113
344262
|
}
|
|
344114
344263
|
}, rescanIssues);
|
|
344264
|
+
r11.get("/rescan/status", { tag: "job:read", localOnly: true }, rescanStatus);
|
|
344115
344265
|
var issuesRoutes = r11.hono;
|
|
344116
344266
|
|
|
344117
344267
|
// ../api/src/modules/jobs/job.routes.ts
|
|
@@ -344646,6 +344796,7 @@ var HealthcheckSchema = Type.Object({
|
|
|
344646
344796
|
}, { additionalProperties: false });
|
|
344647
344797
|
var AdvancedSchema = Type.Object({
|
|
344648
344798
|
healthcheck: Type.Optional(Type.Union([HealthcheckSchema, Type.Null()])),
|
|
344799
|
+
monitoringEnabled: Type.Optional(Type.Union([Type.Boolean(), Type.Null()])),
|
|
344649
344800
|
readiness: Type.Optional(Type.Union([
|
|
344650
344801
|
Type.Object({
|
|
344651
344802
|
enabled: Type.Optional(Type.Boolean()),
|
|
@@ -7,8 +7,8 @@ import {
|
|
|
7
7
|
runHeadlessProvision,
|
|
8
8
|
startService,
|
|
9
9
|
upCommand
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-FCGJN5Q5.js";
|
|
11
|
+
import "./chunk-634DDFT5.js";
|
|
12
12
|
import "./chunk-7YBWXEM6.js";
|
|
13
13
|
import "./chunk-5UXHT6ED.js";
|
|
14
14
|
import "./chunk-QWHBRY2K.js";
|