underpost 3.2.70 → 3.2.90
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/publish.ci.yml +3 -3
- package/.github/workflows/release.cd.yml +1 -1
- package/CHANGELOG.md +1358 -1038
- package/CLI-HELP.md +39 -16
- package/README.md +3 -3
- package/bin/build.js +10 -4
- package/bin/deploy.js +18 -16
- package/docker-compose.yml +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
- 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 +20 -20
- package/scripts/nat-iptables.sh +10 -4
- package/scripts/test-monitor.sh +4 -3
- package/src/api/core/core.controller.js +4 -65
- package/src/api/core/core.router.js +8 -14
- package/src/api/default/default.controller.js +2 -70
- package/src/api/default/default.router.js +7 -17
- package/src/api/document/document.controller.js +5 -77
- package/src/api/document/document.router.js +9 -13
- package/src/api/file/file.controller.js +9 -53
- package/src/api/file/file.router.js +14 -6
- package/src/api/test/test.controller.js +8 -53
- package/src/api/test/test.router.js +1 -4
- package/src/cli/cluster.js +771 -66
- package/src/cli/db.js +6 -4
- package/src/cli/deploy.js +1715 -168
- package/src/cli/docker-compose.js +19 -24
- package/src/cli/fs.js +0 -1
- package/src/cli/image.js +40 -13
- package/src/cli/index.js +129 -35
- package/src/cli/ipfs.js +82 -11
- package/src/cli/monitor.js +1 -1
- package/src/cli/release.js +4 -0
- package/src/cli/repository.js +14 -3
- package/src/cli/run.js +2253 -439
- package/src/cli/secrets.js +969 -0
- package/src/cli/ssh.js +38 -39
- package/src/client/components/core/Modal.js +38 -4
- package/src/client-builder/client-build.js +94 -11
- package/src/client-builder/ssr.js +27 -73
- package/src/db/mongo/MongoBootstrap.js +295 -54
- package/src/db/mongo/MongooseDB.js +47 -32
- package/src/index.js +1 -1
- package/src/server/conf.js +1307 -6
- package/src/server/cri.js +70 -0
- package/src/server/downloader.js +3 -3
- package/src/server/middlewares.js +152 -0
- package/src/server/underpost-gateway.js +1073 -0
- package/src/server/underpost-ingress.js +364 -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/sops-secret-store.test.js +612 -0
- package/test/underpost-gateway.test.js +469 -0
- package/test/underpost-ingress.test.js +253 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CRI (Container Runtime Interface) endpoint resolution shared by every layer
|
|
3
|
+
* that shells out to `crictl`: the cluster CLI, image management, and the
|
|
4
|
+
* database bootstraps. Lives under `src/server` so the db layer can import it
|
|
5
|
+
* without depending on the CLI god-object.
|
|
6
|
+
* @module src/server/cri.js
|
|
7
|
+
* @namespace CriEndpoint
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { shellExec } from './process.js';
|
|
11
|
+
|
|
12
|
+
const CRIO_SOCKET_PATH = '/var/run/crio/crio.sock';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @constant CRI_SOCKETS
|
|
16
|
+
* @description The CRI endpoints this platform ever targets.
|
|
17
|
+
* @memberof CriEndpoint
|
|
18
|
+
*/
|
|
19
|
+
const CRI_SOCKETS = {
|
|
20
|
+
crio: `unix://${CRIO_SOCKET_PATH}`,
|
|
21
|
+
containerd: 'unix:///run/containerd/containerd.sock',
|
|
22
|
+
k3s: 'unix:///run/k3s/containerd/containerd.sock',
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @method resolveCriSocket
|
|
27
|
+
* @description Resolves the CRI endpoint a `crictl` or `kubeadm` call should
|
|
28
|
+
* target. K3s runs its own embedded containerd; a kubeadm host uses CRI-O only
|
|
29
|
+
* while that socket actually exists, otherwise the host-level containerd.
|
|
30
|
+
*
|
|
31
|
+
* Detection is by socket presence, never by configuration, so a host whose
|
|
32
|
+
* CRI-O install was removed or stopped still resolves to a runtime that answers.
|
|
33
|
+
* @param {object} [options] - Resolution inputs.
|
|
34
|
+
* @param {boolean} [options.k3s=false] - Whether the cluster is K3s-based.
|
|
35
|
+
* @param {string} [options.criSocket] - Explicit endpoint override (highest precedence).
|
|
36
|
+
* @returns {string} CRI endpoint URI.
|
|
37
|
+
* @memberof CriEndpoint
|
|
38
|
+
*/
|
|
39
|
+
const resolveCriSocket = (options = {}) => {
|
|
40
|
+
if (options?.criSocket) return options.criSocket;
|
|
41
|
+
if (options?.k3s) return CRI_SOCKETS.k3s;
|
|
42
|
+
const runtime = shellExec(`test -S ${CRIO_SOCKET_PATH} && echo crio || echo containerd`, {
|
|
43
|
+
stdout: true,
|
|
44
|
+
silent: true,
|
|
45
|
+
}).trim();
|
|
46
|
+
return runtime === 'crio' ? CRI_SOCKETS.crio : CRI_SOCKETS.containerd;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @method crictlCommandFactory
|
|
51
|
+
* @description Builds a `crictl` invocation pinned to the live CRI endpoint.
|
|
52
|
+
*
|
|
53
|
+
* Both `--runtime-endpoint` and `--image-endpoint` are passed. crictl resolves
|
|
54
|
+
* the two independently, and `run install-crio` writes both into
|
|
55
|
+
* `/etc/crictl.yaml` pointing at CRI-O; overriding only the runtime leaves image
|
|
56
|
+
* operations (`pull`, `rmi`, `images`) validating a `crio.sock` that no longer
|
|
57
|
+
* exists, which fails with "validate CRI v1 image API for endpoint".
|
|
58
|
+
*
|
|
59
|
+
* crictl is not on sudo's secure_path, hence the explicit PATH.
|
|
60
|
+
* @param {string} args - crictl subcommand and arguments (e.g. `pull mongo:latest`).
|
|
61
|
+
* @param {object} [options] - Forwarded to {@link CriEndpoint.resolveCriSocket}.
|
|
62
|
+
* @returns {string} Full shell command.
|
|
63
|
+
* @memberof CriEndpoint
|
|
64
|
+
*/
|
|
65
|
+
const crictlCommandFactory = (args, options = {}) => {
|
|
66
|
+
const socket = resolveCriSocket(options);
|
|
67
|
+
return `sudo env PATH="$PATH:/usr/local/bin:/usr/bin" crictl --runtime-endpoint ${socket} --image-endpoint ${socket} ${args}`;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export { CRI_SOCKETS, resolveCriSocket, crictlCommandFactory };
|
package/src/server/downloader.js
CHANGED
|
@@ -41,18 +41,18 @@ class Downloader {
|
|
|
41
41
|
const writer = fs.createWriteStream(fullPath);
|
|
42
42
|
response.data.pipe(writer);
|
|
43
43
|
writer.on('finish', () => {
|
|
44
|
-
logger.info('Download
|
|
44
|
+
logger.info('Download completet');
|
|
45
45
|
return resolve(fullPath);
|
|
46
46
|
});
|
|
47
47
|
writer.on('error', (error) => {
|
|
48
|
-
logger.error(
|
|
48
|
+
logger.error('Error downloading the file');
|
|
49
49
|
// Cleanup incomplete file if possible
|
|
50
50
|
if (fs.existsSync(fullPath)) fs.unlinkSync(fullPath);
|
|
51
51
|
return reject(error);
|
|
52
52
|
});
|
|
53
53
|
})
|
|
54
54
|
.catch((error) => {
|
|
55
|
-
logger.error(
|
|
55
|
+
logger.error('Error in the request');
|
|
56
56
|
return reject(error);
|
|
57
57
|
}),
|
|
58
58
|
);
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Express middleware and controller/router helpers for engine APIs.
|
|
3
|
+
*
|
|
4
|
+
* @module src/server/middlewares.js
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { loggerFactory } from './logger.js';
|
|
8
|
+
import { moderatorGuard, adminGuard } from './auth.js';
|
|
9
|
+
|
|
10
|
+
const logger = loggerFactory(import.meta);
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The public-read CORS policy: reflect the request origin (or allow any)
|
|
14
|
+
* and mark the resource embeddable cross-origin.
|
|
15
|
+
* @param {import('express').Request} req
|
|
16
|
+
* @param {import('express').Response} res
|
|
17
|
+
*/
|
|
18
|
+
const setCrossOriginHeaders = (req, res) => {
|
|
19
|
+
if (req && req.headers && req.headers.origin) res.set('Access-Control-Allow-Origin', req.headers.origin);
|
|
20
|
+
else res.setHeader('Access-Control-Allow-Origin', '*');
|
|
21
|
+
res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin');
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/** Express middleware form of {@link setCrossOriginHeaders}. */
|
|
25
|
+
const crossOriginMiddleware = (req, res, next) => {
|
|
26
|
+
setCrossOriginHeaders(req, res);
|
|
27
|
+
next();
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Shallow request copy with `page`/`limit` parsed to integers.
|
|
32
|
+
* `path` and `params` are copied explicitly because spreading an Express
|
|
33
|
+
* request drops prototype getters.
|
|
34
|
+
* @param {import('express').Request} req
|
|
35
|
+
*/
|
|
36
|
+
const withParsedPagination = (req) => {
|
|
37
|
+
const { page, limit } = req.query;
|
|
38
|
+
return {
|
|
39
|
+
...req,
|
|
40
|
+
path: req.path,
|
|
41
|
+
params: req.params,
|
|
42
|
+
query: { ...req.query, page: parseInt(page), limit: parseInt(limit) },
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const sendSuccess = (res, data) => res.status(200).json({ status: 'success', data });
|
|
47
|
+
|
|
48
|
+
const sendError = (res, error, status = 400) => res.status(status).json({ status: 'error', message: error.message });
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Binary response with cross-origin and content headers.
|
|
52
|
+
* @param {import('express').Request} req
|
|
53
|
+
* @param {import('express').Response} res
|
|
54
|
+
* @param {{ buffer: Buffer, mimetype: string, filename: string, disposition?: 'inline'|'attachment' }} blob
|
|
55
|
+
*/
|
|
56
|
+
const sendBlob = (req, res, { buffer, mimetype, filename, disposition = 'inline' }) => {
|
|
57
|
+
setCrossOriginHeaders(req, res);
|
|
58
|
+
res.setHeader('Content-Type', mimetype);
|
|
59
|
+
res.setHeader('Content-Length', buffer.length);
|
|
60
|
+
res.setHeader('Content-Disposition', `${disposition}; filename="${filename}"`);
|
|
61
|
+
return res.status(200).end(buffer);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Wraps a controller body with error logging and the error response envelope.
|
|
66
|
+
* @param {(req, res, options) => Promise<any>} fn
|
|
67
|
+
* @param {{ errorStatus?: number }} [config]
|
|
68
|
+
*/
|
|
69
|
+
const controllerHandler =
|
|
70
|
+
(fn, { errorStatus = 400 } = {}) =>
|
|
71
|
+
async (req, res, options) => {
|
|
72
|
+
try {
|
|
73
|
+
return await fn(req, res, options);
|
|
74
|
+
} catch (error) {
|
|
75
|
+
logger.error(error, error.stack);
|
|
76
|
+
return sendError(res, error, errorStatus);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Builds a controller method that delegates to a service method and wraps the
|
|
82
|
+
* result in the success envelope.
|
|
83
|
+
* @param {(req, res, options) => Promise<any>} serviceFn
|
|
84
|
+
* @param {{ errorStatus?: number, crossOrigin?: boolean, pagination?: boolean }} [config]
|
|
85
|
+
*/
|
|
86
|
+
const serviceHandler = (serviceFn, { errorStatus = 400, crossOrigin = false, pagination = false } = {}) =>
|
|
87
|
+
controllerHandler(
|
|
88
|
+
async (req, res, options) => {
|
|
89
|
+
if (crossOrigin) setCrossOriginHeaders(req, res);
|
|
90
|
+
const result = await serviceFn(pagination ? withParsedPagination(req) : req, res, options);
|
|
91
|
+
return sendSuccess(res, result);
|
|
92
|
+
},
|
|
93
|
+
{ errorStatus },
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Builds a standard CRUD controller class (static post/get/put/delete) from a
|
|
98
|
+
* service exposing the same methods. `get` parses pagination.
|
|
99
|
+
* @param {{ post, get, put, delete }} service
|
|
100
|
+
* @param {Object<string, Function>} [extend] - Extra or overriding static handlers.
|
|
101
|
+
*/
|
|
102
|
+
const buildCrudController = (service, extend = {}) => {
|
|
103
|
+
class CrudController {
|
|
104
|
+
static post = serviceHandler(service.post);
|
|
105
|
+
static get = serviceHandler(service.get, { pagination: true });
|
|
106
|
+
static put = serviceHandler(service.put);
|
|
107
|
+
static delete = serviceHandler(service.delete);
|
|
108
|
+
}
|
|
109
|
+
Object.assign(CrudController, extend);
|
|
110
|
+
return CrudController;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Registers the standard CRUD routes with the standard guard policy:
|
|
115
|
+
* public reads, moderator-guarded writes, admin-guarded collection delete.
|
|
116
|
+
* Custom routes must be registered before calling this (generic `/:id` routes
|
|
117
|
+
* capture everything).
|
|
118
|
+
* @param {import('express').Router} router
|
|
119
|
+
* @param {{ post, get, put, delete }} Controller
|
|
120
|
+
* @param {import('../../api/types.js').RouterOptions} options
|
|
121
|
+
* @param {{ readGuards?: Function[], writeGuards?: Function[], deleteAllGuards?: Function[] }} [config]
|
|
122
|
+
* Pass empty arrays for unguarded endpoints (e.g. player-written progress)
|
|
123
|
+
* or explicit guard chains (e.g. admin-only reads).
|
|
124
|
+
* @returns {import('express').Router}
|
|
125
|
+
*/
|
|
126
|
+
const registerCrudRoutes = (router, Controller, options, { readGuards = [], writeGuards, deleteAllGuards } = {}) => {
|
|
127
|
+
const write = writeGuards ?? [options.authMiddleware, moderatorGuard];
|
|
128
|
+
const deleteAll = deleteAllGuards ?? [options.authMiddleware, adminGuard];
|
|
129
|
+
const handle = (method) => async (req, res) => await Controller[method](req, res, options);
|
|
130
|
+
router.post(`/:id`, ...write, handle('post'));
|
|
131
|
+
router.post(`/`, ...write, handle('post'));
|
|
132
|
+
router.get(`/:id`, ...readGuards, handle('get'));
|
|
133
|
+
router.get(`/`, ...readGuards, handle('get'));
|
|
134
|
+
router.put(`/:id`, ...write, handle('put'));
|
|
135
|
+
router.put(`/`, ...write, handle('put'));
|
|
136
|
+
router.delete(`/:id`, ...write, handle('delete'));
|
|
137
|
+
router.delete(`/`, ...deleteAll, handle('delete'));
|
|
138
|
+
return router;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export {
|
|
142
|
+
setCrossOriginHeaders,
|
|
143
|
+
crossOriginMiddleware,
|
|
144
|
+
withParsedPagination,
|
|
145
|
+
sendSuccess,
|
|
146
|
+
sendError,
|
|
147
|
+
sendBlob,
|
|
148
|
+
controllerHandler,
|
|
149
|
+
serviceHandler,
|
|
150
|
+
buildCrudController,
|
|
151
|
+
registerCrudRoutes,
|
|
152
|
+
};
|