@abtnode/core 1.16.52-beta-20251005-235515-42ad5caf → 1.16.52-beta-20251008-091027-c46c73e3
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/lib/api/team.js +30 -16
- package/lib/blocklet/manager/disk.js +23 -9
- package/lib/blocklet/manager/helper/blue-green-start-blocklet.js +110 -101
- package/lib/blocklet/migration-dist/migration.cjs +457 -456
- package/lib/states/blocklet.js +7 -6
- package/lib/states/org.js +13 -11
- package/lib/util/blocklet.js +43 -38
- package/package.json +25 -24
package/lib/api/team.js
CHANGED
|
@@ -2792,14 +2792,21 @@ class TeamAPI extends EventEmitter {
|
|
|
2792
2792
|
try {
|
|
2793
2793
|
const state = await this.getOrgState(teamDid);
|
|
2794
2794
|
const { passports, orgs, ...rest } = await state.list(payload, context);
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2795
|
+
const { includePassports = true } = payload.options || {};
|
|
2796
|
+
if (includePassports) {
|
|
2797
|
+
// 获取每个组织的 passports
|
|
2798
|
+
const orgPassports = await Promise.all(orgs.map((o) => this.getRoles({ teamDid, orgId: o.id })));
|
|
2799
|
+
|
|
2800
|
+
orgs.forEach((o, index) => {
|
|
2801
|
+
const roles = orgPassports[index]; // 获取每个组织的角色
|
|
2802
|
+
// 过滤 passports
|
|
2803
|
+
o.passports = passports.filter((p) => roles.some((r) => r.name === p.name));
|
|
2804
|
+
});
|
|
2805
|
+
} else {
|
|
2806
|
+
orgs.forEach((o) => {
|
|
2807
|
+
o.passports = [];
|
|
2808
|
+
});
|
|
2809
|
+
}
|
|
2803
2810
|
|
|
2804
2811
|
return {
|
|
2805
2812
|
...rest,
|
|
@@ -2848,7 +2855,12 @@ class TeamAPI extends EventEmitter {
|
|
|
2848
2855
|
}
|
|
2849
2856
|
|
|
2850
2857
|
const state = await this.getOrgState(teamDid);
|
|
2851
|
-
const blocklet = await getBlocklet({
|
|
2858
|
+
const blocklet = await getBlocklet({
|
|
2859
|
+
did: teamDid,
|
|
2860
|
+
states: this.states,
|
|
2861
|
+
dataDirs: this.dataDirs,
|
|
2862
|
+
useCache: true,
|
|
2863
|
+
});
|
|
2852
2864
|
const orgCount = await state.getOrgCountByUser(context.user.did);
|
|
2853
2865
|
|
|
2854
2866
|
const { veriftMaxOrgPerUser } = createOrgValidators(blocklet);
|
|
@@ -2859,13 +2871,15 @@ class TeamAPI extends EventEmitter {
|
|
|
2859
2871
|
|
|
2860
2872
|
// 创建 org 的 owner passport, 并赋值给 owner
|
|
2861
2873
|
const roleName = md5(`${result.id}-owner`); // 避免 name 重复
|
|
2862
|
-
await
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2874
|
+
await Promise.all([
|
|
2875
|
+
this.createRole({ teamDid, name: roleName, title: result.name, description: 'Owner', orgId: result.id }),
|
|
2876
|
+
this.issuePassportToUser({
|
|
2877
|
+
teamDid,
|
|
2878
|
+
userDid: result.ownerDid,
|
|
2879
|
+
role: roleName,
|
|
2880
|
+
notification: {},
|
|
2881
|
+
}),
|
|
2882
|
+
]);
|
|
2869
2883
|
|
|
2870
2884
|
return result;
|
|
2871
2885
|
} catch (err) {
|
|
@@ -2959,6 +2959,7 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
2959
2959
|
};
|
|
2960
2960
|
}
|
|
2961
2961
|
|
|
2962
|
+
let shouldRotateSession = false;
|
|
2962
2963
|
if (!isNil(org)) {
|
|
2963
2964
|
const ORG_SCHEMA = Joi.object({
|
|
2964
2965
|
enabled: Joi.boolean().required(),
|
|
@@ -2969,6 +2970,11 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
2969
2970
|
if (error) {
|
|
2970
2971
|
throw new CustomError(400, error.message);
|
|
2971
2972
|
}
|
|
2973
|
+
const currentState = await this.getBlocklet(did, { useCache: true });
|
|
2974
|
+
const orgEnabled = get(currentState, 'settings.org.enabled', false);
|
|
2975
|
+
if (orgEnabled !== org.enabled) {
|
|
2976
|
+
shouldRotateSession = true;
|
|
2977
|
+
}
|
|
2972
2978
|
params.org = org;
|
|
2973
2979
|
}
|
|
2974
2980
|
|
|
@@ -2989,6 +2995,10 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
2989
2995
|
this.emit(BlockletInternalEvents.appSettingChanged, { appDid: did });
|
|
2990
2996
|
this.emit(BlockletEvents.updated, { ...newState, context });
|
|
2991
2997
|
|
|
2998
|
+
if (shouldRotateSession) {
|
|
2999
|
+
this.teamAPI.rotateSessionKey({ teamDid: did });
|
|
3000
|
+
}
|
|
3001
|
+
|
|
2992
3002
|
return newState;
|
|
2993
3003
|
}
|
|
2994
3004
|
|
|
@@ -3519,26 +3529,30 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
3519
3529
|
isGreen,
|
|
3520
3530
|
});
|
|
3521
3531
|
|
|
3522
|
-
|
|
3532
|
+
if (needUpdateBlueStatus) {
|
|
3533
|
+
await states.blocklet.setBlockletStatus(did, BlockletStatus.stopped, {
|
|
3534
|
+
componentDids,
|
|
3535
|
+
isGreen: !isGreen,
|
|
3536
|
+
});
|
|
3537
|
+
}
|
|
3538
|
+
|
|
3539
|
+
const nextBlocklet = await this.getBlocklet(did);
|
|
3523
3540
|
|
|
3541
|
+
await this.configSynchronizer.throttledSyncAppConfig(nextBlocklet);
|
|
3542
|
+
const componentsInfo = getComponentsInternalInfo(nextBlocklet);
|
|
3524
3543
|
this.emit(BlockletInternalEvents.componentStarted, {
|
|
3525
3544
|
appDid: blocklet.appDid,
|
|
3526
|
-
components:
|
|
3545
|
+
components: componentsInfo,
|
|
3527
3546
|
});
|
|
3528
|
-
this.configSynchronizer.throttledSyncAppConfig(res);
|
|
3529
3547
|
|
|
3530
|
-
this.emit(BlockletEvents.statusChange,
|
|
3531
|
-
this.emit(BlockletEvents.started, { ...
|
|
3548
|
+
this.emit(BlockletEvents.statusChange, nextBlocklet);
|
|
3549
|
+
this.emit(BlockletEvents.started, { ...nextBlocklet, componentDids });
|
|
3532
3550
|
|
|
3533
3551
|
launcher.notifyBlockletStarted(blocklet);
|
|
3534
3552
|
|
|
3535
3553
|
logger.info('blocklet healthy', { did, name, time: Date.now() - startedAt });
|
|
3536
3554
|
|
|
3537
3555
|
if (needUpdateBlueStatus) {
|
|
3538
|
-
await states.blocklet.setBlockletStatus(did, BlockletStatus.stopped, {
|
|
3539
|
-
componentDids,
|
|
3540
|
-
isGreen: !isGreen,
|
|
3541
|
-
});
|
|
3542
3556
|
try {
|
|
3543
3557
|
await this.deleteProcess({ did, componentDids, isGreen: !isGreen }, context);
|
|
3544
3558
|
} catch {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable no-await-in-loop */
|
|
2
2
|
const logger = require('@abtnode/logger')('@abtnode/core:blocklet-manager:blue-green');
|
|
3
|
-
const { BlockletStatus, BlockletGroup, BlockletEvents } = require('@blocklet/constant');
|
|
3
|
+
const { BlockletStatus, BlockletGroup, BlockletEvents, BlockletInternalEvents } = require('@blocklet/constant');
|
|
4
4
|
const {
|
|
5
5
|
hasRunnableComponent,
|
|
6
6
|
getDisplayName,
|
|
@@ -9,6 +9,7 @@ const {
|
|
|
9
9
|
getComponentMissingConfigs,
|
|
10
10
|
} = require('@blocklet/meta/lib/util');
|
|
11
11
|
const { getBlockletEngine, hasStartEngine } = require('@blocklet/meta/lib/engine');
|
|
12
|
+
const { getComponentsInternalInfo } = require('@blocklet/meta/lib/blocklet');
|
|
12
13
|
const {
|
|
13
14
|
forEachBlocklet,
|
|
14
15
|
validateBlocklet,
|
|
@@ -168,123 +169,131 @@ const blueGreenStartBlocklet = async (
|
|
|
168
169
|
const blueGreenComponentIds = await blueGreenGetComponentIds(blocklet1, entryComponentIds);
|
|
169
170
|
|
|
170
171
|
// eslint-disable-next-line no-unreachable-loop
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
172
|
+
for (const item of blueGreenComponentIds) {
|
|
173
|
+
if (!item.componentDids.length) {
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
const nextBlocklet = await ensureAppPortsNotOccupied({
|
|
177
|
+
blocklet: blocklet1,
|
|
178
|
+
componentDids: item.componentDids,
|
|
179
|
+
states,
|
|
180
|
+
manager,
|
|
181
|
+
isGreen: item.changeToGreen,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
const doc1 = await states.blocklet.setBlockletStatus(did, BlockletStatus.starting, {
|
|
178
186
|
componentDids: item.componentDids,
|
|
179
|
-
|
|
180
|
-
manager,
|
|
187
|
+
operator,
|
|
181
188
|
isGreen: item.changeToGreen,
|
|
182
189
|
});
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
componentDids: item.componentDids,
|
|
186
|
-
operator,
|
|
187
|
-
isGreen: item.changeToGreen,
|
|
188
|
-
});
|
|
189
|
-
nextBlocklet.greenStatus = BlockletStatus.starting;
|
|
190
|
-
manager.emit(BlockletEvents.statusChange, doc1);
|
|
190
|
+
nextBlocklet.greenStatus = BlockletStatus.starting;
|
|
191
|
+
manager.emit(BlockletEvents.statusChange, doc1);
|
|
191
192
|
|
|
192
|
-
|
|
193
|
-
|
|
193
|
+
const nodeInfo = await states.node.read();
|
|
194
|
+
const nodeEnvironments = await states.node.getEnvironments();
|
|
194
195
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
env,
|
|
212
|
-
...hookArgs,
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
return hooks[hookName](b, {
|
|
216
|
-
appDir: b.env.appDir,
|
|
217
|
-
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
196
|
+
// 钩子函数设置
|
|
197
|
+
const getHookFn =
|
|
198
|
+
(hookName) =>
|
|
199
|
+
async (b, { env }) => {
|
|
200
|
+
const hookArgs = getHookArgs(b);
|
|
201
|
+
const needRunDocker = await checkNeedRunDocker(b.meta, env, nodeInfo, isExternalBlocklet(nextBlocklet));
|
|
202
|
+
if (!b.meta.scripts?.[hookName]) {
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
if (needRunDocker) {
|
|
206
|
+
return dockerExec({
|
|
207
|
+
blocklet: nextBlocklet,
|
|
208
|
+
meta: b.meta,
|
|
209
|
+
script: b.meta.scripts?.[hookName],
|
|
210
|
+
hookName,
|
|
211
|
+
nodeInfo,
|
|
218
212
|
env,
|
|
219
|
-
did, // root blocklet did,
|
|
220
|
-
teamManager: manager.teamManager,
|
|
221
213
|
...hookArgs,
|
|
222
214
|
});
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
componentDids: item.componentDids,
|
|
234
|
-
configSynchronizer: manager.configSynchronizer,
|
|
235
|
-
isGreen: item.changeToGreen,
|
|
236
|
-
});
|
|
215
|
+
}
|
|
216
|
+
return hooks[hookName](b, {
|
|
217
|
+
appDir: b.env.appDir,
|
|
218
|
+
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
219
|
+
env,
|
|
220
|
+
did, // root blocklet did,
|
|
221
|
+
teamManager: manager.teamManager,
|
|
222
|
+
...hookArgs,
|
|
223
|
+
});
|
|
224
|
+
};
|
|
237
225
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
226
|
+
await startBlockletProcess(nextBlocklet, {
|
|
227
|
+
...context,
|
|
228
|
+
preFlight: getHookFn('preFlight'),
|
|
229
|
+
preStart: getHookFn('preStart'),
|
|
230
|
+
postStart: getHookFn('postStart'),
|
|
231
|
+
nodeEnvironments,
|
|
232
|
+
nodeInfo,
|
|
233
|
+
e2eMode,
|
|
234
|
+
componentDids: item.componentDids,
|
|
235
|
+
configSynchronizer: manager.configSynchronizer,
|
|
236
|
+
isGreen: item.changeToGreen,
|
|
237
|
+
});
|
|
243
238
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
timeout: startTimeout,
|
|
250
|
-
componentDids: item.componentDids,
|
|
251
|
-
},
|
|
252
|
-
{ throwOnError: true, isGreen: item.changeToGreen, needUpdateBlueStatus: true }
|
|
253
|
-
);
|
|
239
|
+
// 健康检查绿色环境
|
|
240
|
+
const { startTimeout, minConsecutiveTime } = getHealthyCheckTimeout(nextBlocklet, {
|
|
241
|
+
checkHealthImmediately,
|
|
242
|
+
componentDids: item.componentDids,
|
|
243
|
+
});
|
|
254
244
|
|
|
255
|
-
|
|
245
|
+
await manager._onCheckIfStarted(
|
|
246
|
+
{
|
|
256
247
|
did,
|
|
248
|
+
context,
|
|
249
|
+
minConsecutiveTime,
|
|
250
|
+
timeout: startTimeout,
|
|
257
251
|
componentDids: item.componentDids,
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
logger.error('Failed to start green environment', { error, did, title: blocklet1.meta.title });
|
|
252
|
+
},
|
|
253
|
+
{ throwOnError: true, isGreen: item.changeToGreen, needUpdateBlueStatus: true }
|
|
254
|
+
);
|
|
262
255
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
256
|
+
logger.info('Green environment started successfully', {
|
|
257
|
+
did,
|
|
258
|
+
componentDids: item.componentDids,
|
|
259
|
+
});
|
|
260
|
+
} catch (err) {
|
|
261
|
+
const error = Array.isArray(err) ? err[0] : err;
|
|
262
|
+
logger.error('Failed to start green environment', { error, did, title: blocklet1.meta.title });
|
|
269
263
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
entityId: did,
|
|
277
|
-
severity: 'error',
|
|
278
|
-
});
|
|
279
|
-
}
|
|
264
|
+
try {
|
|
265
|
+
await manager.deleteProcess({ did, componentDids: item.componentDids, isGreen: item.changeToGreen });
|
|
266
|
+
manager.emit(BlockletEvents.statusChange, blocklet1);
|
|
267
|
+
} catch (cleanupError) {
|
|
268
|
+
logger.error('Failed to cleanup green environment', { cleanupError });
|
|
269
|
+
}
|
|
280
270
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
271
|
+
const description = `Green environment start failed for ${getDisplayName(blocklet1)}: ${error.message}`;
|
|
272
|
+
if (!ignoreErrorNotification) {
|
|
273
|
+
manager._createNotification(did, {
|
|
274
|
+
title: 'Blue-Green Deployment: Green Start Failed',
|
|
275
|
+
description,
|
|
276
|
+
entityType: 'blocklet',
|
|
277
|
+
entityId: did,
|
|
278
|
+
severity: 'error',
|
|
279
|
+
});
|
|
285
280
|
}
|
|
286
|
-
|
|
287
|
-
|
|
281
|
+
|
|
282
|
+
if (throwOnError) {
|
|
283
|
+
throw new Error(description);
|
|
284
|
+
}
|
|
285
|
+
throw error;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const nextBlocklet = await manager.getBlocklet(did);
|
|
290
|
+
const componentsInfo = getComponentsInternalInfo(nextBlocklet);
|
|
291
|
+
manager.emit(BlockletInternalEvents.componentStarted, {
|
|
292
|
+
appDid: nextBlocklet.appDid,
|
|
293
|
+
components: componentsInfo,
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
manager.emit(BlockletEvents.statusChange, nextBlocklet);
|
|
288
297
|
};
|
|
289
298
|
|
|
290
299
|
module.exports = {
|