underpost 3.2.80 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ghpkg.ci.yml +7 -1
- package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -16
- package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
- package/.github/workflows/release.cd.yml +1 -9
- package/CHANGELOG.md +291 -1
- package/CLI-HELP.md +174 -23
- package/README.md +5 -2
- package/bin/build.js +7 -5
- package/bin/deploy.js +19 -17
- package/deploy/lib/logging.sh +96 -0
- package/deploy/pwa-microservices-template/deploy.sh +72 -0
- package/deploy/release/deploy.sh +62 -0
- package/docker-compose.yml +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +5 -1
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +52 -0
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/playwright/deployment.yaml +1 -1
- package/manifests/mongodb/kustomization.yaml +4 -1
- package/manifests/mongodb/statefulset.yaml +4 -0
- package/manifests/mongodb/storage-class.yaml +9 -2
- package/package.json +19 -19
- package/scripts/audit-selinux.sh +64 -0
- package/scripts/coverall-test.sh +24 -0
- package/scripts/gpu-diag.sh +0 -0
- package/scripts/ip-info.sh +0 -0
- package/scripts/k3s-node-setup.sh +18 -15
- package/scripts/kubeadm-node-setup.sh +12 -23
- package/scripts/link-local-underpost-cli.sh +0 -0
- package/scripts/lxd-vm-setup.sh +0 -0
- package/scripts/maas-nat-firewalld.sh +0 -0
- package/scripts/nat-iptables.sh +12 -4
- package/scripts/rhel-grpc-setup.sh +0 -0
- package/scripts/rocky-kickstart.sh +25 -9
- package/scripts/test-monitor.sh +4 -3
- package/src/cli/baremetal.js +1 -2
- package/src/cli/cloud-init.js +1 -1
- package/src/cli/cluster.js +786 -96
- package/src/cli/db.js +11 -4
- package/src/cli/deploy.js +1698 -177
- package/src/cli/docker-compose.js +19 -178
- package/src/cli/env.js +1 -1
- package/src/cli/image.js +15 -7
- package/src/cli/index.js +245 -44
- package/src/cli/ipfs.js +82 -11
- package/src/cli/lxd.js +1 -1
- package/src/cli/monitor.js +2 -2
- package/src/cli/release.js +57 -22
- package/src/cli/repository.js +12 -10
- package/src/cli/run.js +2195 -427
- package/src/cli/secrets.js +969 -0
- package/src/cli/ssh.js +206 -105
- package/src/cli/system.js +26 -13
- package/src/cli/test.js +1 -1
- package/src/cli/vultr.js +583 -0
- package/src/cli/wireguard.js +2125 -0
- package/src/client-builder/client-build.js +102 -13
- package/src/client-builder/ssr.js +27 -73
- package/src/db/mongo/MongoBootstrap.js +295 -54
- package/src/db/mongo/MongooseDB.js +51 -32
- package/src/index.js +25 -1
- package/src/projects/underpost/catalog-underpost.js +4 -1
- package/src/server/backup.js +1 -1
- package/src/server/conf.js +1216 -168
- package/src/server/cri.js +70 -0
- package/src/server/cron.js +249 -51
- package/src/server/dns.js +100 -6
- package/src/server/environment.js +98 -0
- package/src/server/forward-proxy.js +549 -0
- package/src/server/middlewares.js +56 -1
- package/src/server/process.js +0 -1
- package/src/server/selinux.js +185 -0
- package/src/server/systemd.js +205 -0
- package/src/server/underpost-compression.js +186 -0
- package/src/server/underpost-gateway.js +1083 -0
- package/src/server/underpost-ingress.js +380 -0
- package/test/cluster-instances.test.js +435 -0
- package/test/deploy-node-placement.test.js +45 -0
- package/test/instance-traffic-plan.test.js +710 -0
- package/test/selinux.test.js +71 -0
- package/test/sops-secret-store.test.js +612 -0
- package/test/underpost-gateway.test.js +510 -0
- package/test/underpost-ingress.test.js +305 -0
- package/test/wireguard-edge.test.js +1177 -0
|
@@ -12,7 +12,6 @@ import fs from 'fs-extra';
|
|
|
12
12
|
import nodePath from 'path';
|
|
13
13
|
import { getRootDirectory, shellExec } from '../server/process.js';
|
|
14
14
|
import { loggerFactory } from '../server/logger.js';
|
|
15
|
-
import { loadInstanceTopology } from '../server/conf.js';
|
|
16
15
|
import Nginx from '../runtime/nginx/Nginx.js';
|
|
17
16
|
|
|
18
17
|
const logger = loggerFactory(import.meta);
|
|
@@ -82,9 +81,10 @@ class UnderpostDockerCompose {
|
|
|
82
81
|
* Resolves the canonical directory for a custom docker-compose workflow,
|
|
83
82
|
* keyed by `--deploy-id` + `--docker-compose-id`:
|
|
84
83
|
* `engine-private/conf/<deploy-id>/docker-compose/<docker-compose-id>`.
|
|
85
|
-
* This directory ships its own `docker-compose.yml`, `compose.env`, and
|
|
86
|
-
*
|
|
87
|
-
* `--docker-compose-id` is not set (the default,
|
|
84
|
+
* This directory ships its own `docker-compose.yml`, `compose.env`, and any
|
|
85
|
+
* project-specific bind-mounted files (all used as-is, never generated).
|
|
86
|
+
* Returns null when `--docker-compose-id` is not set (the default,
|
|
87
|
+
* self-generating workflow).
|
|
88
88
|
* @param {object} options - CLI options.
|
|
89
89
|
* @returns {string|null} Repo-root-relative canonical dir, or null.
|
|
90
90
|
* @memberof UnderpostDockerCompose
|
|
@@ -100,8 +100,8 @@ class UnderpostDockerCompose {
|
|
|
100
100
|
* so behavior is independent of the caller's working directory.
|
|
101
101
|
*
|
|
102
102
|
* Custom workflow (`--docker-compose-id`): the compose file, env-file, and
|
|
103
|
-
* bind-mounted config
|
|
104
|
-
*
|
|
103
|
+
* project-owned bind-mounted config all live in the canonical dir, so compose
|
|
104
|
+
* runs with `--project-directory` pinned there and no app-override.
|
|
105
105
|
* @param {object} options - CLI options.
|
|
106
106
|
* @returns {string} The base command string (without a subcommand).
|
|
107
107
|
* @memberof UnderpostDockerCompose
|
|
@@ -192,7 +192,7 @@ services:
|
|
|
192
192
|
MONGO_IMAGE=mongo:latest
|
|
193
193
|
VALKEY_IMAGE=valkey/valkey:latest
|
|
194
194
|
APP_IMAGE=underpost/underpost-engine
|
|
195
|
-
APP_TAG=v3.
|
|
195
|
+
APP_TAG=v3.3.0
|
|
196
196
|
PROXY_IMAGE=nginx:stable-alpine
|
|
197
197
|
PROMETHEUS_IMAGE=prom/prometheus:latest
|
|
198
198
|
GRAFANA_IMAGE=grafana/grafana:latest
|
|
@@ -362,150 +362,6 @@ datasources:
|
|
|
362
362
|
`;
|
|
363
363
|
}
|
|
364
364
|
|
|
365
|
-
/**
|
|
366
|
-
* Expands the deploy's `multiInstance` topology (from conf.instances.json, via
|
|
367
|
-
* {@link loadInstanceTopology}) into the per-variant descriptors the compose
|
|
368
|
-
* generators consume. Application-agnostic: it only reads variant code/slug/
|
|
369
|
-
* path and the default code. Returns null when the deploy is single-instance.
|
|
370
|
-
* @param {object} options - CLI options.
|
|
371
|
-
* @returns {?{defaultCode: string, variants: Array<object>}}
|
|
372
|
-
* @memberof UnderpostDockerCompose
|
|
373
|
-
*/
|
|
374
|
-
static instanceTopology(options = {}) {
|
|
375
|
-
const deployId = options.deployId || DEFAULT_DEPLOY_ID;
|
|
376
|
-
let topology = null;
|
|
377
|
-
try {
|
|
378
|
-
topology = loadInstanceTopology(deployId);
|
|
379
|
-
} catch {
|
|
380
|
-
return null;
|
|
381
|
-
}
|
|
382
|
-
if (!topology || !Array.isArray(topology.variants) || topology.variants.length === 0) return null;
|
|
383
|
-
const defaultCode = topology.default || topology.variants[0].code;
|
|
384
|
-
const variants = topology.variants.map((v) => {
|
|
385
|
-
const path = v.path || '/';
|
|
386
|
-
const isDefault = !(v.slug || '');
|
|
387
|
-
return {
|
|
388
|
-
code: v.code,
|
|
389
|
-
slug: v.slug || '',
|
|
390
|
-
path,
|
|
391
|
-
isDefault,
|
|
392
|
-
// Service/container suffix: empty for the default variant so it keeps
|
|
393
|
-
// the historic `cyberia-server` / `cyberia-client` names (and their
|
|
394
|
-
// published host ports); `-forest`, `-test`, … for the rest.
|
|
395
|
-
suffix: v.slug ? `-${v.slug}` : '',
|
|
396
|
-
// Backend prefix strip, mirroring the K8s pathRewritePolicy: the Go
|
|
397
|
-
// server serves `/ws` at its root, so a `/FOREST` prefix is stripped.
|
|
398
|
-
strip: path !== '/',
|
|
399
|
-
};
|
|
400
|
-
});
|
|
401
|
-
return { defaultCode, variants };
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
/**
|
|
405
|
-
* Renders the nginx reverse-proxy config for the multi-instance Cyberia stack
|
|
406
|
-
* as a SINGLE localhost gateway (dev compose is single-host; production uses
|
|
407
|
-
* the K8s HTTPProxy, not this file). All three tiers share one origin, routed
|
|
408
|
-
* by URL sub-path so `http://localhost/` works with no /etc/hosts:
|
|
409
|
-
* /api/*, /assets/* -> engine-cyberia (shared content authority)
|
|
410
|
-
* /<slug>/ws -> cyberia-server-<slug> (prefix stripped; the Go
|
|
411
|
-
* runtime is instance-agnostic, selected by
|
|
412
|
-
* INSTANCE_CODE), and /ws -> the default server
|
|
413
|
-
* /<slug>, / -> cyberia-client-<slug> (prefix kept; the WASM
|
|
414
|
-
* reads the instance from the URL)
|
|
415
|
-
* Upstreams resolve lazily through Docker's embedded DNS so a variant that is
|
|
416
|
-
* briefly down never fails nginx startup. Returns null for single-instance.
|
|
417
|
-
* @param {object} options - CLI options.
|
|
418
|
-
* @returns {?string} nginx.conf content, or null.
|
|
419
|
-
* @memberof UnderpostDockerCompose
|
|
420
|
-
*/
|
|
421
|
-
static instancesNginxContent(options = {}) {
|
|
422
|
-
const topology = UnderpostDockerCompose.instanceTopology(options);
|
|
423
|
-
if (!topology) return null;
|
|
424
|
-
const { variants } = topology;
|
|
425
|
-
|
|
426
|
-
const headers = ` proxy_set_header Host $host;
|
|
427
|
-
proxy_set_header X-Real-IP $remote_addr;
|
|
428
|
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
429
|
-
proxy_set_header X-Forwarded-Proto $scheme;
|
|
430
|
-
proxy_set_header Upgrade $http_upgrade;
|
|
431
|
-
proxy_set_header Connection $connection_upgrade;
|
|
432
|
-
proxy_read_timeout 3600s;`;
|
|
433
|
-
|
|
434
|
-
const proxyBlock = (variable, upstream, extra = '') =>
|
|
435
|
-
` set ${variable} ${upstream};
|
|
436
|
-
${extra} proxy_pass http://${variable};
|
|
437
|
-
${headers}`;
|
|
438
|
-
|
|
439
|
-
// Websocket tier: /<path>/ws -> server (prefix stripped); default -> = /ws.
|
|
440
|
-
// Longest-prefix ensures /<path>/ws beats the /<path> client location.
|
|
441
|
-
const wsLocations = variants
|
|
442
|
-
.map((v) => {
|
|
443
|
-
const upstream = `cyberia-server${v.suffix}:8081`;
|
|
444
|
-
const varName = `$up_server_${v.slug || 'default'}`;
|
|
445
|
-
if (v.isDefault) return ` location = /ws {\n${proxyBlock(varName, upstream)}\n }`;
|
|
446
|
-
return ` location ${v.path}/ws {\n${proxyBlock(
|
|
447
|
-
varName,
|
|
448
|
-
upstream,
|
|
449
|
-
` rewrite ^${v.path}/(.*)$ /$1 break;\n`,
|
|
450
|
-
)}\n }`;
|
|
451
|
-
})
|
|
452
|
-
.join('\n\n');
|
|
453
|
-
|
|
454
|
-
// Presentation tier: /<path> -> client (prefix kept); default -> catch-all /.
|
|
455
|
-
const clientLocations = variants
|
|
456
|
-
.map((v) => {
|
|
457
|
-
const upstream = `cyberia-client${v.suffix}:8081`;
|
|
458
|
-
const varName = `$up_client_${v.slug || 'default'}`;
|
|
459
|
-
if (v.isDefault) return ` location / {\n${proxyBlock(varName, upstream)}\n }`;
|
|
460
|
-
return ` location = ${v.path} { return 301 ${v.path}/; }
|
|
461
|
-
location ${v.path} {\n${proxyBlock(varName, upstream)}\n }`;
|
|
462
|
-
})
|
|
463
|
-
.join('\n\n');
|
|
464
|
-
|
|
465
|
-
const deployId = options.deployId || DEFAULT_DEPLOY_ID;
|
|
466
|
-
return `# Generated by 'underpost docker-compose --generate --deploy-id ${deployId} --docker-compose-id ${options.dockerComposeId || 'cyberia'}' — do not hand-edit.
|
|
467
|
-
# Source of truth: engine-private/conf/${deployId}/conf.instances.json (multiInstance).
|
|
468
|
-
# Single localhost gateway (dev compose). Access http://localhost/ (default),
|
|
469
|
-
# http://localhost/<PATH> per variant. Client origins point back here
|
|
470
|
-
# (compose.env CYBERIA_WS_ORIGIN=ws://localhost, CYBERIA_ENGINE_API_ORIGIN=http://localhost).
|
|
471
|
-
|
|
472
|
-
map $http_upgrade $connection_upgrade {
|
|
473
|
-
default upgrade;
|
|
474
|
-
'' close;
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
# Docker embedded DNS: resolve upstream names per request so a variant that is
|
|
478
|
-
# briefly down never fails nginx startup or config reload.
|
|
479
|
-
resolver 127.0.0.11 ipv6=off valid=10s;
|
|
480
|
-
|
|
481
|
-
proxy_http_version 1.1;
|
|
482
|
-
|
|
483
|
-
server {
|
|
484
|
-
listen 80 default_server;
|
|
485
|
-
server_name localhost 127.0.0.1 _;
|
|
486
|
-
|
|
487
|
-
location = /healthz {
|
|
488
|
-
access_log off;
|
|
489
|
-
return 200 "ok\\n";
|
|
490
|
-
add_header Content-Type text/plain;
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
# Shared content authority: REST API + engine-served assets (fonts, ui-icons).
|
|
494
|
-
location /api/ {
|
|
495
|
-
${proxyBlock('$up_engine', 'engine-cyberia:4005')}
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
location /assets/ {
|
|
499
|
-
${proxyBlock('$up_engine', 'engine-cyberia:4005')}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
${wsLocations}
|
|
503
|
-
|
|
504
|
-
${clientLocations}
|
|
505
|
-
}
|
|
506
|
-
`;
|
|
507
|
-
}
|
|
508
|
-
|
|
509
365
|
/**
|
|
510
366
|
* Renders all dynamic supporting files: the nginx reverse-proxy config (from
|
|
511
367
|
* PROXY_HOSTS), the monitoring configs (Prometheus + Grafana datasource), and
|
|
@@ -516,25 +372,17 @@ ${clientLocations}
|
|
|
516
372
|
* @memberof UnderpostDockerCompose
|
|
517
373
|
*/
|
|
518
374
|
static generate(options = {}) {
|
|
519
|
-
//
|
|
520
|
-
//
|
|
521
|
-
//
|
|
522
|
-
// bootstrap) and, for a multi-instance deploy, nginx.conf (per-variant
|
|
523
|
-
// sub-path routing derived from the conf.instances.json multiInstance block,
|
|
524
|
-
// kept in sync with the service tiers hand-authored in docker-compose.yml).
|
|
375
|
+
// A named custom workflow is fully owned by its canonical directory. The
|
|
376
|
+
// generic CLI validates the standard entry files but never imports project
|
|
377
|
+
// modules or generates application-specific nginx, env, or helper content.
|
|
525
378
|
const composeIdBase = UnderpostDockerCompose.composeIdBase(options);
|
|
526
379
|
if (composeIdBase) {
|
|
527
|
-
const
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
if (nginx) {
|
|
534
|
-
const nginxPath = UnderpostDockerCompose.resolve(`${composeIdBase}/nginx.conf`);
|
|
535
|
-
fs.writeFileSync(nginxPath, nginx, 'utf8');
|
|
536
|
-
logger.info('multi-instance nginx.conf written', { path: nginxPath });
|
|
537
|
-
}
|
|
380
|
+
const required = ['docker-compose.yml', 'compose.env'].map((name) =>
|
|
381
|
+
UnderpostDockerCompose.resolve(`${composeIdBase}/${name}`),
|
|
382
|
+
);
|
|
383
|
+
const missing = required.filter((path) => !fs.existsSync(path));
|
|
384
|
+
if (missing.length) throw new Error(`Custom Docker Compose workflow is missing: ${missing.join(', ')}`);
|
|
385
|
+
logger.info('custom Docker Compose workflow uses canonical files as-is', { path: composeIdBase });
|
|
538
386
|
return;
|
|
539
387
|
}
|
|
540
388
|
|
|
@@ -644,17 +492,10 @@ ${clientLocations}
|
|
|
644
492
|
silentOnError: true,
|
|
645
493
|
});
|
|
646
494
|
|
|
647
|
-
//
|
|
648
|
-
//
|
|
649
|
-
// nginx.conf is left in place so the mount stays valid and --generate/--up
|
|
650
|
-
// rewrites it.
|
|
495
|
+
// A named custom workflow owns every file beneath its canonical directory.
|
|
496
|
+
// Reset tears down Docker resources but never prunes project-owned files.
|
|
651
497
|
const composeIdBase = UnderpostDockerCompose.composeIdBase(options);
|
|
652
498
|
if (composeIdBase) {
|
|
653
|
-
const mongoEntrypointPath = UnderpostDockerCompose.resolve(`${composeIdBase}/mongodb/entrypoint.sh`);
|
|
654
|
-
if (fs.existsSync(mongoEntrypointPath)) {
|
|
655
|
-
fs.removeSync(mongoEntrypointPath);
|
|
656
|
-
logger.info('removed generated artifact', { path: mongoEntrypointPath });
|
|
657
|
-
}
|
|
658
499
|
logger.info('Docker Compose reset complete. Run `--up` to recreate the stack.');
|
|
659
500
|
return;
|
|
660
501
|
}
|
|
@@ -699,7 +540,7 @@ ${clientLocations}
|
|
|
699
540
|
* @param {boolean} [options.shell] - Open an interactive shell in `target` (default: app).
|
|
700
541
|
* @param {string} [options.exec] - General-purpose passthrough docker compose subcommand.
|
|
701
542
|
* @param {string} [options.deployId] - Deployment to run as the app (default: dd-default). `dd-default` self-bootstraps a fresh engine; any other id runs the standard `underpost start` command.
|
|
702
|
-
* @param {string} [options.dockerComposeId] - Custom-workflow selector. When set, use the canonical stack at `engine-private/conf/<deploy-id>/docker-compose/<docker-compose-id>/` (docker-compose.yml + compose.env
|
|
543
|
+
* @param {string} [options.dockerComposeId] - Custom-workflow selector. When set, use the canonical stack at `engine-private/conf/<deploy-id>/docker-compose/<docker-compose-id>/` (docker-compose.yml + compose.env, used as-is), skipping nginx/env/app-override generation.
|
|
703
544
|
* @param {string} [options.env] - Deployment environment for non-default deploy ids (default: development).
|
|
704
545
|
* @param {string} [options.composeFile] - Override compose file path.
|
|
705
546
|
* @param {string} [options.envFile] - Override env-file path.
|
package/src/cli/env.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @namespace UnderpostEnv
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { getNpmRootPath, writeEnv } from '../server/
|
|
7
|
+
import { getNpmRootPath, writeEnv } from '../server/environment.js';
|
|
8
8
|
import fs from 'fs-extra';
|
|
9
9
|
import { loggerFactory } from '../server/logger.js';
|
|
10
10
|
import dotenv from 'dotenv';
|
package/src/cli/image.js
CHANGED
|
@@ -10,8 +10,8 @@ import nodePath from 'path';
|
|
|
10
10
|
import crypto from 'crypto';
|
|
11
11
|
import { loggerFactory } from '../server/logger.js';
|
|
12
12
|
import Underpost from '../index.js';
|
|
13
|
-
import { getNpmRootPath } from '../server/conf.js';
|
|
14
13
|
import { shellExec } from '../server/process.js';
|
|
14
|
+
import { crictlCommandFactory } from '../server/cri.js';
|
|
15
15
|
|
|
16
16
|
const logger = loggerFactory(import.meta);
|
|
17
17
|
|
|
@@ -225,6 +225,7 @@ class UnderpostImage {
|
|
|
225
225
|
* @param {object} options - Options for the image retrieval.
|
|
226
226
|
* @param {boolean} options.spec - Whether to retrieve images from the pod specifications.
|
|
227
227
|
* @param {string} options.namespace - Kubernetes namespace to filter pods.
|
|
228
|
+
* @param {boolean} [options.k3s] - Resolve the CRI endpoint as K3s' embedded containerd.
|
|
228
229
|
* @returns {Array<object>} - Array of objects containing pod names and their corresponding images.
|
|
229
230
|
* @memberof UnderpostImage
|
|
230
231
|
*/
|
|
@@ -245,10 +246,17 @@ class UnderpostImage {
|
|
|
245
246
|
}))
|
|
246
247
|
.filter((o) => o.image);
|
|
247
248
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
249
|
+
// Outside kind, target the live CRI endpoint explicitly: /etc/crictl.yaml
|
|
250
|
+
// may still point at a CRI-O socket the host no longer runs.
|
|
251
|
+
const raw = shellExec(
|
|
252
|
+
node === 'kind-worker'
|
|
253
|
+
? `docker exec -i ${node} crictl images`
|
|
254
|
+
: crictlCommandFactory('images', options || {}),
|
|
255
|
+
{
|
|
256
|
+
stdout: true,
|
|
257
|
+
silent: true,
|
|
258
|
+
},
|
|
259
|
+
);
|
|
252
260
|
|
|
253
261
|
const heads = raw
|
|
254
262
|
.split(`\n`)[0]
|
|
@@ -312,7 +320,7 @@ class UnderpostImage {
|
|
|
312
320
|
shellExec(`docker exec -i kind-control-plane crictl rmi ${imageName}`);
|
|
313
321
|
shellExec(`docker exec -i kind-worker crictl rmi ${imageName}`);
|
|
314
322
|
} else if (kubeadm === true) {
|
|
315
|
-
shellExec(`
|
|
323
|
+
shellExec(crictlCommandFactory(`rmi ${imageName}`));
|
|
316
324
|
} else if (k3s === true) {
|
|
317
325
|
shellExec(`sudo k3s ctr images rm ${imageName}`);
|
|
318
326
|
}
|
|
@@ -381,7 +389,7 @@ class UnderpostImage {
|
|
|
381
389
|
shellExec(`docker pull ${image}`);
|
|
382
390
|
shellExec(`sudo kind load docker-image ${image}`);
|
|
383
391
|
} else {
|
|
384
|
-
shellExec(`
|
|
392
|
+
shellExec(crictlCommandFactory(`pull ${image}`, { k3s: targetK3s }));
|
|
385
393
|
}
|
|
386
394
|
},
|
|
387
395
|
};
|