@rallycry/conveyor-k3 0.1.8 → 0.1.10

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 CHANGED
@@ -127,6 +127,21 @@ var init_exec = __esm({
127
127
  }
128
128
  });
129
129
 
130
+ // src/vm/memory-budget.ts
131
+ function vmHostMemoryGiB(guestGiB) {
132
+ return guestGiB + Math.max(1, guestGiB / 4);
133
+ }
134
+ function maximumGuestMemoryGiB(hostBytes) {
135
+ if (!Number.isFinite(hostBytes) || hostBytes <= 0) return 0;
136
+ const budget = hostBytes / 1024 ** 3 * 0.75;
137
+ return Math.max(0, Math.floor(Math.min(budget - 1, budget / 1.25)));
138
+ }
139
+ var init_memory_budget = __esm({
140
+ "src/vm/memory-budget.ts"() {
141
+ "use strict";
142
+ }
143
+ });
144
+
130
145
  // src/vm/config.ts
131
146
  import { cpus, freemem, totalmem } from "os";
132
147
  import { stringify as stringify2 } from "yaml";
@@ -139,8 +154,10 @@ function validateResources(resources, host = { cpus: cpus().length, memory: tota
139
154
  if (!Number.isInteger(count) || count < 1 || count > Math.max(1, host.cpus - 1)) {
140
155
  throw new Error("CPU allocation must leave at least one host CPU available.");
141
156
  }
142
- if (!Number.isInteger(memoryGiB) || memoryGiB < 2 || memoryGiB * GIB > host.memory * 0.75) {
143
- throw new Error("VM memory must be at least 2 GiB and leave 25% of host memory available.");
157
+ if (!Number.isInteger(memoryGiB) || memoryGiB < 2 || vmHostMemoryGiB(memoryGiB) * GIB > host.memory * 0.75) {
158
+ throw new Error(
159
+ "VM memory must be at least 2 GiB and leave 25% of host memory available, including QEMU and relay overhead."
160
+ );
144
161
  }
145
162
  if (!Number.isInteger(diskGiB) || diskGiB < 20 || diskGiB > 512) {
146
163
  throw new Error("VM disk must be between 20 and 512 GiB.");
@@ -193,10 +210,18 @@ function parseInstallUrl(value) {
193
210
  throw new Error("Install URL is missing its enrollment token.");
194
211
  return url;
195
212
  }
213
+ function validateStartupMemory(memoryGiB, hostBytes = totalmem()) {
214
+ if (memoryGiB > maximumGuestMemoryGiB(hostBytes)) {
215
+ throw new Error(
216
+ "VM memory plus host overhead must leave 25% of host RAM available. Reduce the memory allocation before starting."
217
+ );
218
+ }
219
+ }
196
220
  var VM_NAME, GIB, IMAGES;
197
221
  var init_config = __esm({
198
222
  "src/vm/config.ts"() {
199
223
  "use strict";
224
+ init_memory_budget();
200
225
  VM_NAME = "conveyor";
201
226
  GIB = 1024 ** 3;
202
227
  IMAGES = {
@@ -1198,6 +1223,7 @@ async function createVm(ports, resources, installUrl) {
1198
1223
  async function startVm(ports, state) {
1199
1224
  ports.log("Checking VM configuration and current state\u2026");
1200
1225
  await assertTemplateUnchanged(ports.paths, state);
1226
+ validateStartupMemory(state.resources.memoryGiB, ports.hostMemory?.());
1201
1227
  const status = await vmStatus(ports, state);
1202
1228
  const stopped = status.status === "Stopped";
1203
1229
  if (!stopped && status.status !== "Running") {
@@ -9274,6 +9300,7 @@ Documentation=https://conveyor.rallycryapp.com/docs/guides/managed-personal-comp
9274
9300
 
9275
9301
  [Service]
9276
9302
  Type=oneshot
9303
+ User=root
9277
9304
  EnvironmentFile=${ENV_FILE}
9278
9305
  ExecStart=${options.cliBin} update
9279
9306
  StandardOutput=journal
package/dist/index.d.ts CHANGED
@@ -774,4 +774,7 @@ interface QemuPolicyContext {
774
774
  /** Rewrites only a complete, known Lima QEMU profile; every unknown input fails closed. */
775
775
  declare function rewriteQemuArgs(args: string[], network: QemuNetworkPolicy, ncPath?: string, context?: QemuPolicyContext): string[];
776
776
 
777
- export { ClusterConnection, type ClusterConnectionConfig, ClusterDaemon, CommandError, type CrictlImage, type DaemonPorts, type Executor, type FileSystemPort$1 as FileSystemPort, type GuestDnsProvision, type GuestSrvRecord, HELP, type ImageInventory, K3S_DISABLED_COMPONENTS, K3S_INSTALL_EXEC, type K3sUpgradeDecision, type MachineState, type NetworkEndpoint, type NetworkPolicy, type QemuNetworkPolicy, type ReconcileContext, type ReconcileResult, type RegistriesFile, type ResolvedNetwork, type ResolvedNetworkHost, type SRVLookup, type UninstallResult, type UnitRenderOptions, VERBS, type Verb, cloudflaredSrvRecords, collectHeartbeat, configuredAuthHosts, countRunningConveyorPods, createMemoryFileSystem, decideK3sUpgrade, isGloballyRoutableIPv4, isVerb, meetsK3sMinimum, missingAuthHosts, nodeFileSystem, ownerConfiguredKeys, ownerConfiguredKubeletFlags, parseArgs, parseK3sVersion, parseRegistries, pruneStrandedImages, readImageInventory, readState, reconcile, registryAdd, registryList, renderAllUnits, renderGuestDnsProvision, renderK3sDropIn, renderKubeletDropIn, renderRegistryAuthSummary, resolveCloudflaredSrvRecords, resolveNetwork, rewriteQemuArgs, runOrThrow, runUpdate, selectStrandedImages, serializeRegistries, spawnExecutor, uninstall, upsertRegistryAuth, warmImages, writeState };
777
+ /** Reserve 25% of physical host RAM after accounting for VM overhead. */
778
+ declare function maximumGuestMemoryGiB(hostBytes: number): number;
779
+
780
+ export { ClusterConnection, type ClusterConnectionConfig, ClusterDaemon, CommandError, type CrictlImage, type DaemonPorts, type Executor, type FileSystemPort$1 as FileSystemPort, type GuestDnsProvision, type GuestSrvRecord, HELP, type ImageInventory, K3S_DISABLED_COMPONENTS, K3S_INSTALL_EXEC, type K3sUpgradeDecision, type MachineState, type NetworkEndpoint, type NetworkPolicy, type QemuNetworkPolicy, type ReconcileContext, type ReconcileResult, type RegistriesFile, type ResolvedNetwork, type ResolvedNetworkHost, type SRVLookup, type UninstallResult, type UnitRenderOptions, VERBS, type Verb, cloudflaredSrvRecords, collectHeartbeat, configuredAuthHosts, countRunningConveyorPods, createMemoryFileSystem, decideK3sUpgrade, isGloballyRoutableIPv4, isVerb, maximumGuestMemoryGiB, meetsK3sMinimum, missingAuthHosts, nodeFileSystem, ownerConfiguredKeys, ownerConfiguredKubeletFlags, parseArgs, parseK3sVersion, parseRegistries, pruneStrandedImages, readImageInventory, readState, reconcile, registryAdd, registryList, renderAllUnits, renderGuestDnsProvision, renderK3sDropIn, renderKubeletDropIn, renderRegistryAuthSummary, resolveCloudflaredSrvRecords, resolveNetwork, rewriteQemuArgs, runOrThrow, runUpdate, selectStrandedImages, serializeRegistries, spawnExecutor, uninstall, upsertRegistryAuth, warmImages, writeState };
package/dist/index.js CHANGED
@@ -7723,6 +7723,7 @@ Documentation=https://conveyor.rallycryapp.com/docs/guides/managed-personal-comp
7723
7723
 
7724
7724
  [Service]
7725
7725
  Type=oneshot
7726
+ User=root
7726
7727
  EnvironmentFile=${ENV_FILE}
7727
7728
  ExecStart=${options.cliBin} update
7728
7729
  StandardOutput=journal
@@ -8850,6 +8851,13 @@ function rewriteQemuArgs(args, network, ncPath = "/usr/bin/nc", context = {}) {
8850
8851
  assertCompleteProfile(state);
8851
8852
  return output;
8852
8853
  }
8854
+
8855
+ // src/vm/memory-budget.ts
8856
+ function maximumGuestMemoryGiB(hostBytes) {
8857
+ if (!Number.isFinite(hostBytes) || hostBytes <= 0) return 0;
8858
+ const budget = hostBytes / 1024 ** 3 * 0.75;
8859
+ return Math.max(0, Math.floor(Math.min(budget - 1, budget / 1.25)));
8860
+ }
8853
8861
  export {
8854
8862
  ClusterConnection,
8855
8863
  ClusterDaemon,
@@ -8866,6 +8874,7 @@ export {
8866
8874
  decideK3sUpgrade,
8867
8875
  isGloballyRoutableIPv4,
8868
8876
  isVerb,
8877
+ maximumGuestMemoryGiB,
8869
8878
  meetsK3sMinimum,
8870
8879
  missingAuthHosts,
8871
8880
  nodeFileSystem,
package/dist/vm-qemu.js CHANGED
@@ -744,6 +744,11 @@ function runRelayNow(root, invocation, io) {
744
744
  });
745
745
  }
746
746
 
747
+ // src/vm/memory-budget.ts
748
+ function vmHostMemoryGiB(guestGiB) {
749
+ return guestGiB + Math.max(1, guestGiB / 4);
750
+ }
751
+
747
752
  // src/vm/resource-guard.ts
748
753
  var GIB = 1024 ** 3;
749
754
  var GUARD_INTERVAL_MS = 2e3;
@@ -753,7 +758,9 @@ function guardLimits(resources) {
753
758
  }
754
759
  return {
755
760
  minFreeBytes: 10 * GIB,
756
- maxRssKiB: (resources.memoryGiB + 1) * 1024 ** 2,
761
+ // A 24 GiB Mac guest exceeded 27 GiB during image unpacking. Allow 25%
762
+ // overhead (at least 1 GiB); admission reserves host RAM using this same cap.
763
+ maxRssKiB: vmHostMemoryGiB(resources.memoryGiB) * 1024 ** 2,
757
764
  maxProcesses: 64,
758
765
  maxOutputBytes: 1024 * 1024,
759
766
  maxDiskBytes: (resources.diskGiB + 1) * GIB,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rallycry/conveyor-k3",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "Managed personal compute for Conveyor. Installs and maintains a k3s cluster that runs your own card builds, kept converged on Conveyor's desired state.",
5
5
  "keywords": [
6
6
  "cloudflared",