plugin-cluster-manager 1.1.5 → 1.1.7
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/README.md +17 -5
- package/dist/client/index.js +1 -1
- package/dist/externalVersion.js +5 -5
- package/dist/locale/en-US.json +28 -4
- package/dist/locale/vi-VN.json +28 -4
- package/dist/locale/zh-CN.json +28 -4
- package/dist/server/actions/event-queue-monitor.js +123 -1
- package/dist/server/actions/orchestrator.js +1 -1
- package/dist/server/actions/plugin-operations.js +171 -0
- package/dist/server/collections/cluster-manager-plugins.js +44 -0
- package/dist/server/plugin.js +8 -2
- package/package.json +9 -4
- package/src/client/ClusterManagerLayout.tsx +16 -10
- package/src/client/EventQueueMonitor.tsx +349 -202
- package/src/client/PluginOperations.tsx +234 -0
- package/src/locale/en-US.json +28 -4
- package/src/locale/vi-VN.json +28 -4
- package/src/locale/zh-CN.json +28 -4
- package/src/server/actions/event-queue-monitor.ts +234 -95
- package/src/server/actions/orchestrator.ts +1 -1
- package/src/server/actions/plugin-operations.ts +151 -0
- package/src/server/collections/cluster-manager-plugins.ts +19 -0
- package/src/server/orchestrator/PackageManager.ts +84 -17
- package/src/server/plugin.ts +28 -20
- package/dist/client/AclCacheManager.d.ts +0 -2
- package/dist/client/CacheMonitor.d.ts +0 -2
- package/dist/client/ClusterManagerLayout.d.ts +0 -2
- package/dist/client/ClusterNodes.d.ts +0 -2
- package/dist/client/ContainerOrchestrator.d.ts +0 -2
- package/dist/client/EventQueueMonitor.d.ts +0 -2
- package/dist/client/LockMonitor.d.ts +0 -2
- package/dist/client/PackageInstaller.d.ts +0 -2
- package/dist/client/RedisMonitor.d.ts +0 -2
- package/dist/client/TaskManager.d.ts +0 -2
- package/dist/client/WorkflowExecutions.d.ts +0 -2
- package/dist/client/index.d.ts +0 -5
- package/dist/client/utils.d.ts +0 -12
- package/dist/index.d.ts +0 -2
- package/dist/server/actions/acl-cache.d.ts +0 -53
- package/dist/server/actions/cache-monitor.d.ts +0 -23
- package/dist/server/actions/cluster-nodes.d.ts +0 -49
- package/dist/server/actions/event-queue-monitor.d.ts +0 -13
- package/dist/server/actions/lock-monitor.d.ts +0 -19
- package/dist/server/actions/orchestrator.d.ts +0 -58
- package/dist/server/actions/package-manager.d.ts +0 -6
- package/dist/server/actions/redis-monitor.d.ts +0 -12
- package/dist/server/actions/tasks.d.ts +0 -7
- package/dist/server/actions/workflow-executions.d.ts +0 -7
- package/dist/server/adapters/redis-lock-adapter.d.ts +0 -15
- package/dist/server/adapters/redis-node-registry.d.ts +0 -12
- package/dist/server/adapters/redis-pubsub-adapter.d.ts +0 -16
- package/dist/server/collections/app.d.ts +0 -8
- package/dist/server/collections/cluster-manager-acl-cache.d.ts +0 -22
- package/dist/server/collections/cluster-manager-cache-mgr.d.ts +0 -22
- package/dist/server/collections/cluster-manager-cluster.d.ts +0 -22
- package/dist/server/collections/cluster-manager-lock.d.ts +0 -22
- package/dist/server/collections/cluster-manager-queue.d.ts +0 -22
- package/dist/server/collections/cluster-manager-redis.d.ts +0 -22
- package/dist/server/collections/cluster-manager-workflow.d.ts +0 -22
- package/dist/server/collections/cluster-manager.d.ts +0 -22
- package/dist/server/collections/orchestrator-settings.d.ts +0 -59
- package/dist/server/collections/orchestrator-stacks.d.ts +0 -102
- package/dist/server/collections/worker-orchestrator.d.ts +0 -22
- package/dist/server/collections/worker-packages-configs.d.ts +0 -3
- package/dist/server/collections/worker-packages.d.ts +0 -22
- package/dist/server/index.d.ts +0 -1
- package/dist/server/orchestrator/PackageManager.d.ts +0 -37
- package/dist/server/orchestrator/docker-adapter.d.ts +0 -41
- package/dist/server/orchestrator/index.d.ts +0 -4
- package/dist/server/orchestrator/k8s-adapter.d.ts +0 -50
- package/dist/server/orchestrator/leader-election.d.ts +0 -48
- package/dist/server/orchestrator/types.d.ts +0 -84
- package/dist/server/plugin.d.ts +0 -26
- package/dist/server/utils/node.d.ts +0 -6
- package/dist/server/utils/redis.d.ts +0 -29
- package/dist/shared/packages.d.ts +0 -23
|
@@ -5,7 +5,7 @@ import path from 'path';
|
|
|
5
5
|
import Application from '@nocobase/server';
|
|
6
6
|
|
|
7
7
|
/** Allow only safe package name characters: letters, digits, dash, underscore, dot, @, /, [, ] */
|
|
8
|
-
const SAFE_PKG_RE = /^[a-zA-Z0-9_
|
|
8
|
+
const SAFE_PKG_RE = /^(?:[a-zA-Z0-9_.@/-]|\[|\])+$/;
|
|
9
9
|
const INSTALL_CHANNEL = 'cluster-manager.install-packages';
|
|
10
10
|
|
|
11
11
|
type TargetRole = 'app' | 'worker' | 'sandbox' | 'all';
|
|
@@ -17,6 +17,11 @@ interface InstallPayload {
|
|
|
17
17
|
registryConfig?: { aptMirrorUrl?: string; npmRegistryUrl?: string; pypiIndexUrl?: string; pypiTrustedHost?: string };
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
interface AptOsInfo {
|
|
21
|
+
id: string;
|
|
22
|
+
codename: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
20
25
|
function sanitizePkg(name: string): string {
|
|
21
26
|
if (typeof name !== 'string') {
|
|
22
27
|
throw new Error('Package name must be a string');
|
|
@@ -81,10 +86,44 @@ function formatCommand(command: string, args: string[]): string {
|
|
|
81
86
|
.join(' ');
|
|
82
87
|
}
|
|
83
88
|
|
|
89
|
+
function parseOsRelease(content: string): Record<string, string> {
|
|
90
|
+
const values: Record<string, string> = {};
|
|
91
|
+
for (const line of content.split('\n')) {
|
|
92
|
+
const match = line.match(/^([A-Z0-9_]+)=(.*)$/);
|
|
93
|
+
if (!match) continue;
|
|
94
|
+
|
|
95
|
+
values[match[1]] = match[2].replace(/^"|"$/g, '');
|
|
96
|
+
}
|
|
97
|
+
return values;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function normalizeMirrorUrl(value: string): string {
|
|
101
|
+
return value.endsWith('/') ? value : `${value}/`;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function isInternalCacheMirror(url: URL): boolean {
|
|
105
|
+
return url.hostname === 'nginx-cache-registry';
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function resolveAptMirrorForOs(aptMirrorUrl: string, osInfo: AptOsInfo, logs: string[]): string {
|
|
109
|
+
const url = new URL(normalizeMirrorUrl(aptMirrorUrl));
|
|
110
|
+
const original = url.toString();
|
|
111
|
+
|
|
112
|
+
if (isInternalCacheMirror(url) && osInfo.id === 'debian' && url.pathname === '/ubuntu/') {
|
|
113
|
+
url.pathname = '/debian/';
|
|
114
|
+
} else if (isInternalCacheMirror(url) && osInfo.id === 'ubuntu' && url.pathname === '/debian/') {
|
|
115
|
+
url.pathname = '/ubuntu/';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const resolved = url.toString();
|
|
119
|
+
if (resolved !== original) {
|
|
120
|
+
logs.push(`Adjusted APT mirror for ${osInfo.id}: ${redactUrl(resolved)}`);
|
|
121
|
+
}
|
|
122
|
+
return resolved;
|
|
123
|
+
}
|
|
124
|
+
|
|
84
125
|
export class PackageManager {
|
|
85
|
-
constructor(
|
|
86
|
-
private app: Application,
|
|
87
|
-
) {}
|
|
126
|
+
constructor(private app: Application) {}
|
|
88
127
|
|
|
89
128
|
/**
|
|
90
129
|
* Called from REST action when admin clicks "Install Packages".
|
|
@@ -107,9 +146,7 @@ export class PackageManager {
|
|
|
107
146
|
// Filter by role
|
|
108
147
|
const currentRole = getCurrentRole();
|
|
109
148
|
const roleMatches =
|
|
110
|
-
targetRole === 'all' ||
|
|
111
|
-
targetRole === currentRole ||
|
|
112
|
-
(targetRole === 'worker' && currentRole === 'sandbox');
|
|
149
|
+
targetRole === 'all' || targetRole === currentRole || (targetRole === 'worker' && currentRole === 'sandbox');
|
|
113
150
|
|
|
114
151
|
if (!roleMatches) {
|
|
115
152
|
return; // Skip if role doesn't match
|
|
@@ -138,7 +175,7 @@ export class PackageManager {
|
|
|
138
175
|
if (registryConfig.aptMirrorUrl) {
|
|
139
176
|
const aptMirrorUrl = sanitizeHttpUrl(registryConfig.aptMirrorUrl, 'APT mirror URL');
|
|
140
177
|
logs.push(`Applying APT mirror: ${redactUrl(aptMirrorUrl)}`);
|
|
141
|
-
await this.configureAptMirror(aptMirrorUrl);
|
|
178
|
+
await this.configureAptMirror(aptMirrorUrl, logs);
|
|
142
179
|
}
|
|
143
180
|
|
|
144
181
|
await this.updateInstallStatus('running', 20, 'Installing APT packages...', logs);
|
|
@@ -241,7 +278,13 @@ export class PackageManager {
|
|
|
241
278
|
/**
|
|
242
279
|
* Run a command without a shell so registry URLs and package names are not re-parsed as shell syntax.
|
|
243
280
|
*/
|
|
244
|
-
private async runCommand(
|
|
281
|
+
private async runCommand(
|
|
282
|
+
command: string,
|
|
283
|
+
args: string[],
|
|
284
|
+
label: string,
|
|
285
|
+
logs: string[],
|
|
286
|
+
timeoutMs = 1200000,
|
|
287
|
+
): Promise<void> {
|
|
245
288
|
logs.push(`RUNNING: ${formatCommand(command, args)}`);
|
|
246
289
|
logs.push(`${label}`);
|
|
247
290
|
|
|
@@ -250,12 +293,12 @@ export class PackageManager {
|
|
|
250
293
|
let stdout = '';
|
|
251
294
|
let stderr = '';
|
|
252
295
|
let settled = false;
|
|
253
|
-
|
|
296
|
+
const state: { timer?: NodeJS.Timeout } = {};
|
|
254
297
|
|
|
255
298
|
const finish = (error?: Error) => {
|
|
256
299
|
if (settled) return;
|
|
257
300
|
settled = true;
|
|
258
|
-
clearTimeout(timer);
|
|
301
|
+
if (state.timer) clearTimeout(state.timer);
|
|
259
302
|
if (stdout) logs.push(stdout.slice(0, 500));
|
|
260
303
|
if (stderr) logs.push(`WARN: ${stderr.slice(0, 300)}`);
|
|
261
304
|
if (error) {
|
|
@@ -266,7 +309,7 @@ export class PackageManager {
|
|
|
266
309
|
}
|
|
267
310
|
};
|
|
268
311
|
|
|
269
|
-
timer = setTimeout(() => {
|
|
312
|
+
state.timer = setTimeout(() => {
|
|
270
313
|
child.kill('SIGTERM');
|
|
271
314
|
finish(new Error(`${command} timed out after ${timeoutMs}ms`));
|
|
272
315
|
}, timeoutMs);
|
|
@@ -324,16 +367,16 @@ export class PackageManager {
|
|
|
324
367
|
const child = spawn(command, args, { stdio: ['ignore', 'pipe', 'ignore'] });
|
|
325
368
|
let stdout = '';
|
|
326
369
|
let settled = false;
|
|
327
|
-
|
|
370
|
+
const state: { timer?: NodeJS.Timeout } = {};
|
|
328
371
|
|
|
329
372
|
const finish = (ok: boolean) => {
|
|
330
373
|
if (settled) return;
|
|
331
374
|
settled = true;
|
|
332
|
-
clearTimeout(timer);
|
|
375
|
+
if (state.timer) clearTimeout(state.timer);
|
|
333
376
|
resolve(ok);
|
|
334
377
|
};
|
|
335
378
|
|
|
336
|
-
timer = setTimeout(() => {
|
|
379
|
+
state.timer = setTimeout(() => {
|
|
337
380
|
child.kill('SIGTERM');
|
|
338
381
|
finish(false);
|
|
339
382
|
}, timeoutMs);
|
|
@@ -346,7 +389,31 @@ export class PackageManager {
|
|
|
346
389
|
});
|
|
347
390
|
}
|
|
348
391
|
|
|
349
|
-
private async
|
|
392
|
+
private async getAptOsInfo(): Promise<AptOsInfo> {
|
|
393
|
+
const values = parseOsRelease(await fsp.readFile('/etc/os-release', 'utf8'));
|
|
394
|
+
const id = (values.ID || '').toLowerCase();
|
|
395
|
+
const codename = values.VERSION_CODENAME || values.UBUNTU_CODENAME;
|
|
396
|
+
|
|
397
|
+
if (!id || !codename) {
|
|
398
|
+
throw new Error('Cannot detect OS ID/version codename from /etc/os-release for APT mirror configuration.');
|
|
399
|
+
}
|
|
400
|
+
return { id, codename };
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
private buildAptSources(aptMirrorUrl: string, osInfo: AptOsInfo): string {
|
|
404
|
+
const mirror = normalizeMirrorUrl(aptMirrorUrl);
|
|
405
|
+
if (osInfo.id === 'ubuntu') {
|
|
406
|
+
return `deb ${mirror} ${osInfo.codename} main universe restricted multiverse\n`;
|
|
407
|
+
}
|
|
408
|
+
if (osInfo.id === 'debian') {
|
|
409
|
+
return `deb ${mirror} ${osInfo.codename} main contrib non-free non-free-firmware\n`;
|
|
410
|
+
}
|
|
411
|
+
return `deb ${mirror} ${osInfo.codename} main\n`;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
private async configureAptMirror(aptMirrorUrl: string, logs: string[]): Promise<void> {
|
|
415
|
+
const osInfo = await this.getAptOsInfo();
|
|
416
|
+
const resolvedMirrorUrl = resolveAptMirrorForOs(aptMirrorUrl, osInfo, logs);
|
|
350
417
|
const backupDir = '/etc/apt/sources.list.d.bak';
|
|
351
418
|
await fsp.mkdir(backupDir, { recursive: true });
|
|
352
419
|
|
|
@@ -362,7 +429,7 @@ export class PackageManager {
|
|
|
362
429
|
// sources.list.d may not exist in minimal images.
|
|
363
430
|
}
|
|
364
431
|
|
|
365
|
-
await fsp.writeFile('/etc/apt/sources.list',
|
|
432
|
+
await fsp.writeFile('/etc/apt/sources.list', this.buildAptSources(resolvedMirrorUrl, osInfo), 'utf8');
|
|
366
433
|
}
|
|
367
434
|
|
|
368
435
|
private async moveIfExists(from: string, to: string): Promise<void> {
|
package/src/server/plugin.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { RedisPubSubAdapter } from './adapters/redis-pubsub-adapter';
|
|
|
15
15
|
import { RedisNodeRegistry } from './adapters/redis-node-registry';
|
|
16
16
|
import { RedisLockAdapter } from './adapters/redis-lock-adapter';
|
|
17
17
|
import { orchestratorActions } from './actions/orchestrator';
|
|
18
|
+
import { pluginOperationsActions } from './actions/plugin-operations';
|
|
18
19
|
import type { IOrchestratorAdapter } from './orchestrator/types';
|
|
19
20
|
import { DockerAdapter } from './orchestrator/docker-adapter';
|
|
20
21
|
import { K8sAdapter } from './orchestrator/k8s-adapter';
|
|
@@ -240,11 +241,17 @@ export class PluginClusterManagerServer extends Plugin {
|
|
|
240
241
|
actions: cacheMonitorActions,
|
|
241
242
|
});
|
|
242
243
|
|
|
243
|
-
// Package manager (installs apt/npm/python packages across nodes)
|
|
244
|
-
this.app.resourcer.define({
|
|
245
|
-
name: 'workerPackages',
|
|
246
|
-
actions: packageManagerActions,
|
|
247
|
-
});
|
|
244
|
+
// Package manager (installs apt/npm/python packages across nodes)
|
|
245
|
+
this.app.resourcer.define({
|
|
246
|
+
name: 'workerPackages',
|
|
247
|
+
actions: packageManagerActions,
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Plugin operations (force disable/remove application plugin records)
|
|
251
|
+
this.app.resourcer.define({
|
|
252
|
+
name: 'clusterManagerPlugins',
|
|
253
|
+
actions: pluginOperationsActions,
|
|
254
|
+
});
|
|
248
255
|
|
|
249
256
|
// Install ACL cache middleware inside the ACL chain so cached permissions are not overwritten.
|
|
250
257
|
const aclCacheMiddleware = createAclCacheMiddleware(this.app);
|
|
@@ -279,11 +286,12 @@ export class PluginClusterManagerServer extends Plugin {
|
|
|
279
286
|
'clusterManagerQueue:*',
|
|
280
287
|
'clusterManagerLock:*',
|
|
281
288
|
'clusterManagerCacheMgr:*',
|
|
282
|
-
'workerOrchestrator:*',
|
|
283
|
-
'orchestratorStacks:*',
|
|
284
|
-
'workerPackages:*',
|
|
285
|
-
|
|
286
|
-
|
|
289
|
+
'workerOrchestrator:*',
|
|
290
|
+
'orchestratorStacks:*',
|
|
291
|
+
'workerPackages:*',
|
|
292
|
+
'clusterManagerPlugins:*',
|
|
293
|
+
],
|
|
294
|
+
});
|
|
287
295
|
|
|
288
296
|
// ── Container Orchestrator ──
|
|
289
297
|
await this.initOrchestrator();
|
|
@@ -365,16 +373,16 @@ export class PluginClusterManagerServer extends Plugin {
|
|
|
365
373
|
} else {
|
|
366
374
|
// Fall back to env var for initial setup
|
|
367
375
|
const envAdapter = process.env.ORCHESTRATOR_ADAPTER;
|
|
368
|
-
if (envAdapter && envAdapter !== 'none') {
|
|
369
|
-
await this.connectAdapter({
|
|
370
|
-
adapterType: envAdapter,
|
|
371
|
-
dockerSocketPath: process.env.DOCKER_SOCKET || '/var/run/docker.sock',
|
|
372
|
-
k8sNamespace: 'nocobase',
|
|
373
|
-
});
|
|
374
|
-
} else {
|
|
375
|
-
this.app.logger.info('[Orchestrator] No adapter configured — configurable via
|
|
376
|
-
}
|
|
377
|
-
}
|
|
376
|
+
if (envAdapter && envAdapter !== 'none') {
|
|
377
|
+
await this.connectAdapter({
|
|
378
|
+
adapterType: envAdapter,
|
|
379
|
+
dockerSocketPath: process.env.DOCKER_SOCKET || '/var/run/docker.sock',
|
|
380
|
+
k8sNamespace: 'nocobase',
|
|
381
|
+
});
|
|
382
|
+
} else {
|
|
383
|
+
this.app.logger.info('[Orchestrator] No adapter configured — configurable via Cluster Manager UI');
|
|
384
|
+
}
|
|
385
|
+
}
|
|
378
386
|
} catch (err: any) {
|
|
379
387
|
this.app.logger.warn(`[Orchestrator] Could not load settings: ${err.message}`);
|
|
380
388
|
}
|
package/dist/client/index.d.ts
DELETED
package/dist/client/utils.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared i18n hook for the cluster-manager plugin.
|
|
3
|
-
*/
|
|
4
|
-
export declare function useT(): (key: string) => string;
|
|
5
|
-
/**
|
|
6
|
-
* Format bytes into human-readable string (B, KB, MB, GB).
|
|
7
|
-
*/
|
|
8
|
-
export declare function formatBytes(bytes: number): string;
|
|
9
|
-
/**
|
|
10
|
-
* Format seconds into human-readable uptime string (e.g., "2d 5h 30m").
|
|
11
|
-
*/
|
|
12
|
-
export declare function formatUptime(seconds: number): string;
|
package/dist/index.d.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { Context } from '@nocobase/actions';
|
|
2
|
-
/**
|
|
3
|
-
* In-memory ACL stats counter.
|
|
4
|
-
* Tracks total checks, cache hits/misses per role:resource:action.
|
|
5
|
-
*/
|
|
6
|
-
export interface AclCacheStats {
|
|
7
|
-
totalChecks: number;
|
|
8
|
-
cacheHits: number;
|
|
9
|
-
cacheMisses: number;
|
|
10
|
-
startedAt: string;
|
|
11
|
-
detailByRole: Record<string, {
|
|
12
|
-
checks: number;
|
|
13
|
-
hits: number;
|
|
14
|
-
misses: number;
|
|
15
|
-
}>;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Middleware that caches the permission object computed by the ACL middleware.
|
|
19
|
-
* Install via: app.acl.use(aclCacheMiddleware, { tag: 'aclCache', before: 'core', after: 'allow-manager' })
|
|
20
|
-
*
|
|
21
|
-
* FIX: Previously monkey-patched ctx.app.acl.can per-request, which is a race condition
|
|
22
|
-
* because acl is a shared singleton across concurrent requests. Now we use a post-check
|
|
23
|
-
* approach that reads from cache first and writes after the ACL middleware runs, without
|
|
24
|
-
* ever replacing the shared acl.can method.
|
|
25
|
-
*/
|
|
26
|
-
export declare function createAclCacheMiddleware(app: any): (ctx: Context, next: () => Promise<void>) => Promise<void>;
|
|
27
|
-
export declare const aclCacheActions: {
|
|
28
|
-
/**
|
|
29
|
-
* GET /clusterManagerAclCache:stats
|
|
30
|
-
* Returns ACL cache hit/miss statistics
|
|
31
|
-
*/
|
|
32
|
-
stats(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
33
|
-
/**
|
|
34
|
-
* GET /clusterManagerAclCache:listKeys
|
|
35
|
-
* Lists all cached ACL permission keys
|
|
36
|
-
*/
|
|
37
|
-
listKeys(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
38
|
-
/**
|
|
39
|
-
* POST /clusterManagerAclCache:clear
|
|
40
|
-
* Clear all ACL cache entries and reset stats
|
|
41
|
-
*/
|
|
42
|
-
clear(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
43
|
-
/**
|
|
44
|
-
* POST /clusterManagerAclCache:resetStats
|
|
45
|
-
* Reset the in-memory ACL stats counters
|
|
46
|
-
*/
|
|
47
|
-
resetStats(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
48
|
-
/**
|
|
49
|
-
* POST /clusterManagerAclCache:clearRole
|
|
50
|
-
* Clear ACL cache entries for a specific role
|
|
51
|
-
*/
|
|
52
|
-
clearRole(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
53
|
-
};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Context } from '@nocobase/actions';
|
|
2
|
-
export declare const cacheMonitorActions: {
|
|
3
|
-
/**
|
|
4
|
-
* GET /clusterManagerCacheMgr:stores
|
|
5
|
-
* List all registered cache stores and their config
|
|
6
|
-
*/
|
|
7
|
-
stores(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
8
|
-
/**
|
|
9
|
-
* GET /clusterManagerCacheMgr:caches
|
|
10
|
-
* List all created named caches
|
|
11
|
-
*/
|
|
12
|
-
caches(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
13
|
-
/**
|
|
14
|
-
* GET /clusterManagerCacheMgr:redisMemory
|
|
15
|
-
* Get Redis memory usage for cache keys
|
|
16
|
-
*/
|
|
17
|
-
redisMemory(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
18
|
-
/**
|
|
19
|
-
* POST /clusterManagerCacheMgr:flushAll
|
|
20
|
-
* Flush all caches via CacheManager
|
|
21
|
-
*/
|
|
22
|
-
flushAll(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
23
|
-
};
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { Context } from '@nocobase/actions';
|
|
2
|
-
/**
|
|
3
|
-
* Read the last N lines from the local system log file.
|
|
4
|
-
* Extracted so it can be called from both the HTTP action and the PubSub subscriber.
|
|
5
|
-
*/
|
|
6
|
-
export declare function readLocalLogs(app: any, maxLines: number): Promise<{
|
|
7
|
-
node: {
|
|
8
|
-
hostname: string;
|
|
9
|
-
pid: number;
|
|
10
|
-
workerMode: string;
|
|
11
|
-
};
|
|
12
|
-
lines: string[];
|
|
13
|
-
file: string;
|
|
14
|
-
}>;
|
|
15
|
-
export declare const clusterActions: {
|
|
16
|
-
/**
|
|
17
|
-
* GET /clusterManagerCluster:current
|
|
18
|
-
* Always returns info about the APP node (not workers).
|
|
19
|
-
* If this request is handled by a worker, we look up the APP node from Redis.
|
|
20
|
-
*/
|
|
21
|
-
current(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
22
|
-
/**
|
|
23
|
-
* GET /clusterManagerCluster:list
|
|
24
|
-
* Returns all known cluster environments/nodes (if discovery adapter supports it)
|
|
25
|
-
*/
|
|
26
|
-
list(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
27
|
-
/**
|
|
28
|
-
* GET /clusterManagerCluster:health
|
|
29
|
-
* Health check for all subsystems
|
|
30
|
-
*/
|
|
31
|
-
health(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
32
|
-
/**
|
|
33
|
-
* POST /clusterManagerCluster:restart
|
|
34
|
-
* Publishes a restart signal to target nodes orchestrating a soft NocoBase restart or a hard docker daemon rebirth
|
|
35
|
-
*/
|
|
36
|
-
restart(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
37
|
-
/**
|
|
38
|
-
* GET /clusterManagerCluster:logs?targetNodeId=xxx&lines=200
|
|
39
|
-
*
|
|
40
|
-
* HA-aware log viewer. Reads logs from a specific node in the cluster.
|
|
41
|
-
*
|
|
42
|
-
* Flow:
|
|
43
|
-
* 1. If targetNodeId matches current node (or is empty) → read local FS directly
|
|
44
|
-
* 2. Otherwise → publish a log request via PubSub → target node reads its local FS
|
|
45
|
-
* and writes the result to a Redis key → this handler polls Redis until the
|
|
46
|
-
* response arrives (max 10s) → returns it to the client
|
|
47
|
-
*/
|
|
48
|
-
logs(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
49
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Context } from '@nocobase/actions';
|
|
2
|
-
export declare const eventQueueActions: {
|
|
3
|
-
/**
|
|
4
|
-
* GET /clusterManagerQueue:stats
|
|
5
|
-
* Returns event queue statistics
|
|
6
|
-
*/
|
|
7
|
-
stats(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
8
|
-
/**
|
|
9
|
-
* GET /clusterManagerQueue:messages
|
|
10
|
-
* List pending messages in a specific channel (memory adapter only)
|
|
11
|
-
*/
|
|
12
|
-
messages(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
13
|
-
};
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { Context } from '@nocobase/actions';
|
|
2
|
-
export declare const lockActions: {
|
|
3
|
-
/**
|
|
4
|
-
* GET /clusterManagerLock:info
|
|
5
|
-
* Returns lock manager info
|
|
6
|
-
*/
|
|
7
|
-
info(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
8
|
-
/**
|
|
9
|
-
* GET /clusterManagerLock:list
|
|
10
|
-
* List active locks
|
|
11
|
-
*/
|
|
12
|
-
list(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
13
|
-
/**
|
|
14
|
-
* POST /clusterManagerLock:release
|
|
15
|
-
* Force release a stuck lock (admin emergency action)
|
|
16
|
-
* Uses compare-and-swap via DEL for Redis locks with the correct key prefix.
|
|
17
|
-
*/
|
|
18
|
-
release(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
19
|
-
};
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Orchestrator Actions
|
|
3
|
-
*
|
|
4
|
-
* API endpoints for container management. Write operations (scale, start, stop, remove)
|
|
5
|
-
* are guarded by leader election — only the leader node can execute them.
|
|
6
|
-
*/
|
|
7
|
-
import { Context } from '@nocobase/actions';
|
|
8
|
-
export declare const orchestratorActions: {
|
|
9
|
-
/**
|
|
10
|
-
* GET /workerOrchestrator:ping
|
|
11
|
-
* Test connectivity to the container runtime
|
|
12
|
-
*/
|
|
13
|
-
ping(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
14
|
-
/**
|
|
15
|
-
* GET /workerOrchestrator:containers?stackId=1
|
|
16
|
-
* List live containers for a stack
|
|
17
|
-
*/
|
|
18
|
-
containers(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
19
|
-
/**
|
|
20
|
-
* POST /workerOrchestrator:scale
|
|
21
|
-
* Body: { stackId: 1, replicas: 3 }
|
|
22
|
-
* Leader-only
|
|
23
|
-
*/
|
|
24
|
-
scale(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
25
|
-
/**
|
|
26
|
-
* POST /workerOrchestrator:start
|
|
27
|
-
* Body: { stackId: 1, containerId: "abc123" }
|
|
28
|
-
* Leader-only
|
|
29
|
-
*/
|
|
30
|
-
start(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
31
|
-
/**
|
|
32
|
-
* POST /workerOrchestrator:stop
|
|
33
|
-
* Body: { stackId: 1, containerId: "abc123" }
|
|
34
|
-
* Leader-only
|
|
35
|
-
*/
|
|
36
|
-
stop(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
37
|
-
/**
|
|
38
|
-
* POST /workerOrchestrator:remove
|
|
39
|
-
* Body: { stackId: 1, containerId: "abc123" }
|
|
40
|
-
* Leader-only
|
|
41
|
-
*/
|
|
42
|
-
remove(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
43
|
-
/**
|
|
44
|
-
* GET /workerOrchestrator:stats?containerId=abc123
|
|
45
|
-
* Get real-time stats for a container
|
|
46
|
-
*/
|
|
47
|
-
stats(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
48
|
-
/**
|
|
49
|
-
* GET /workerOrchestrator:logs?containerId=abc123&tail=100
|
|
50
|
-
* Get tail logs from a container
|
|
51
|
-
*/
|
|
52
|
-
logs(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
53
|
-
/**
|
|
54
|
-
* GET /workerOrchestrator:networks
|
|
55
|
-
* List available networks (if supported by adapter)
|
|
56
|
-
*/
|
|
57
|
-
networks(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
58
|
-
};
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export declare const packageManagerActions: {
|
|
2
|
-
installPackages(ctx: any, next: () => Promise<void>): Promise<void>;
|
|
3
|
-
getPackageConfig(ctx: any, next: () => Promise<void>): Promise<void>;
|
|
4
|
-
savePackageConfig(ctx: any, next: () => Promise<void>): Promise<void>;
|
|
5
|
-
resetInitStatus(ctx: any, next: () => Promise<void>): Promise<void>;
|
|
6
|
-
};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { Context } from '@nocobase/actions';
|
|
2
|
-
export declare const redisActions: {
|
|
3
|
-
info(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
4
|
-
clients(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
5
|
-
pubsub(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
6
|
-
slowlog(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
7
|
-
/**
|
|
8
|
-
* GET /clusterManagerRedis:syncMessages
|
|
9
|
-
* Returns info about NocoBase sync message channels (pub/sub layer)
|
|
10
|
-
*/
|
|
11
|
-
syncMessages(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
12
|
-
};
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { Context } from '@nocobase/actions';
|
|
2
|
-
export declare const tasksActions: {
|
|
3
|
-
list(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
4
|
-
cancel(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
5
|
-
retry(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
6
|
-
purge(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
7
|
-
};
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { Context } from '@nocobase/actions';
|
|
2
|
-
export declare const workflowActions: {
|
|
3
|
-
list(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
4
|
-
getJobs(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
5
|
-
cancel(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
6
|
-
purge(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
7
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { ILockAdapter, ILock, Releaser } from '@nocobase/lock-manager';
|
|
2
|
-
import { Application } from '@nocobase/server';
|
|
3
|
-
export declare class RedisLockAdapter implements ILockAdapter {
|
|
4
|
-
private options;
|
|
5
|
-
private client;
|
|
6
|
-
constructor(options: {
|
|
7
|
-
url?: string;
|
|
8
|
-
app: Application;
|
|
9
|
-
});
|
|
10
|
-
connect(): Promise<void>;
|
|
11
|
-
close(): Promise<void>;
|
|
12
|
-
acquire(key: string, ttl: number): Promise<Releaser>;
|
|
13
|
-
runExclusive<T>(key: string, fn: () => Promise<T>, ttl: number): Promise<T>;
|
|
14
|
-
tryAcquire(key: string, timeout?: number): Promise<ILock>;
|
|
15
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export declare class RedisNodeRegistry {
|
|
2
|
-
private app;
|
|
3
|
-
private timer;
|
|
4
|
-
private readonly ttlSecs;
|
|
5
|
-
private readonly intervalMs;
|
|
6
|
-
private readonly keyPrefix;
|
|
7
|
-
constructor(app: any);
|
|
8
|
-
start(): void;
|
|
9
|
-
stop(): void;
|
|
10
|
-
private heartbeat;
|
|
11
|
-
getNodes(): Promise<any[]>;
|
|
12
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { IPubSubAdapter, PubSubCallback } from '@nocobase/server';
|
|
2
|
-
export declare class RedisPubSubAdapter implements IPubSubAdapter {
|
|
3
|
-
private url;
|
|
4
|
-
private logger?;
|
|
5
|
-
private publisher;
|
|
6
|
-
private subscriber;
|
|
7
|
-
private connected;
|
|
8
|
-
private subscriptions;
|
|
9
|
-
constructor(url: string, logger?: any);
|
|
10
|
-
isConnected(): boolean;
|
|
11
|
-
connect(): Promise<void>;
|
|
12
|
-
close(): Promise<void>;
|
|
13
|
-
subscribe(channel: string, callback: PubSubCallback): Promise<void>;
|
|
14
|
-
unsubscribe(channel: string, callback: PubSubCallback): Promise<void>;
|
|
15
|
-
publish(channel: string, message: string): Promise<void>;
|
|
16
|
-
}
|