freestyle-sandboxes 0.1.39 → 0.1.40
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/index.cjs +328 -114
- package/index.d.cts +33 -4
- package/index.d.mts +33 -4
- package/index.mjs +328 -114
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -6007,6 +6007,64 @@ function composeVmSpecs(specs) {
|
|
|
6007
6007
|
}
|
|
6008
6008
|
|
|
6009
6009
|
const DEFAULT_CONFIGURE_BASE_IMAGE = "FROM debian:trixie-slim";
|
|
6010
|
+
const RUN_COMMANDS_SYSTEMD_SERVICE_PREFIX = "freestyle-run-command";
|
|
6011
|
+
const WAIT_FOR_SYSTEMD_SERVICE_PREFIX = "freestyle-wait-for";
|
|
6012
|
+
function escapeRegExp(value) {
|
|
6013
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6014
|
+
}
|
|
6015
|
+
function getGeneratedServiceState(services, prefix) {
|
|
6016
|
+
const generatedPrefixes = [
|
|
6017
|
+
RUN_COMMANDS_SYSTEMD_SERVICE_PREFIX,
|
|
6018
|
+
WAIT_FOR_SYSTEMD_SERVICE_PREFIX
|
|
6019
|
+
];
|
|
6020
|
+
let maxIndex = 0;
|
|
6021
|
+
let lastGeneratedServiceName;
|
|
6022
|
+
for (const service of services) {
|
|
6023
|
+
if (!service.name) {
|
|
6024
|
+
continue;
|
|
6025
|
+
}
|
|
6026
|
+
for (const generatedPrefix of generatedPrefixes) {
|
|
6027
|
+
const match = service.name.match(
|
|
6028
|
+
new RegExp(`^${escapeRegExp(generatedPrefix)}-(\\d+)$`)
|
|
6029
|
+
);
|
|
6030
|
+
if (!match) {
|
|
6031
|
+
continue;
|
|
6032
|
+
}
|
|
6033
|
+
if (generatedPrefix === prefix) {
|
|
6034
|
+
const index = Number.parseInt(match[1] ?? "0", 10);
|
|
6035
|
+
if (index > maxIndex) {
|
|
6036
|
+
maxIndex = index;
|
|
6037
|
+
}
|
|
6038
|
+
}
|
|
6039
|
+
lastGeneratedServiceName = service.name;
|
|
6040
|
+
break;
|
|
6041
|
+
}
|
|
6042
|
+
}
|
|
6043
|
+
return { maxIndex, lastGeneratedServiceName };
|
|
6044
|
+
}
|
|
6045
|
+
function appendServiceDependency(dependencies, dependency) {
|
|
6046
|
+
if (!dependency) {
|
|
6047
|
+
return dependencies ?? void 0;
|
|
6048
|
+
}
|
|
6049
|
+
const values = [...dependencies ?? []];
|
|
6050
|
+
if (!values.includes(dependency)) {
|
|
6051
|
+
values.push(dependency);
|
|
6052
|
+
}
|
|
6053
|
+
return values;
|
|
6054
|
+
}
|
|
6055
|
+
function buildWaitForScript(command, intervalSeconds) {
|
|
6056
|
+
const body = command.trim().split("\n").map((line) => ` ${line}`).join("\n");
|
|
6057
|
+
return [
|
|
6058
|
+
"while true; do",
|
|
6059
|
+
" if (",
|
|
6060
|
+
body,
|
|
6061
|
+
" ); then",
|
|
6062
|
+
" exit 0",
|
|
6063
|
+
" fi",
|
|
6064
|
+
` sleep ${intervalSeconds}`,
|
|
6065
|
+
"done"
|
|
6066
|
+
].join("\n");
|
|
6067
|
+
}
|
|
6010
6068
|
function processSystemdServices(services, existingFiles = {}) {
|
|
6011
6069
|
const additionalFiles = { ...existingFiles };
|
|
6012
6070
|
const processedServices = [];
|
|
@@ -6041,6 +6099,63 @@ ${bash}`;
|
|
|
6041
6099
|
}
|
|
6042
6100
|
return { services: processedServices, additionalFiles };
|
|
6043
6101
|
}
|
|
6102
|
+
function normalizeSystemdServices(services) {
|
|
6103
|
+
return services.map((service) => ({
|
|
6104
|
+
...service,
|
|
6105
|
+
after: service.after?.map((s) => s.includes(".") ? s : `${s}.service`),
|
|
6106
|
+
requires: service.requires?.map(
|
|
6107
|
+
(s) => s.includes(".") ? s : `${s}.service`
|
|
6108
|
+
),
|
|
6109
|
+
wantedBy: service.wantedBy?.map(
|
|
6110
|
+
(s) => s.includes(".") ? s : `${s}.service`
|
|
6111
|
+
)
|
|
6112
|
+
}));
|
|
6113
|
+
}
|
|
6114
|
+
function normalizePatchedServices(services) {
|
|
6115
|
+
return services.map((service) => ({
|
|
6116
|
+
...service,
|
|
6117
|
+
after: service.after?.map((s) => s.includes(".") ? s : `${s}.service`),
|
|
6118
|
+
requires: service.requires?.map(
|
|
6119
|
+
(s) => s.includes(".") ? s : `${s}.service`
|
|
6120
|
+
),
|
|
6121
|
+
wantedBy: service.wantedBy?.map(
|
|
6122
|
+
(s) => s.includes(".") ? s : `${s}.service`
|
|
6123
|
+
)
|
|
6124
|
+
}));
|
|
6125
|
+
}
|
|
6126
|
+
function normalizeTemplateForRequest(template) {
|
|
6127
|
+
const normalizedTemplate = {
|
|
6128
|
+
...template ?? {}
|
|
6129
|
+
};
|
|
6130
|
+
if (normalizedTemplate.template) {
|
|
6131
|
+
normalizedTemplate.template = normalizeTemplateForRequest(
|
|
6132
|
+
normalizedTemplate.template
|
|
6133
|
+
);
|
|
6134
|
+
}
|
|
6135
|
+
if (normalizedTemplate.baseImage) {
|
|
6136
|
+
normalizedTemplate.baseImage = normalizeBaseImage(
|
|
6137
|
+
normalizedTemplate.baseImage
|
|
6138
|
+
)?.toRaw();
|
|
6139
|
+
}
|
|
6140
|
+
normalizedTemplate.git = normalizeGitOptions(normalizedTemplate.git);
|
|
6141
|
+
if (normalizedTemplate.systemd?.services) {
|
|
6142
|
+
const normalizedServices = normalizeSystemdServices(
|
|
6143
|
+
normalizedTemplate.systemd.services
|
|
6144
|
+
);
|
|
6145
|
+
const { services: processedServices, additionalFiles: bashFiles } = processSystemdServices(
|
|
6146
|
+
normalizedServices,
|
|
6147
|
+
normalizedTemplate.additionalFiles ?? {}
|
|
6148
|
+
);
|
|
6149
|
+
normalizedTemplate.systemd.services = processedServices;
|
|
6150
|
+
normalizedTemplate.additionalFiles = bashFiles;
|
|
6151
|
+
}
|
|
6152
|
+
if (normalizedTemplate.systemd?.patchedServices) {
|
|
6153
|
+
normalizedTemplate.systemd.patchedServices = normalizePatchedServices(
|
|
6154
|
+
normalizedTemplate.systemd.patchedServices
|
|
6155
|
+
);
|
|
6156
|
+
}
|
|
6157
|
+
return normalizedTemplate;
|
|
6158
|
+
}
|
|
6044
6159
|
function normalizeGitOptions(git) {
|
|
6045
6160
|
if (!git) return git;
|
|
6046
6161
|
return {
|
|
@@ -6236,10 +6351,12 @@ class Vm {
|
|
|
6236
6351
|
params: { vm_id: this.vmId },
|
|
6237
6352
|
body: options
|
|
6238
6353
|
});
|
|
6239
|
-
const vmId = response.id;
|
|
6240
6354
|
return {
|
|
6241
|
-
|
|
6242
|
-
|
|
6355
|
+
forks: response.forks.map((fork) => ({
|
|
6356
|
+
vmId: fork.id,
|
|
6357
|
+
vm: this._freestyle.vms.ref({ vmId: fork.id })
|
|
6358
|
+
// Create a new Vm instance for the forked VM
|
|
6359
|
+
}))
|
|
6243
6360
|
};
|
|
6244
6361
|
}
|
|
6245
6362
|
/**
|
|
@@ -6388,10 +6505,14 @@ class VmSpec {
|
|
|
6388
6505
|
return { ...this.withDiscriminators };
|
|
6389
6506
|
}
|
|
6390
6507
|
mergeRaw(options) {
|
|
6508
|
+
const existingSnapshot = this.raw.snapshot;
|
|
6391
6509
|
this.raw = composeCreateVmOptions([
|
|
6392
6510
|
this.raw,
|
|
6393
6511
|
options
|
|
6394
6512
|
]);
|
|
6513
|
+
if (existingSnapshot !== void 0 && this.raw.snapshot === void 0) {
|
|
6514
|
+
this.raw.snapshot = existingSnapshot;
|
|
6515
|
+
}
|
|
6395
6516
|
return this;
|
|
6396
6517
|
}
|
|
6397
6518
|
clearBuilders() {
|
|
@@ -6475,9 +6596,74 @@ class VmSpec {
|
|
|
6475
6596
|
return this;
|
|
6476
6597
|
}
|
|
6477
6598
|
runCommands(...commands) {
|
|
6478
|
-
const
|
|
6479
|
-
|
|
6480
|
-
|
|
6599
|
+
const normalizedCommands = commands.map((command) => command.trim()).filter((command) => command.length > 0);
|
|
6600
|
+
if (normalizedCommands.length === 0) {
|
|
6601
|
+
return this;
|
|
6602
|
+
}
|
|
6603
|
+
const existingSystemd = this.raw.systemd ?? {};
|
|
6604
|
+
const existingServices = [...existingSystemd.services ?? []];
|
|
6605
|
+
let { maxIndex: maxRunCommandIndex, lastGeneratedServiceName } = getGeneratedServiceState(
|
|
6606
|
+
existingServices,
|
|
6607
|
+
RUN_COMMANDS_SYSTEMD_SERVICE_PREFIX
|
|
6608
|
+
);
|
|
6609
|
+
for (const command of normalizedCommands) {
|
|
6610
|
+
const nextIndex = ++maxRunCommandIndex;
|
|
6611
|
+
const serviceName = `${RUN_COMMANDS_SYSTEMD_SERVICE_PREFIX}-${nextIndex}`;
|
|
6612
|
+
existingServices.push({
|
|
6613
|
+
name: serviceName,
|
|
6614
|
+
mode: "oneshot",
|
|
6615
|
+
deleteAfterSuccess: true,
|
|
6616
|
+
bash: command,
|
|
6617
|
+
...lastGeneratedServiceName ? {
|
|
6618
|
+
after: [lastGeneratedServiceName],
|
|
6619
|
+
requires: [lastGeneratedServiceName]
|
|
6620
|
+
} : {}
|
|
6621
|
+
});
|
|
6622
|
+
lastGeneratedServiceName = serviceName;
|
|
6623
|
+
}
|
|
6624
|
+
this.raw.systemd = {
|
|
6625
|
+
...existingSystemd,
|
|
6626
|
+
services: existingServices
|
|
6627
|
+
};
|
|
6628
|
+
return this;
|
|
6629
|
+
}
|
|
6630
|
+
waitFor(command, config = {}) {
|
|
6631
|
+
const trimmedCommand = command.trim();
|
|
6632
|
+
if (!trimmedCommand) {
|
|
6633
|
+
throw new Error("VmSpec.waitFor requires a non-empty command");
|
|
6634
|
+
}
|
|
6635
|
+
const intervalSeconds = config.intervalSeconds ?? 2;
|
|
6636
|
+
if (!Number.isFinite(intervalSeconds) || intervalSeconds <= 0) {
|
|
6637
|
+
throw new Error("VmSpec.waitFor intervalSeconds must be greater than 0");
|
|
6638
|
+
}
|
|
6639
|
+
const existingSystemd = this.raw.systemd ?? {};
|
|
6640
|
+
const existingServices = [...existingSystemd.services ?? []];
|
|
6641
|
+
const { maxIndex, lastGeneratedServiceName } = getGeneratedServiceState(
|
|
6642
|
+
existingServices,
|
|
6643
|
+
WAIT_FOR_SYSTEMD_SERVICE_PREFIX
|
|
6644
|
+
);
|
|
6645
|
+
const {
|
|
6646
|
+
intervalSeconds: _intervalSeconds,
|
|
6647
|
+
name,
|
|
6648
|
+
after,
|
|
6649
|
+
requires,
|
|
6650
|
+
timeoutSec,
|
|
6651
|
+
...rest
|
|
6652
|
+
} = config;
|
|
6653
|
+
existingServices.push({
|
|
6654
|
+
...rest,
|
|
6655
|
+
name: name ?? `${WAIT_FOR_SYSTEMD_SERVICE_PREFIX}-${maxIndex + 1}`,
|
|
6656
|
+
mode: "oneshot",
|
|
6657
|
+
// deleteAfterSuccess: true,
|
|
6658
|
+
timeoutSec: timeoutSec ?? 0,
|
|
6659
|
+
after: appendServiceDependency(after, lastGeneratedServiceName),
|
|
6660
|
+
requires: appendServiceDependency(requires, lastGeneratedServiceName),
|
|
6661
|
+
bash: buildWaitForScript(trimmedCommand, intervalSeconds)
|
|
6662
|
+
});
|
|
6663
|
+
this.raw.systemd = {
|
|
6664
|
+
...existingSystemd,
|
|
6665
|
+
services: existingServices
|
|
6666
|
+
};
|
|
6481
6667
|
return this;
|
|
6482
6668
|
}
|
|
6483
6669
|
repo(repo, path) {
|
|
@@ -6504,7 +6690,7 @@ class VmSpec {
|
|
|
6504
6690
|
function isVmSpecLike$1(value) {
|
|
6505
6691
|
return !!value && typeof value === "object" && "raw" in value && "with" in value;
|
|
6506
6692
|
}
|
|
6507
|
-
function isVmTemplateLike(value) {
|
|
6693
|
+
function isVmTemplateLike$1(value) {
|
|
6508
6694
|
return !!value && typeof value === "object" && "raw" in value && "with" in value;
|
|
6509
6695
|
}
|
|
6510
6696
|
async function convertSpecSnapshotsToTemplates(spec, processBuilders = true) {
|
|
@@ -6630,21 +6816,8 @@ class VmsNamespace {
|
|
|
6630
6816
|
}
|
|
6631
6817
|
}
|
|
6632
6818
|
if (options.systemd?.services) {
|
|
6633
|
-
const normalizedServices =
|
|
6634
|
-
|
|
6635
|
-
return {
|
|
6636
|
-
...service,
|
|
6637
|
-
after: service.after?.map(
|
|
6638
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6639
|
-
),
|
|
6640
|
-
requires: service.requires?.map(
|
|
6641
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6642
|
-
),
|
|
6643
|
-
wantedBy: service.wantedBy?.map(
|
|
6644
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6645
|
-
)
|
|
6646
|
-
};
|
|
6647
|
-
}
|
|
6819
|
+
const normalizedServices = normalizeSystemdServices(
|
|
6820
|
+
options.systemd.services
|
|
6648
6821
|
);
|
|
6649
6822
|
const { services: processedServices, additionalFiles: bashFiles } = processSystemdServices(
|
|
6650
6823
|
normalizedServices,
|
|
@@ -6654,19 +6827,8 @@ class VmsNamespace {
|
|
|
6654
6827
|
options.additionalFiles = bashFiles;
|
|
6655
6828
|
}
|
|
6656
6829
|
if (options.systemd?.patchedServices) {
|
|
6657
|
-
options.systemd.patchedServices =
|
|
6658
|
-
|
|
6659
|
-
service.after = service.after?.map(
|
|
6660
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6661
|
-
);
|
|
6662
|
-
service.requires = service.requires?.map(
|
|
6663
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6664
|
-
);
|
|
6665
|
-
service.wantedBy = service.wantedBy?.map(
|
|
6666
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6667
|
-
);
|
|
6668
|
-
return service;
|
|
6669
|
-
}
|
|
6830
|
+
options.systemd.patchedServices = normalizePatchedServices(
|
|
6831
|
+
options.systemd.patchedServices
|
|
6670
6832
|
);
|
|
6671
6833
|
}
|
|
6672
6834
|
if ("snapshot" in options) {
|
|
@@ -6699,7 +6861,7 @@ class VmsNamespace {
|
|
|
6699
6861
|
const specBuilders = isVmSpecLike$1(
|
|
6700
6862
|
options.spec
|
|
6701
6863
|
) ? collectSpecBuilders(options.spec) : void 0;
|
|
6702
|
-
const templateBuilders = isVmTemplateLike(options.template) ? options.template.with : void 0;
|
|
6864
|
+
const templateBuilders = isVmTemplateLike$1(options.template) ? options.template.with : void 0;
|
|
6703
6865
|
const builders = {
|
|
6704
6866
|
...templateBuilders || {},
|
|
6705
6867
|
...specBuilders || {},
|
|
@@ -6707,10 +6869,10 @@ class VmsNamespace {
|
|
|
6707
6869
|
};
|
|
6708
6870
|
const { with: _, spec: _spec, ...baseConfig } = options;
|
|
6709
6871
|
let config = baseConfig;
|
|
6710
|
-
if (isVmTemplateLike(config.template)) {
|
|
6872
|
+
if (isVmTemplateLike$1(config.template)) {
|
|
6711
6873
|
config.template = await processTemplateTree(config.template);
|
|
6712
6874
|
}
|
|
6713
|
-
if (isVmTemplateLike(config.template)) {
|
|
6875
|
+
if (isVmTemplateLike$1(config.template)) {
|
|
6714
6876
|
config.template = await ensureNestedTemplates(
|
|
6715
6877
|
config.template,
|
|
6716
6878
|
this.snapshots
|
|
@@ -6724,18 +6886,9 @@ class VmsNamespace {
|
|
|
6724
6886
|
}
|
|
6725
6887
|
}
|
|
6726
6888
|
if (config.systemd?.services) {
|
|
6727
|
-
const normalizedServices =
|
|
6728
|
-
|
|
6729
|
-
|
|
6730
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6731
|
-
),
|
|
6732
|
-
requires: service.requires?.map(
|
|
6733
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6734
|
-
),
|
|
6735
|
-
wantedBy: service.wantedBy?.map(
|
|
6736
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6737
|
-
)
|
|
6738
|
-
}));
|
|
6889
|
+
const normalizedServices = normalizeSystemdServices(
|
|
6890
|
+
config.systemd.services
|
|
6891
|
+
);
|
|
6739
6892
|
const { services: processedServices, additionalFiles: bashFiles } = processSystemdServices(
|
|
6740
6893
|
normalizedServices,
|
|
6741
6894
|
config.additionalFiles ?? {}
|
|
@@ -6744,28 +6897,20 @@ class VmsNamespace {
|
|
|
6744
6897
|
config.additionalFiles = bashFiles;
|
|
6745
6898
|
}
|
|
6746
6899
|
if (config.systemd?.patchedServices) {
|
|
6747
|
-
config.systemd.patchedServices =
|
|
6748
|
-
|
|
6749
|
-
service.after = service.after?.map(
|
|
6750
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6751
|
-
);
|
|
6752
|
-
service.requires = service.requires?.map(
|
|
6753
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6754
|
-
);
|
|
6755
|
-
service.wantedBy = service.wantedBy?.map(
|
|
6756
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6757
|
-
);
|
|
6758
|
-
return service;
|
|
6759
|
-
}
|
|
6900
|
+
config.systemd.patchedServices = normalizePatchedServices(
|
|
6901
|
+
config.systemd.patchedServices
|
|
6760
6902
|
);
|
|
6761
6903
|
}
|
|
6762
6904
|
config.git = normalizeGitOptions(config.git);
|
|
6763
6905
|
const serializedBaseImage = normalizeBaseImage(config.baseImage)?.toRaw();
|
|
6764
|
-
const rawTemplate = isVmTemplateLike(config.template) ? config.template.raw : config.template;
|
|
6906
|
+
const rawTemplate = isVmTemplateLike$1(config.template) ? config.template.raw : config.template;
|
|
6765
6907
|
const requestTemplate = serializedBaseImage ? {
|
|
6766
6908
|
...rawTemplate ?? {},
|
|
6767
6909
|
baseImage: serializedBaseImage
|
|
6768
6910
|
} : rawTemplate;
|
|
6911
|
+
const normalizedRequestTemplate = requestTemplate ? normalizeTemplateForRequest(
|
|
6912
|
+
requestTemplate
|
|
6913
|
+
) : requestTemplate;
|
|
6769
6914
|
const {
|
|
6770
6915
|
baseImage: _baseImage,
|
|
6771
6916
|
template: _template,
|
|
@@ -6774,7 +6919,7 @@ class VmsNamespace {
|
|
|
6774
6919
|
const response = await this.freestyle._apiClient.post("/v1/vms", {
|
|
6775
6920
|
body: {
|
|
6776
6921
|
...requestConfig,
|
|
6777
|
-
template:
|
|
6922
|
+
template: normalizedRequestTemplate,
|
|
6778
6923
|
// Cast systemd since we've processed SystemdServiceInput[] to RawSystemdService[]
|
|
6779
6924
|
systemd: config.systemd,
|
|
6780
6925
|
// Normalize git options - default config to {}
|
|
@@ -6869,6 +7014,35 @@ function enhanceError(e) {
|
|
|
6869
7014
|
if (!e.message.includes("create --snapshot")) {
|
|
6870
7015
|
e.message = `${e.message}. Hint: use \`npx freestyle-sandboxes@latest vm create --snapshot ${e.body.snapshotId} --ssh --delete\` to debug.`;
|
|
6871
7016
|
}
|
|
7017
|
+
if (e.body.diagnostics) {
|
|
7018
|
+
const d = e.body.diagnostics;
|
|
7019
|
+
const parts = [];
|
|
7020
|
+
if (d.serviceStates.length > 0) {
|
|
7021
|
+
parts.push("Service states:");
|
|
7022
|
+
for (const g of d.serviceStates) {
|
|
7023
|
+
parts.push(
|
|
7024
|
+
` ${g.activeState}(${g.subState}): ${g.services.join(", ")}`
|
|
7025
|
+
);
|
|
7026
|
+
}
|
|
7027
|
+
}
|
|
7028
|
+
const allLogs = [
|
|
7029
|
+
...d.failedServiceLogs ?? [],
|
|
7030
|
+
...d.additionalFailedServiceLogs ?? []
|
|
7031
|
+
];
|
|
7032
|
+
if (allLogs.length > 0) {
|
|
7033
|
+
parts.push("Failed service logs:");
|
|
7034
|
+
for (const l of allLogs) {
|
|
7035
|
+
parts.push(` --- ${l.unitName} ---`);
|
|
7036
|
+
parts.push(` ${l.log}`);
|
|
7037
|
+
}
|
|
7038
|
+
}
|
|
7039
|
+
if (parts.length > 0) {
|
|
7040
|
+
e.message = `${e.message}
|
|
7041
|
+
|
|
7042
|
+
Diagnostics:
|
|
7043
|
+
${parts.join("\n")}`;
|
|
7044
|
+
}
|
|
7045
|
+
}
|
|
6872
7046
|
}
|
|
6873
7047
|
return e;
|
|
6874
7048
|
}
|
|
@@ -6936,12 +7110,12 @@ class VmSnapshotsNamespace {
|
|
|
6936
7110
|
const { spec: _spec, ...rest } = requestOptions;
|
|
6937
7111
|
requestOptions = rest;
|
|
6938
7112
|
}
|
|
6939
|
-
if (isVmTemplateLike(requestOptions.template)) {
|
|
7113
|
+
if (isVmTemplateLike$1(requestOptions.template)) {
|
|
6940
7114
|
const processedTemplate = await processTemplateTree(
|
|
6941
7115
|
requestOptions.template
|
|
6942
7116
|
);
|
|
6943
7117
|
requestOptions.template = processedTemplate;
|
|
6944
|
-
if (isVmTemplateLike(processedTemplate.raw.template)) {
|
|
7118
|
+
if (isVmTemplateLike$1(processedTemplate.raw.template)) {
|
|
6945
7119
|
requestOptions.template = await ensureNestedTemplates(
|
|
6946
7120
|
processedTemplate,
|
|
6947
7121
|
this
|
|
@@ -6956,7 +7130,9 @@ class VmSnapshotsNamespace {
|
|
|
6956
7130
|
return this.apiClient.post("/v1/vms/snapshots", {
|
|
6957
7131
|
body: {
|
|
6958
7132
|
...requestOptions,
|
|
6959
|
-
template:
|
|
7133
|
+
template: normalizeTemplateForRequest(
|
|
7134
|
+
isVmTemplateLike$1(requestOptions.template) ? requestOptions.template.raw : requestOptions.template
|
|
7135
|
+
)
|
|
6960
7136
|
}
|
|
6961
7137
|
}).catch((e) => {
|
|
6962
7138
|
enhanceError(e);
|
|
@@ -6976,22 +7152,9 @@ async function processTemplateTree(template) {
|
|
|
6976
7152
|
);
|
|
6977
7153
|
}
|
|
6978
7154
|
if (template.raw.systemd?.services) {
|
|
6979
|
-
|
|
6980
|
-
|
|
6981
|
-
after: service.after?.map((s) => s.includes(".") ? s : `${s}.service`),
|
|
6982
|
-
requires: service.requires?.map(
|
|
6983
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6984
|
-
),
|
|
6985
|
-
wantedBy: service.wantedBy?.map(
|
|
6986
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6987
|
-
)
|
|
6988
|
-
}));
|
|
6989
|
-
const { services: processedServices, additionalFiles: bashFiles } = processSystemdServices(
|
|
6990
|
-
normalizedServices,
|
|
6991
|
-
template.raw.additionalFiles ?? {}
|
|
7155
|
+
template.raw.systemd.services = normalizeSystemdServices(
|
|
7156
|
+
template.raw.systemd.services
|
|
6992
7157
|
);
|
|
6993
|
-
template.raw.systemd.services = processedServices;
|
|
6994
|
-
template.raw.additionalFiles = bashFiles;
|
|
6995
7158
|
}
|
|
6996
7159
|
for (const key in template.with) {
|
|
6997
7160
|
const builder = template.with[key];
|
|
@@ -7008,7 +7171,7 @@ async function processTemplateTree(template) {
|
|
|
7008
7171
|
}
|
|
7009
7172
|
if (builder.configureNestedTemplate) {
|
|
7010
7173
|
let nestedTemplate;
|
|
7011
|
-
if (isVmTemplateLike(template.raw.template)) {
|
|
7174
|
+
if (isVmTemplateLike$1(template.raw.template)) {
|
|
7012
7175
|
nestedTemplate = template.raw.template;
|
|
7013
7176
|
} else {
|
|
7014
7177
|
nestedTemplate = new VmTemplate({});
|
|
@@ -7031,38 +7194,16 @@ async function processTemplateTree(template) {
|
|
|
7031
7194
|
);
|
|
7032
7195
|
}
|
|
7033
7196
|
if (template.raw.systemd?.services) {
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
after: service.after?.map((s) => s.includes(".") ? s : `${s}.service`),
|
|
7037
|
-
requires: service.requires?.map(
|
|
7038
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
7039
|
-
),
|
|
7040
|
-
wantedBy: service.wantedBy?.map(
|
|
7041
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
7042
|
-
)
|
|
7043
|
-
}));
|
|
7044
|
-
const { services: processedServices, additionalFiles: bashFiles } = processSystemdServices(
|
|
7045
|
-
normalizedServices,
|
|
7046
|
-
template.raw.additionalFiles ?? {}
|
|
7197
|
+
template.raw.systemd.services = normalizeSystemdServices(
|
|
7198
|
+
template.raw.systemd.services
|
|
7047
7199
|
);
|
|
7048
|
-
template.raw.systemd.services = processedServices;
|
|
7049
|
-
template.raw.additionalFiles = bashFiles;
|
|
7050
7200
|
}
|
|
7051
7201
|
if (template.raw.systemd?.patchedServices) {
|
|
7052
|
-
template.raw.systemd.patchedServices =
|
|
7053
|
-
|
|
7054
|
-
|
|
7055
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
7056
|
-
),
|
|
7057
|
-
requires: service.requires?.map(
|
|
7058
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
7059
|
-
),
|
|
7060
|
-
wantedBy: service.wantedBy?.map(
|
|
7061
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
7062
|
-
)
|
|
7063
|
-
}));
|
|
7202
|
+
template.raw.systemd.patchedServices = normalizePatchedServices(
|
|
7203
|
+
template.raw.systemd.patchedServices
|
|
7204
|
+
);
|
|
7064
7205
|
}
|
|
7065
|
-
if (isVmTemplateLike(template.raw.template)) {
|
|
7206
|
+
if (isVmTemplateLike$1(template.raw.template)) {
|
|
7066
7207
|
template.raw.template = await processTemplateTree(
|
|
7067
7208
|
template.raw.template
|
|
7068
7209
|
);
|
|
@@ -7071,7 +7212,7 @@ async function processTemplateTree(template) {
|
|
|
7071
7212
|
}
|
|
7072
7213
|
async function ensureNestedTemplates(template, snapshots) {
|
|
7073
7214
|
const templates = [template];
|
|
7074
|
-
while (isVmTemplateLike(templates.at(-1)?.raw.template)) {
|
|
7215
|
+
while (isVmTemplateLike$1(templates.at(-1)?.raw.template)) {
|
|
7075
7216
|
const innerTemplate = templates.at(-1).raw.template;
|
|
7076
7217
|
templates.at(-1).raw.template = void 0;
|
|
7077
7218
|
templates.push(innerTemplate);
|
|
@@ -7256,7 +7397,7 @@ async function readFiles(directory) {
|
|
|
7256
7397
|
}
|
|
7257
7398
|
|
|
7258
7399
|
async function debugCreateRequests(freestyle, optionsOrSpec = {}) {
|
|
7259
|
-
const options = isVmSpecLike(optionsOrSpec) ? { spec: optionsOrSpec } : optionsOrSpec;
|
|
7400
|
+
const options = isVmSpecLike(optionsOrSpec) ? { spec: cloneVmSpec(optionsOrSpec) } : cloneCreateOptions(optionsOrSpec);
|
|
7260
7401
|
const requests = [];
|
|
7261
7402
|
let snapshotCounter = 0;
|
|
7262
7403
|
let vmCounter = 0;
|
|
@@ -7303,6 +7444,79 @@ async function debugCreateRequests(freestyle, optionsOrSpec = {}) {
|
|
|
7303
7444
|
function isVmSpecLike(value) {
|
|
7304
7445
|
return !!value && typeof value === "object" && "raw" in value && "with" in value;
|
|
7305
7446
|
}
|
|
7447
|
+
function isVmTemplateLike(value) {
|
|
7448
|
+
return !!value && typeof value === "object" && "raw" in value && "with" in value;
|
|
7449
|
+
}
|
|
7450
|
+
function cloneCreateOptions(options) {
|
|
7451
|
+
return {
|
|
7452
|
+
...clonePlainObject(options),
|
|
7453
|
+
with: options.with,
|
|
7454
|
+
template: isVmTemplateLike(options.template) ? cloneVmTemplate(options.template) : cloneValue(options.template),
|
|
7455
|
+
spec: isVmSpecLike(options.spec) ? cloneVmSpec(options.spec) : void 0,
|
|
7456
|
+
snapshot: isVmSpecLike(options.snapshot) ? cloneVmSpec(options.snapshot) : void 0
|
|
7457
|
+
};
|
|
7458
|
+
}
|
|
7459
|
+
function cloneVmSpec(spec) {
|
|
7460
|
+
const clonedRaw = cloneVmSpecRaw(spec.raw);
|
|
7461
|
+
return new VmSpec({
|
|
7462
|
+
...clonedRaw,
|
|
7463
|
+
with: { ...spec.builders },
|
|
7464
|
+
__withDiscriminators: typeof spec.getBuilderDiscriminators === "function" ? spec.getBuilderDiscriminators() : void 0
|
|
7465
|
+
});
|
|
7466
|
+
}
|
|
7467
|
+
function cloneVmTemplate(template) {
|
|
7468
|
+
const clonedRaw = cloneVmTemplateRaw(template.raw);
|
|
7469
|
+
return new VmTemplate({
|
|
7470
|
+
...clonedRaw,
|
|
7471
|
+
with: { ...template.with }
|
|
7472
|
+
});
|
|
7473
|
+
}
|
|
7474
|
+
function cloneVmSpecRaw(raw) {
|
|
7475
|
+
const cloned = cloneVmTemplateRaw(raw);
|
|
7476
|
+
if (isVmSpecLike(raw.snapshot)) {
|
|
7477
|
+
cloned.snapshot = cloneVmSpec(raw.snapshot);
|
|
7478
|
+
} else if (raw.snapshot !== void 0) {
|
|
7479
|
+
cloned.snapshot = cloneValue(raw.snapshot);
|
|
7480
|
+
}
|
|
7481
|
+
return cloned;
|
|
7482
|
+
}
|
|
7483
|
+
function cloneVmTemplateRaw(raw) {
|
|
7484
|
+
const cloned = clonePlainObject(raw);
|
|
7485
|
+
if (isVmTemplateLike(raw.template)) {
|
|
7486
|
+
cloned.template = cloneVmTemplate(raw.template);
|
|
7487
|
+
} else if (raw.template !== void 0) {
|
|
7488
|
+
cloned.template = cloneValue(raw.template);
|
|
7489
|
+
}
|
|
7490
|
+
return cloned;
|
|
7491
|
+
}
|
|
7492
|
+
function clonePlainObject(value) {
|
|
7493
|
+
if (!value || typeof value !== "object") {
|
|
7494
|
+
return value;
|
|
7495
|
+
}
|
|
7496
|
+
const cloned = {};
|
|
7497
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
7498
|
+
cloned[key] = cloneValue(entry);
|
|
7499
|
+
}
|
|
7500
|
+
return cloned;
|
|
7501
|
+
}
|
|
7502
|
+
function cloneValue(value) {
|
|
7503
|
+
if (value instanceof VmBaseImage) {
|
|
7504
|
+
return new VmBaseImage(value.toRaw());
|
|
7505
|
+
}
|
|
7506
|
+
if (isVmSpecLike(value)) {
|
|
7507
|
+
return cloneVmSpec(value);
|
|
7508
|
+
}
|
|
7509
|
+
if (isVmTemplateLike(value)) {
|
|
7510
|
+
return cloneVmTemplate(value);
|
|
7511
|
+
}
|
|
7512
|
+
if (Array.isArray(value)) {
|
|
7513
|
+
return value.map((entry) => cloneValue(entry));
|
|
7514
|
+
}
|
|
7515
|
+
if (value && typeof value === "object") {
|
|
7516
|
+
return clonePlainObject(value);
|
|
7517
|
+
}
|
|
7518
|
+
return value;
|
|
7519
|
+
}
|
|
7306
7520
|
|
|
7307
7521
|
class Freestyle {
|
|
7308
7522
|
/**
|