freestyle-sandboxes 0.1.38 → 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 +336 -114
- package/index.d.cts +35 -4
- package/index.d.mts +35 -4
- package/index.mjs +336 -114
- package/package.json +1 -1
package/index.cjs
CHANGED
|
@@ -6009,6 +6009,64 @@ function composeVmSpecs(specs) {
|
|
|
6009
6009
|
}
|
|
6010
6010
|
|
|
6011
6011
|
const DEFAULT_CONFIGURE_BASE_IMAGE = "FROM debian:trixie-slim";
|
|
6012
|
+
const RUN_COMMANDS_SYSTEMD_SERVICE_PREFIX = "freestyle-run-command";
|
|
6013
|
+
const WAIT_FOR_SYSTEMD_SERVICE_PREFIX = "freestyle-wait-for";
|
|
6014
|
+
function escapeRegExp(value) {
|
|
6015
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6016
|
+
}
|
|
6017
|
+
function getGeneratedServiceState(services, prefix) {
|
|
6018
|
+
const generatedPrefixes = [
|
|
6019
|
+
RUN_COMMANDS_SYSTEMD_SERVICE_PREFIX,
|
|
6020
|
+
WAIT_FOR_SYSTEMD_SERVICE_PREFIX
|
|
6021
|
+
];
|
|
6022
|
+
let maxIndex = 0;
|
|
6023
|
+
let lastGeneratedServiceName;
|
|
6024
|
+
for (const service of services) {
|
|
6025
|
+
if (!service.name) {
|
|
6026
|
+
continue;
|
|
6027
|
+
}
|
|
6028
|
+
for (const generatedPrefix of generatedPrefixes) {
|
|
6029
|
+
const match = service.name.match(
|
|
6030
|
+
new RegExp(`^${escapeRegExp(generatedPrefix)}-(\\d+)$`)
|
|
6031
|
+
);
|
|
6032
|
+
if (!match) {
|
|
6033
|
+
continue;
|
|
6034
|
+
}
|
|
6035
|
+
if (generatedPrefix === prefix) {
|
|
6036
|
+
const index = Number.parseInt(match[1] ?? "0", 10);
|
|
6037
|
+
if (index > maxIndex) {
|
|
6038
|
+
maxIndex = index;
|
|
6039
|
+
}
|
|
6040
|
+
}
|
|
6041
|
+
lastGeneratedServiceName = service.name;
|
|
6042
|
+
break;
|
|
6043
|
+
}
|
|
6044
|
+
}
|
|
6045
|
+
return { maxIndex, lastGeneratedServiceName };
|
|
6046
|
+
}
|
|
6047
|
+
function appendServiceDependency(dependencies, dependency) {
|
|
6048
|
+
if (!dependency) {
|
|
6049
|
+
return dependencies ?? void 0;
|
|
6050
|
+
}
|
|
6051
|
+
const values = [...dependencies ?? []];
|
|
6052
|
+
if (!values.includes(dependency)) {
|
|
6053
|
+
values.push(dependency);
|
|
6054
|
+
}
|
|
6055
|
+
return values;
|
|
6056
|
+
}
|
|
6057
|
+
function buildWaitForScript(command, intervalSeconds) {
|
|
6058
|
+
const body = command.trim().split("\n").map((line) => ` ${line}`).join("\n");
|
|
6059
|
+
return [
|
|
6060
|
+
"while true; do",
|
|
6061
|
+
" if (",
|
|
6062
|
+
body,
|
|
6063
|
+
" ); then",
|
|
6064
|
+
" exit 0",
|
|
6065
|
+
" fi",
|
|
6066
|
+
` sleep ${intervalSeconds}`,
|
|
6067
|
+
"done"
|
|
6068
|
+
].join("\n");
|
|
6069
|
+
}
|
|
6012
6070
|
function processSystemdServices(services, existingFiles = {}) {
|
|
6013
6071
|
const additionalFiles = { ...existingFiles };
|
|
6014
6072
|
const processedServices = [];
|
|
@@ -6043,6 +6101,63 @@ ${bash}`;
|
|
|
6043
6101
|
}
|
|
6044
6102
|
return { services: processedServices, additionalFiles };
|
|
6045
6103
|
}
|
|
6104
|
+
function normalizeSystemdServices(services) {
|
|
6105
|
+
return services.map((service) => ({
|
|
6106
|
+
...service,
|
|
6107
|
+
after: service.after?.map((s) => s.includes(".") ? s : `${s}.service`),
|
|
6108
|
+
requires: service.requires?.map(
|
|
6109
|
+
(s) => s.includes(".") ? s : `${s}.service`
|
|
6110
|
+
),
|
|
6111
|
+
wantedBy: service.wantedBy?.map(
|
|
6112
|
+
(s) => s.includes(".") ? s : `${s}.service`
|
|
6113
|
+
)
|
|
6114
|
+
}));
|
|
6115
|
+
}
|
|
6116
|
+
function normalizePatchedServices(services) {
|
|
6117
|
+
return services.map((service) => ({
|
|
6118
|
+
...service,
|
|
6119
|
+
after: service.after?.map((s) => s.includes(".") ? s : `${s}.service`),
|
|
6120
|
+
requires: service.requires?.map(
|
|
6121
|
+
(s) => s.includes(".") ? s : `${s}.service`
|
|
6122
|
+
),
|
|
6123
|
+
wantedBy: service.wantedBy?.map(
|
|
6124
|
+
(s) => s.includes(".") ? s : `${s}.service`
|
|
6125
|
+
)
|
|
6126
|
+
}));
|
|
6127
|
+
}
|
|
6128
|
+
function normalizeTemplateForRequest(template) {
|
|
6129
|
+
const normalizedTemplate = {
|
|
6130
|
+
...template ?? {}
|
|
6131
|
+
};
|
|
6132
|
+
if (normalizedTemplate.template) {
|
|
6133
|
+
normalizedTemplate.template = normalizeTemplateForRequest(
|
|
6134
|
+
normalizedTemplate.template
|
|
6135
|
+
);
|
|
6136
|
+
}
|
|
6137
|
+
if (normalizedTemplate.baseImage) {
|
|
6138
|
+
normalizedTemplate.baseImage = normalizeBaseImage(
|
|
6139
|
+
normalizedTemplate.baseImage
|
|
6140
|
+
)?.toRaw();
|
|
6141
|
+
}
|
|
6142
|
+
normalizedTemplate.git = normalizeGitOptions(normalizedTemplate.git);
|
|
6143
|
+
if (normalizedTemplate.systemd?.services) {
|
|
6144
|
+
const normalizedServices = normalizeSystemdServices(
|
|
6145
|
+
normalizedTemplate.systemd.services
|
|
6146
|
+
);
|
|
6147
|
+
const { services: processedServices, additionalFiles: bashFiles } = processSystemdServices(
|
|
6148
|
+
normalizedServices,
|
|
6149
|
+
normalizedTemplate.additionalFiles ?? {}
|
|
6150
|
+
);
|
|
6151
|
+
normalizedTemplate.systemd.services = processedServices;
|
|
6152
|
+
normalizedTemplate.additionalFiles = bashFiles;
|
|
6153
|
+
}
|
|
6154
|
+
if (normalizedTemplate.systemd?.patchedServices) {
|
|
6155
|
+
normalizedTemplate.systemd.patchedServices = normalizePatchedServices(
|
|
6156
|
+
normalizedTemplate.systemd.patchedServices
|
|
6157
|
+
);
|
|
6158
|
+
}
|
|
6159
|
+
return normalizedTemplate;
|
|
6160
|
+
}
|
|
6046
6161
|
function normalizeGitOptions(git) {
|
|
6047
6162
|
if (!git) return git;
|
|
6048
6163
|
return {
|
|
@@ -6238,10 +6353,12 @@ class Vm {
|
|
|
6238
6353
|
params: { vm_id: this.vmId },
|
|
6239
6354
|
body: options
|
|
6240
6355
|
});
|
|
6241
|
-
const vmId = response.id;
|
|
6242
6356
|
return {
|
|
6243
|
-
|
|
6244
|
-
|
|
6357
|
+
forks: response.forks.map((fork) => ({
|
|
6358
|
+
vmId: fork.id,
|
|
6359
|
+
vm: this._freestyle.vms.ref({ vmId: fork.id })
|
|
6360
|
+
// Create a new Vm instance for the forked VM
|
|
6361
|
+
}))
|
|
6245
6362
|
};
|
|
6246
6363
|
}
|
|
6247
6364
|
/**
|
|
@@ -6390,10 +6507,14 @@ class VmSpec {
|
|
|
6390
6507
|
return { ...this.withDiscriminators };
|
|
6391
6508
|
}
|
|
6392
6509
|
mergeRaw(options) {
|
|
6510
|
+
const existingSnapshot = this.raw.snapshot;
|
|
6393
6511
|
this.raw = composeCreateVmOptions([
|
|
6394
6512
|
this.raw,
|
|
6395
6513
|
options
|
|
6396
6514
|
]);
|
|
6515
|
+
if (existingSnapshot !== void 0 && this.raw.snapshot === void 0) {
|
|
6516
|
+
this.raw.snapshot = existingSnapshot;
|
|
6517
|
+
}
|
|
6397
6518
|
return this;
|
|
6398
6519
|
}
|
|
6399
6520
|
clearBuilders() {
|
|
@@ -6460,6 +6581,14 @@ class VmSpec {
|
|
|
6460
6581
|
const existing = this.raw.aptDeps ?? [];
|
|
6461
6582
|
return this.mergeRaw({ aptDeps: [...existing, ...deps] });
|
|
6462
6583
|
}
|
|
6584
|
+
users(users) {
|
|
6585
|
+
const existing = this.raw.users ?? [];
|
|
6586
|
+
return this.mergeRaw({ users: [...existing, ...users] });
|
|
6587
|
+
}
|
|
6588
|
+
groups(groups) {
|
|
6589
|
+
const existing = this.raw.groups ?? [];
|
|
6590
|
+
return this.mergeRaw({ groups: [...existing, ...groups] });
|
|
6591
|
+
}
|
|
6463
6592
|
additionalFiles(files) {
|
|
6464
6593
|
const existing = this.raw.additionalFiles ?? {};
|
|
6465
6594
|
this.raw.additionalFiles = {
|
|
@@ -6469,9 +6598,74 @@ class VmSpec {
|
|
|
6469
6598
|
return this;
|
|
6470
6599
|
}
|
|
6471
6600
|
runCommands(...commands) {
|
|
6472
|
-
const
|
|
6473
|
-
|
|
6474
|
-
|
|
6601
|
+
const normalizedCommands = commands.map((command) => command.trim()).filter((command) => command.length > 0);
|
|
6602
|
+
if (normalizedCommands.length === 0) {
|
|
6603
|
+
return this;
|
|
6604
|
+
}
|
|
6605
|
+
const existingSystemd = this.raw.systemd ?? {};
|
|
6606
|
+
const existingServices = [...existingSystemd.services ?? []];
|
|
6607
|
+
let { maxIndex: maxRunCommandIndex, lastGeneratedServiceName } = getGeneratedServiceState(
|
|
6608
|
+
existingServices,
|
|
6609
|
+
RUN_COMMANDS_SYSTEMD_SERVICE_PREFIX
|
|
6610
|
+
);
|
|
6611
|
+
for (const command of normalizedCommands) {
|
|
6612
|
+
const nextIndex = ++maxRunCommandIndex;
|
|
6613
|
+
const serviceName = `${RUN_COMMANDS_SYSTEMD_SERVICE_PREFIX}-${nextIndex}`;
|
|
6614
|
+
existingServices.push({
|
|
6615
|
+
name: serviceName,
|
|
6616
|
+
mode: "oneshot",
|
|
6617
|
+
deleteAfterSuccess: true,
|
|
6618
|
+
bash: command,
|
|
6619
|
+
...lastGeneratedServiceName ? {
|
|
6620
|
+
after: [lastGeneratedServiceName],
|
|
6621
|
+
requires: [lastGeneratedServiceName]
|
|
6622
|
+
} : {}
|
|
6623
|
+
});
|
|
6624
|
+
lastGeneratedServiceName = serviceName;
|
|
6625
|
+
}
|
|
6626
|
+
this.raw.systemd = {
|
|
6627
|
+
...existingSystemd,
|
|
6628
|
+
services: existingServices
|
|
6629
|
+
};
|
|
6630
|
+
return this;
|
|
6631
|
+
}
|
|
6632
|
+
waitFor(command, config = {}) {
|
|
6633
|
+
const trimmedCommand = command.trim();
|
|
6634
|
+
if (!trimmedCommand) {
|
|
6635
|
+
throw new Error("VmSpec.waitFor requires a non-empty command");
|
|
6636
|
+
}
|
|
6637
|
+
const intervalSeconds = config.intervalSeconds ?? 2;
|
|
6638
|
+
if (!Number.isFinite(intervalSeconds) || intervalSeconds <= 0) {
|
|
6639
|
+
throw new Error("VmSpec.waitFor intervalSeconds must be greater than 0");
|
|
6640
|
+
}
|
|
6641
|
+
const existingSystemd = this.raw.systemd ?? {};
|
|
6642
|
+
const existingServices = [...existingSystemd.services ?? []];
|
|
6643
|
+
const { maxIndex, lastGeneratedServiceName } = getGeneratedServiceState(
|
|
6644
|
+
existingServices,
|
|
6645
|
+
WAIT_FOR_SYSTEMD_SERVICE_PREFIX
|
|
6646
|
+
);
|
|
6647
|
+
const {
|
|
6648
|
+
intervalSeconds: _intervalSeconds,
|
|
6649
|
+
name,
|
|
6650
|
+
after,
|
|
6651
|
+
requires,
|
|
6652
|
+
timeoutSec,
|
|
6653
|
+
...rest
|
|
6654
|
+
} = config;
|
|
6655
|
+
existingServices.push({
|
|
6656
|
+
...rest,
|
|
6657
|
+
name: name ?? `${WAIT_FOR_SYSTEMD_SERVICE_PREFIX}-${maxIndex + 1}`,
|
|
6658
|
+
mode: "oneshot",
|
|
6659
|
+
// deleteAfterSuccess: true,
|
|
6660
|
+
timeoutSec: timeoutSec ?? 0,
|
|
6661
|
+
after: appendServiceDependency(after, lastGeneratedServiceName),
|
|
6662
|
+
requires: appendServiceDependency(requires, lastGeneratedServiceName),
|
|
6663
|
+
bash: buildWaitForScript(trimmedCommand, intervalSeconds)
|
|
6664
|
+
});
|
|
6665
|
+
this.raw.systemd = {
|
|
6666
|
+
...existingSystemd,
|
|
6667
|
+
services: existingServices
|
|
6668
|
+
};
|
|
6475
6669
|
return this;
|
|
6476
6670
|
}
|
|
6477
6671
|
repo(repo, path) {
|
|
@@ -6498,7 +6692,7 @@ class VmSpec {
|
|
|
6498
6692
|
function isVmSpecLike$1(value) {
|
|
6499
6693
|
return !!value && typeof value === "object" && "raw" in value && "with" in value;
|
|
6500
6694
|
}
|
|
6501
|
-
function isVmTemplateLike(value) {
|
|
6695
|
+
function isVmTemplateLike$1(value) {
|
|
6502
6696
|
return !!value && typeof value === "object" && "raw" in value && "with" in value;
|
|
6503
6697
|
}
|
|
6504
6698
|
async function convertSpecSnapshotsToTemplates(spec, processBuilders = true) {
|
|
@@ -6624,21 +6818,8 @@ class VmsNamespace {
|
|
|
6624
6818
|
}
|
|
6625
6819
|
}
|
|
6626
6820
|
if (options.systemd?.services) {
|
|
6627
|
-
const normalizedServices =
|
|
6628
|
-
|
|
6629
|
-
return {
|
|
6630
|
-
...service,
|
|
6631
|
-
after: service.after?.map(
|
|
6632
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6633
|
-
),
|
|
6634
|
-
requires: service.requires?.map(
|
|
6635
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6636
|
-
),
|
|
6637
|
-
wantedBy: service.wantedBy?.map(
|
|
6638
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6639
|
-
)
|
|
6640
|
-
};
|
|
6641
|
-
}
|
|
6821
|
+
const normalizedServices = normalizeSystemdServices(
|
|
6822
|
+
options.systemd.services
|
|
6642
6823
|
);
|
|
6643
6824
|
const { services: processedServices, additionalFiles: bashFiles } = processSystemdServices(
|
|
6644
6825
|
normalizedServices,
|
|
@@ -6648,19 +6829,8 @@ class VmsNamespace {
|
|
|
6648
6829
|
options.additionalFiles = bashFiles;
|
|
6649
6830
|
}
|
|
6650
6831
|
if (options.systemd?.patchedServices) {
|
|
6651
|
-
options.systemd.patchedServices =
|
|
6652
|
-
|
|
6653
|
-
service.after = service.after?.map(
|
|
6654
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6655
|
-
);
|
|
6656
|
-
service.requires = service.requires?.map(
|
|
6657
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6658
|
-
);
|
|
6659
|
-
service.wantedBy = service.wantedBy?.map(
|
|
6660
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6661
|
-
);
|
|
6662
|
-
return service;
|
|
6663
|
-
}
|
|
6832
|
+
options.systemd.patchedServices = normalizePatchedServices(
|
|
6833
|
+
options.systemd.patchedServices
|
|
6664
6834
|
);
|
|
6665
6835
|
}
|
|
6666
6836
|
if ("snapshot" in options) {
|
|
@@ -6693,7 +6863,7 @@ class VmsNamespace {
|
|
|
6693
6863
|
const specBuilders = isVmSpecLike$1(
|
|
6694
6864
|
options.spec
|
|
6695
6865
|
) ? collectSpecBuilders(options.spec) : void 0;
|
|
6696
|
-
const templateBuilders = isVmTemplateLike(options.template) ? options.template.with : void 0;
|
|
6866
|
+
const templateBuilders = isVmTemplateLike$1(options.template) ? options.template.with : void 0;
|
|
6697
6867
|
const builders = {
|
|
6698
6868
|
...templateBuilders || {},
|
|
6699
6869
|
...specBuilders || {},
|
|
@@ -6701,10 +6871,10 @@ class VmsNamespace {
|
|
|
6701
6871
|
};
|
|
6702
6872
|
const { with: _, spec: _spec, ...baseConfig } = options;
|
|
6703
6873
|
let config = baseConfig;
|
|
6704
|
-
if (isVmTemplateLike(config.template)) {
|
|
6874
|
+
if (isVmTemplateLike$1(config.template)) {
|
|
6705
6875
|
config.template = await processTemplateTree(config.template);
|
|
6706
6876
|
}
|
|
6707
|
-
if (isVmTemplateLike(config.template)) {
|
|
6877
|
+
if (isVmTemplateLike$1(config.template)) {
|
|
6708
6878
|
config.template = await ensureNestedTemplates(
|
|
6709
6879
|
config.template,
|
|
6710
6880
|
this.snapshots
|
|
@@ -6718,18 +6888,9 @@ class VmsNamespace {
|
|
|
6718
6888
|
}
|
|
6719
6889
|
}
|
|
6720
6890
|
if (config.systemd?.services) {
|
|
6721
|
-
const normalizedServices =
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6725
|
-
),
|
|
6726
|
-
requires: service.requires?.map(
|
|
6727
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6728
|
-
),
|
|
6729
|
-
wantedBy: service.wantedBy?.map(
|
|
6730
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6731
|
-
)
|
|
6732
|
-
}));
|
|
6891
|
+
const normalizedServices = normalizeSystemdServices(
|
|
6892
|
+
config.systemd.services
|
|
6893
|
+
);
|
|
6733
6894
|
const { services: processedServices, additionalFiles: bashFiles } = processSystemdServices(
|
|
6734
6895
|
normalizedServices,
|
|
6735
6896
|
config.additionalFiles ?? {}
|
|
@@ -6738,28 +6899,20 @@ class VmsNamespace {
|
|
|
6738
6899
|
config.additionalFiles = bashFiles;
|
|
6739
6900
|
}
|
|
6740
6901
|
if (config.systemd?.patchedServices) {
|
|
6741
|
-
config.systemd.patchedServices =
|
|
6742
|
-
|
|
6743
|
-
service.after = service.after?.map(
|
|
6744
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6745
|
-
);
|
|
6746
|
-
service.requires = service.requires?.map(
|
|
6747
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6748
|
-
);
|
|
6749
|
-
service.wantedBy = service.wantedBy?.map(
|
|
6750
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6751
|
-
);
|
|
6752
|
-
return service;
|
|
6753
|
-
}
|
|
6902
|
+
config.systemd.patchedServices = normalizePatchedServices(
|
|
6903
|
+
config.systemd.patchedServices
|
|
6754
6904
|
);
|
|
6755
6905
|
}
|
|
6756
6906
|
config.git = normalizeGitOptions(config.git);
|
|
6757
6907
|
const serializedBaseImage = normalizeBaseImage(config.baseImage)?.toRaw();
|
|
6758
|
-
const rawTemplate = isVmTemplateLike(config.template) ? config.template.raw : config.template;
|
|
6908
|
+
const rawTemplate = isVmTemplateLike$1(config.template) ? config.template.raw : config.template;
|
|
6759
6909
|
const requestTemplate = serializedBaseImage ? {
|
|
6760
6910
|
...rawTemplate ?? {},
|
|
6761
6911
|
baseImage: serializedBaseImage
|
|
6762
6912
|
} : rawTemplate;
|
|
6913
|
+
const normalizedRequestTemplate = requestTemplate ? normalizeTemplateForRequest(
|
|
6914
|
+
requestTemplate
|
|
6915
|
+
) : requestTemplate;
|
|
6763
6916
|
const {
|
|
6764
6917
|
baseImage: _baseImage,
|
|
6765
6918
|
template: _template,
|
|
@@ -6768,7 +6921,7 @@ class VmsNamespace {
|
|
|
6768
6921
|
const response = await this.freestyle._apiClient.post("/v1/vms", {
|
|
6769
6922
|
body: {
|
|
6770
6923
|
...requestConfig,
|
|
6771
|
-
template:
|
|
6924
|
+
template: normalizedRequestTemplate,
|
|
6772
6925
|
// Cast systemd since we've processed SystemdServiceInput[] to RawSystemdService[]
|
|
6773
6926
|
systemd: config.systemd,
|
|
6774
6927
|
// Normalize git options - default config to {}
|
|
@@ -6863,6 +7016,35 @@ function enhanceError(e) {
|
|
|
6863
7016
|
if (!e.message.includes("create --snapshot")) {
|
|
6864
7017
|
e.message = `${e.message}. Hint: use \`npx freestyle-sandboxes@latest vm create --snapshot ${e.body.snapshotId} --ssh --delete\` to debug.`;
|
|
6865
7018
|
}
|
|
7019
|
+
if (e.body.diagnostics) {
|
|
7020
|
+
const d = e.body.diagnostics;
|
|
7021
|
+
const parts = [];
|
|
7022
|
+
if (d.serviceStates.length > 0) {
|
|
7023
|
+
parts.push("Service states:");
|
|
7024
|
+
for (const g of d.serviceStates) {
|
|
7025
|
+
parts.push(
|
|
7026
|
+
` ${g.activeState}(${g.subState}): ${g.services.join(", ")}`
|
|
7027
|
+
);
|
|
7028
|
+
}
|
|
7029
|
+
}
|
|
7030
|
+
const allLogs = [
|
|
7031
|
+
...d.failedServiceLogs ?? [],
|
|
7032
|
+
...d.additionalFailedServiceLogs ?? []
|
|
7033
|
+
];
|
|
7034
|
+
if (allLogs.length > 0) {
|
|
7035
|
+
parts.push("Failed service logs:");
|
|
7036
|
+
for (const l of allLogs) {
|
|
7037
|
+
parts.push(` --- ${l.unitName} ---`);
|
|
7038
|
+
parts.push(` ${l.log}`);
|
|
7039
|
+
}
|
|
7040
|
+
}
|
|
7041
|
+
if (parts.length > 0) {
|
|
7042
|
+
e.message = `${e.message}
|
|
7043
|
+
|
|
7044
|
+
Diagnostics:
|
|
7045
|
+
${parts.join("\n")}`;
|
|
7046
|
+
}
|
|
7047
|
+
}
|
|
6866
7048
|
}
|
|
6867
7049
|
return e;
|
|
6868
7050
|
}
|
|
@@ -6930,12 +7112,12 @@ class VmSnapshotsNamespace {
|
|
|
6930
7112
|
const { spec: _spec, ...rest } = requestOptions;
|
|
6931
7113
|
requestOptions = rest;
|
|
6932
7114
|
}
|
|
6933
|
-
if (isVmTemplateLike(requestOptions.template)) {
|
|
7115
|
+
if (isVmTemplateLike$1(requestOptions.template)) {
|
|
6934
7116
|
const processedTemplate = await processTemplateTree(
|
|
6935
7117
|
requestOptions.template
|
|
6936
7118
|
);
|
|
6937
7119
|
requestOptions.template = processedTemplate;
|
|
6938
|
-
if (isVmTemplateLike(processedTemplate.raw.template)) {
|
|
7120
|
+
if (isVmTemplateLike$1(processedTemplate.raw.template)) {
|
|
6939
7121
|
requestOptions.template = await ensureNestedTemplates(
|
|
6940
7122
|
processedTemplate,
|
|
6941
7123
|
this
|
|
@@ -6950,7 +7132,9 @@ class VmSnapshotsNamespace {
|
|
|
6950
7132
|
return this.apiClient.post("/v1/vms/snapshots", {
|
|
6951
7133
|
body: {
|
|
6952
7134
|
...requestOptions,
|
|
6953
|
-
template:
|
|
7135
|
+
template: normalizeTemplateForRequest(
|
|
7136
|
+
isVmTemplateLike$1(requestOptions.template) ? requestOptions.template.raw : requestOptions.template
|
|
7137
|
+
)
|
|
6954
7138
|
}
|
|
6955
7139
|
}).catch((e) => {
|
|
6956
7140
|
enhanceError(e);
|
|
@@ -6970,22 +7154,9 @@ async function processTemplateTree(template) {
|
|
|
6970
7154
|
);
|
|
6971
7155
|
}
|
|
6972
7156
|
if (template.raw.systemd?.services) {
|
|
6973
|
-
|
|
6974
|
-
|
|
6975
|
-
after: service.after?.map((s) => s.includes(".") ? s : `${s}.service`),
|
|
6976
|
-
requires: service.requires?.map(
|
|
6977
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6978
|
-
),
|
|
6979
|
-
wantedBy: service.wantedBy?.map(
|
|
6980
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
6981
|
-
)
|
|
6982
|
-
}));
|
|
6983
|
-
const { services: processedServices, additionalFiles: bashFiles } = processSystemdServices(
|
|
6984
|
-
normalizedServices,
|
|
6985
|
-
template.raw.additionalFiles ?? {}
|
|
7157
|
+
template.raw.systemd.services = normalizeSystemdServices(
|
|
7158
|
+
template.raw.systemd.services
|
|
6986
7159
|
);
|
|
6987
|
-
template.raw.systemd.services = processedServices;
|
|
6988
|
-
template.raw.additionalFiles = bashFiles;
|
|
6989
7160
|
}
|
|
6990
7161
|
for (const key in template.with) {
|
|
6991
7162
|
const builder = template.with[key];
|
|
@@ -7002,7 +7173,7 @@ async function processTemplateTree(template) {
|
|
|
7002
7173
|
}
|
|
7003
7174
|
if (builder.configureNestedTemplate) {
|
|
7004
7175
|
let nestedTemplate;
|
|
7005
|
-
if (isVmTemplateLike(template.raw.template)) {
|
|
7176
|
+
if (isVmTemplateLike$1(template.raw.template)) {
|
|
7006
7177
|
nestedTemplate = template.raw.template;
|
|
7007
7178
|
} else {
|
|
7008
7179
|
nestedTemplate = new VmTemplate({});
|
|
@@ -7025,38 +7196,16 @@ async function processTemplateTree(template) {
|
|
|
7025
7196
|
);
|
|
7026
7197
|
}
|
|
7027
7198
|
if (template.raw.systemd?.services) {
|
|
7028
|
-
|
|
7029
|
-
|
|
7030
|
-
after: service.after?.map((s) => s.includes(".") ? s : `${s}.service`),
|
|
7031
|
-
requires: service.requires?.map(
|
|
7032
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
7033
|
-
),
|
|
7034
|
-
wantedBy: service.wantedBy?.map(
|
|
7035
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
7036
|
-
)
|
|
7037
|
-
}));
|
|
7038
|
-
const { services: processedServices, additionalFiles: bashFiles } = processSystemdServices(
|
|
7039
|
-
normalizedServices,
|
|
7040
|
-
template.raw.additionalFiles ?? {}
|
|
7199
|
+
template.raw.systemd.services = normalizeSystemdServices(
|
|
7200
|
+
template.raw.systemd.services
|
|
7041
7201
|
);
|
|
7042
|
-
template.raw.systemd.services = processedServices;
|
|
7043
|
-
template.raw.additionalFiles = bashFiles;
|
|
7044
7202
|
}
|
|
7045
7203
|
if (template.raw.systemd?.patchedServices) {
|
|
7046
|
-
template.raw.systemd.patchedServices =
|
|
7047
|
-
|
|
7048
|
-
|
|
7049
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
7050
|
-
),
|
|
7051
|
-
requires: service.requires?.map(
|
|
7052
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
7053
|
-
),
|
|
7054
|
-
wantedBy: service.wantedBy?.map(
|
|
7055
|
-
(s) => s.includes(".") ? s : `${s}.service`
|
|
7056
|
-
)
|
|
7057
|
-
}));
|
|
7204
|
+
template.raw.systemd.patchedServices = normalizePatchedServices(
|
|
7205
|
+
template.raw.systemd.patchedServices
|
|
7206
|
+
);
|
|
7058
7207
|
}
|
|
7059
|
-
if (isVmTemplateLike(template.raw.template)) {
|
|
7208
|
+
if (isVmTemplateLike$1(template.raw.template)) {
|
|
7060
7209
|
template.raw.template = await processTemplateTree(
|
|
7061
7210
|
template.raw.template
|
|
7062
7211
|
);
|
|
@@ -7065,7 +7214,7 @@ async function processTemplateTree(template) {
|
|
|
7065
7214
|
}
|
|
7066
7215
|
async function ensureNestedTemplates(template, snapshots) {
|
|
7067
7216
|
const templates = [template];
|
|
7068
|
-
while (isVmTemplateLike(templates.at(-1)?.raw.template)) {
|
|
7217
|
+
while (isVmTemplateLike$1(templates.at(-1)?.raw.template)) {
|
|
7069
7218
|
const innerTemplate = templates.at(-1).raw.template;
|
|
7070
7219
|
templates.at(-1).raw.template = void 0;
|
|
7071
7220
|
templates.push(innerTemplate);
|
|
@@ -7250,7 +7399,7 @@ async function readFiles(directory) {
|
|
|
7250
7399
|
}
|
|
7251
7400
|
|
|
7252
7401
|
async function debugCreateRequests(freestyle, optionsOrSpec = {}) {
|
|
7253
|
-
const options = isVmSpecLike(optionsOrSpec) ? { spec: optionsOrSpec } : optionsOrSpec;
|
|
7402
|
+
const options = isVmSpecLike(optionsOrSpec) ? { spec: cloneVmSpec(optionsOrSpec) } : cloneCreateOptions(optionsOrSpec);
|
|
7254
7403
|
const requests = [];
|
|
7255
7404
|
let snapshotCounter = 0;
|
|
7256
7405
|
let vmCounter = 0;
|
|
@@ -7297,6 +7446,79 @@ async function debugCreateRequests(freestyle, optionsOrSpec = {}) {
|
|
|
7297
7446
|
function isVmSpecLike(value) {
|
|
7298
7447
|
return !!value && typeof value === "object" && "raw" in value && "with" in value;
|
|
7299
7448
|
}
|
|
7449
|
+
function isVmTemplateLike(value) {
|
|
7450
|
+
return !!value && typeof value === "object" && "raw" in value && "with" in value;
|
|
7451
|
+
}
|
|
7452
|
+
function cloneCreateOptions(options) {
|
|
7453
|
+
return {
|
|
7454
|
+
...clonePlainObject(options),
|
|
7455
|
+
with: options.with,
|
|
7456
|
+
template: isVmTemplateLike(options.template) ? cloneVmTemplate(options.template) : cloneValue(options.template),
|
|
7457
|
+
spec: isVmSpecLike(options.spec) ? cloneVmSpec(options.spec) : void 0,
|
|
7458
|
+
snapshot: isVmSpecLike(options.snapshot) ? cloneVmSpec(options.snapshot) : void 0
|
|
7459
|
+
};
|
|
7460
|
+
}
|
|
7461
|
+
function cloneVmSpec(spec) {
|
|
7462
|
+
const clonedRaw = cloneVmSpecRaw(spec.raw);
|
|
7463
|
+
return new VmSpec({
|
|
7464
|
+
...clonedRaw,
|
|
7465
|
+
with: { ...spec.builders },
|
|
7466
|
+
__withDiscriminators: typeof spec.getBuilderDiscriminators === "function" ? spec.getBuilderDiscriminators() : void 0
|
|
7467
|
+
});
|
|
7468
|
+
}
|
|
7469
|
+
function cloneVmTemplate(template) {
|
|
7470
|
+
const clonedRaw = cloneVmTemplateRaw(template.raw);
|
|
7471
|
+
return new VmTemplate({
|
|
7472
|
+
...clonedRaw,
|
|
7473
|
+
with: { ...template.with }
|
|
7474
|
+
});
|
|
7475
|
+
}
|
|
7476
|
+
function cloneVmSpecRaw(raw) {
|
|
7477
|
+
const cloned = cloneVmTemplateRaw(raw);
|
|
7478
|
+
if (isVmSpecLike(raw.snapshot)) {
|
|
7479
|
+
cloned.snapshot = cloneVmSpec(raw.snapshot);
|
|
7480
|
+
} else if (raw.snapshot !== void 0) {
|
|
7481
|
+
cloned.snapshot = cloneValue(raw.snapshot);
|
|
7482
|
+
}
|
|
7483
|
+
return cloned;
|
|
7484
|
+
}
|
|
7485
|
+
function cloneVmTemplateRaw(raw) {
|
|
7486
|
+
const cloned = clonePlainObject(raw);
|
|
7487
|
+
if (isVmTemplateLike(raw.template)) {
|
|
7488
|
+
cloned.template = cloneVmTemplate(raw.template);
|
|
7489
|
+
} else if (raw.template !== void 0) {
|
|
7490
|
+
cloned.template = cloneValue(raw.template);
|
|
7491
|
+
}
|
|
7492
|
+
return cloned;
|
|
7493
|
+
}
|
|
7494
|
+
function clonePlainObject(value) {
|
|
7495
|
+
if (!value || typeof value !== "object") {
|
|
7496
|
+
return value;
|
|
7497
|
+
}
|
|
7498
|
+
const cloned = {};
|
|
7499
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
7500
|
+
cloned[key] = cloneValue(entry);
|
|
7501
|
+
}
|
|
7502
|
+
return cloned;
|
|
7503
|
+
}
|
|
7504
|
+
function cloneValue(value) {
|
|
7505
|
+
if (value instanceof VmBaseImage) {
|
|
7506
|
+
return new VmBaseImage(value.toRaw());
|
|
7507
|
+
}
|
|
7508
|
+
if (isVmSpecLike(value)) {
|
|
7509
|
+
return cloneVmSpec(value);
|
|
7510
|
+
}
|
|
7511
|
+
if (isVmTemplateLike(value)) {
|
|
7512
|
+
return cloneVmTemplate(value);
|
|
7513
|
+
}
|
|
7514
|
+
if (Array.isArray(value)) {
|
|
7515
|
+
return value.map((entry) => cloneValue(entry));
|
|
7516
|
+
}
|
|
7517
|
+
if (value && typeof value === "object") {
|
|
7518
|
+
return clonePlainObject(value);
|
|
7519
|
+
}
|
|
7520
|
+
return value;
|
|
7521
|
+
}
|
|
7300
7522
|
|
|
7301
7523
|
class Freestyle {
|
|
7302
7524
|
/**
|