@kapeta/local-cluster-service 0.27.0 → 0.28.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/CHANGELOG.md +7 -0
- package/definitions.d.ts +2 -0
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/src/api.js +2 -3
- package/dist/cjs/src/assetManager.d.ts +3 -0
- package/dist/cjs/src/assetManager.js +55 -0
- package/dist/cjs/src/definitionsManager.d.ts +1 -0
- package/dist/cjs/src/definitionsManager.js +13 -0
- package/dist/cjs/src/repositoryManager.d.ts +9 -0
- package/dist/cjs/src/repositoryManager.js +92 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/src/api.js +2 -3
- package/dist/esm/src/assetManager.d.ts +3 -0
- package/dist/esm/src/assetManager.js +55 -0
- package/dist/esm/src/definitionsManager.d.ts +1 -0
- package/dist/esm/src/definitionsManager.js +13 -0
- package/dist/esm/src/repositoryManager.d.ts +9 -0
- package/dist/esm/src/repositoryManager.js +92 -0
- package/index.ts +3 -0
- package/package.json +1 -1
- package/src/api.ts +2 -3
- package/src/assetManager.ts +64 -0
- package/src/definitionsManager.ts +18 -1
- package/src/repositoryManager.ts +114 -3
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
# [0.28.0](https://github.com/kapetacom/local-cluster-service/compare/v0.27.0...v0.28.0) (2023-11-15)
|
2
|
+
|
3
|
+
|
4
|
+
### Features
|
5
|
+
|
6
|
+
* Auto-upgrade providers every 10th minute ([#100](https://github.com/kapetacom/local-cluster-service/issues/100)) ([2c35569](https://github.com/kapetacom/local-cluster-service/commit/2c35569587f456374529bb1f9a9e8f5c03be2189))
|
7
|
+
|
1
8
|
# [0.27.0](https://github.com/kapetacom/local-cluster-service/compare/v0.26.0...v0.27.0) (2023-11-13)
|
2
9
|
|
3
10
|
|
package/definitions.d.ts
CHANGED
@@ -13,12 +13,14 @@ declare module '@kapeta/nodejs-registry-utils' {
|
|
13
13
|
export interface AssetVersion {
|
14
14
|
content: Kind;
|
15
15
|
dependencies: Dependency[];
|
16
|
+
version: string;
|
16
17
|
}
|
17
18
|
|
18
19
|
export class RegistryService {
|
19
20
|
constructor(url: string);
|
20
21
|
|
21
22
|
getVersion(fullName: string, version: string): Promise<AssetVersion>;
|
23
|
+
getLatestVersion(name): Promise<AssetVersion>;
|
22
24
|
}
|
23
25
|
|
24
26
|
export const Config: any;
|
package/dist/cjs/index.js
CHANGED
@@ -58,6 +58,7 @@ const DefaultProviderInstaller_1 = require("./src/utils/DefaultProviderInstaller
|
|
58
58
|
const authManager_1 = require("./src/authManager");
|
59
59
|
const codeGeneratorManager_1 = require("./src/codeGeneratorManager");
|
60
60
|
const Sentry = __importStar(require("@sentry/node"));
|
61
|
+
const assetManager_1 = require("./src/assetManager");
|
61
62
|
Sentry.init({
|
62
63
|
dsn: 'https://0b7cc946d82c591473d6f95fff5e210b@o4505820837249024.ingest.sentry.io/4506212692000768',
|
63
64
|
enabled: process.env.NODE_ENV !== 'development',
|
@@ -231,6 +232,7 @@ exports.default = {
|
|
231
232
|
catch (e) {
|
232
233
|
console.error('Failed to install default providers.', e);
|
233
234
|
}
|
235
|
+
assetManager_1.assetManager.startUpgradeInterval();
|
234
236
|
resolve({ host, port, dockerStatus: containerManager_1.containerManager.isAlive() });
|
235
237
|
});
|
236
238
|
currentServer.host = host;
|
package/dist/cjs/src/api.js
CHANGED
@@ -10,13 +10,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
const express_promise_router_1 = __importDefault(require("express-promise-router"));
|
11
11
|
const cors_1 = require("./middleware/cors");
|
12
12
|
const nodejs_api_client_1 = require("@kapeta/nodejs-api-client");
|
13
|
-
const
|
13
|
+
const nodejs_registry_utils_1 = require("@kapeta/nodejs-registry-utils");
|
14
14
|
const { createAPIRoute } = require('@kapeta/web-microfrontend/server');
|
15
15
|
const packageJson = require('../package.json');
|
16
16
|
const router = (0, express_promise_router_1.default)();
|
17
|
-
const remoteServices = local_cluster_config_1.default.getClusterConfig().remoteServices ?? {};
|
18
17
|
router.use('/', cors_1.corsHandler);
|
19
|
-
router.use('/registry', createAPIRoute(
|
18
|
+
router.use('/registry', createAPIRoute(nodejs_registry_utils_1.Config.data?.registry?.url ?? 'https://registry.kapeta.com', {
|
20
19
|
nonce: false,
|
21
20
|
userAgent: `KapetaDesktopCluster/${packageJson.version}`,
|
22
21
|
tokenFetcher: () => {
|
@@ -16,6 +16,7 @@ export interface EnrichedAsset {
|
|
16
16
|
ymlPath: string;
|
17
17
|
}
|
18
18
|
declare class AssetManager {
|
19
|
+
startUpgradeInterval(): void;
|
19
20
|
/**
|
20
21
|
*
|
21
22
|
* @param {string[]} [assetKinds]
|
@@ -31,6 +32,8 @@ declare class AssetManager {
|
|
31
32
|
importFile(filePath: string): Promise<EnrichedAsset[]>;
|
32
33
|
unregisterAsset(ref: string): Promise<void>;
|
33
34
|
installAsset(ref: string, wait?: boolean): Promise<import("./taskManager").Task<void>[] | undefined>;
|
35
|
+
private cleanupUnusedProviders;
|
36
|
+
private upgradeAllProviders;
|
34
37
|
private maybeGenerateCode;
|
35
38
|
}
|
36
39
|
export declare const assetManager: AssetManager;
|
@@ -20,7 +20,9 @@ const definitionsManager_1 = require("./definitionsManager");
|
|
20
20
|
const taskManager_1 = require("./taskManager");
|
21
21
|
const cacheManager_1 = require("./cacheManager");
|
22
22
|
const node_uuid_1 = __importDefault(require("node-uuid"));
|
23
|
+
const node_os_1 = __importDefault(require("node:os"));
|
23
24
|
const CACHE_TTL = 60 * 60 * 1000; // 1 hour
|
25
|
+
const UPGRADE_CHECK_INTERVAL = 10 * 60 * 1000; // 10 minutes
|
24
26
|
const toKey = (ref) => `assetManager:asset:${ref}`;
|
25
27
|
function enrichAsset(asset) {
|
26
28
|
return {
|
@@ -47,6 +49,21 @@ function parseRef(ref) {
|
|
47
49
|
return [out[0].toLowerCase(), out[1].toLowerCase()];
|
48
50
|
}
|
49
51
|
class AssetManager {
|
52
|
+
startUpgradeInterval() {
|
53
|
+
console.debug('Checking for upgrades...');
|
54
|
+
this.upgradeAllProviders()
|
55
|
+
.then((task) => {
|
56
|
+
return task && task.wait();
|
57
|
+
})
|
58
|
+
.catch((e) => {
|
59
|
+
console.error('Failed to upgrade providers', e);
|
60
|
+
})
|
61
|
+
.finally(() => {
|
62
|
+
setTimeout(() => {
|
63
|
+
this.startUpgradeInterval();
|
64
|
+
}, UPGRADE_CHECK_INTERVAL);
|
65
|
+
});
|
66
|
+
}
|
50
67
|
/**
|
51
68
|
*
|
52
69
|
* @param {string[]} [assetKinds]
|
@@ -191,6 +208,44 @@ class AssetManager {
|
|
191
208
|
definitionsManager_1.definitionsManager.clearCache();
|
192
209
|
return await repositoryManager_1.repositoryManager.ensureAsset(uri.handle, uri.name, uri.version, wait);
|
193
210
|
}
|
211
|
+
async cleanupUnusedProviders() {
|
212
|
+
const unusedProviders = await repositoryManager_1.repositoryManager.getUnusedProviders();
|
213
|
+
if (unusedProviders.length < 1) {
|
214
|
+
return;
|
215
|
+
}
|
216
|
+
console.log('Cleaning up unused providers: ', unusedProviders);
|
217
|
+
await Promise.all(unusedProviders.map((ref) => {
|
218
|
+
return this.unregisterAsset(ref);
|
219
|
+
}));
|
220
|
+
}
|
221
|
+
async upgradeAllProviders() {
|
222
|
+
const providers = await definitionsManager_1.definitionsManager.getProviderDefinitions();
|
223
|
+
const names = providers.map((p) => p.definition.metadata.name);
|
224
|
+
const refs = await repositoryManager_1.repositoryManager.getUpdatableAssets(names);
|
225
|
+
if (refs.length < 1) {
|
226
|
+
await this.cleanupUnusedProviders();
|
227
|
+
return;
|
228
|
+
}
|
229
|
+
console.log('Installing updates', refs);
|
230
|
+
const updateAll = async () => {
|
231
|
+
try {
|
232
|
+
//We change to a temp dir to avoid issues with the current working directory
|
233
|
+
process.chdir(node_os_1.default.tmpdir());
|
234
|
+
await nodejs_registry_utils_1.Actions.install(new progressListener_1.ProgressListener(), refs, {});
|
235
|
+
await this.cleanupUnusedProviders();
|
236
|
+
}
|
237
|
+
catch (e) {
|
238
|
+
console.error(`Failed to update assets: ${refs.join(',')}`, e);
|
239
|
+
throw e;
|
240
|
+
}
|
241
|
+
cacheManager_1.cacheManager.flush();
|
242
|
+
definitionsManager_1.definitionsManager.clearCache();
|
243
|
+
};
|
244
|
+
return taskManager_1.taskManager.add(`asset:update`, updateAll, {
|
245
|
+
name: `Installing ${refs.length} updates`,
|
246
|
+
group: 'asset:update:check',
|
247
|
+
});
|
248
|
+
}
|
194
249
|
async maybeGenerateCode(ref, ymlPath, block) {
|
195
250
|
ref = (0, nodejs_utils_1.normalizeKapetaUri)(ref);
|
196
251
|
if (await codeGeneratorManager_1.codeGeneratorManager.canGenerateCode(block)) {
|
@@ -11,6 +11,7 @@ declare class DefinitionsManager {
|
|
11
11
|
exists(ref: string): Promise<boolean>;
|
12
12
|
getProviderDefinitions(): Promise<DefinitionInfo[]>;
|
13
13
|
getDefinition(ref: string): Promise<DefinitionInfo | undefined>;
|
14
|
+
getLatestDefinition(name: string): Promise<DefinitionInfo | undefined>;
|
14
15
|
getVersions(assetName: string): Promise<DefinitionInfo[]>;
|
15
16
|
clearCache(): void;
|
16
17
|
}
|
@@ -136,6 +136,19 @@ class DefinitionsManager {
|
|
136
136
|
return (0, nodejs_utils_1.parseKapetaUri)(`${d.definition.metadata.name}:${d.version}`).id === uri.id;
|
137
137
|
});
|
138
138
|
}
|
139
|
+
async getLatestDefinition(name) {
|
140
|
+
const definitions = await this.getDefinitions();
|
141
|
+
const allVersions = definitions.filter((d) => {
|
142
|
+
return d.version !== 'local' && d.definition.metadata.name === name;
|
143
|
+
});
|
144
|
+
if (allVersions.length === 0) {
|
145
|
+
return;
|
146
|
+
}
|
147
|
+
allVersions.sort((a, b) => {
|
148
|
+
return (0, nodejs_utils_1.parseVersion)(a.version).compareTo((0, nodejs_utils_1.parseVersion)(b.version)) * -1;
|
149
|
+
});
|
150
|
+
return allVersions[0];
|
151
|
+
}
|
139
152
|
async getVersions(assetName) {
|
140
153
|
const uri = (0, nodejs_utils_1.parseKapetaUri)(assetName);
|
141
154
|
const definitions = await this.getDefinitions();
|
@@ -19,6 +19,15 @@ declare class RepositoryManager extends EventEmitter {
|
|
19
19
|
setSourceOfChangeFor(file: string, source: SourceOfChange): Promise<void>;
|
20
20
|
clearSourceOfChangeFor(file: string): Promise<void>;
|
21
21
|
ensureDefaultProviders(): Promise<void>;
|
22
|
+
/**
|
23
|
+
* Will go through all available assets and get a list of
|
24
|
+
* providers that are not referenced anywhere.
|
25
|
+
*
|
26
|
+
* It will also make sure to not include the latest version of an asset.
|
27
|
+
*
|
28
|
+
*/
|
29
|
+
getUnusedProviders(): Promise<string[]>;
|
30
|
+
getUpdatableAssets(allNames: string[]): Promise<string[]>;
|
22
31
|
private scheduleInstallation;
|
23
32
|
ensureAsset(handle: string, name: string, version: string, wait?: boolean): Promise<undefined | Task[]>;
|
24
33
|
}
|
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.repositoryManager = void 0;
|
11
11
|
const node_os_1 = __importDefault(require("node:os"));
|
12
12
|
const socketManager_1 = require("./socketManager");
|
13
|
+
const schemas_1 = require("@kapeta/schemas");
|
13
14
|
const nodejs_registry_utils_1 = require("@kapeta/nodejs-registry-utils");
|
14
15
|
const definitionsManager_1 = require("./definitionsManager");
|
15
16
|
const taskManager_1 = require("./taskManager");
|
@@ -69,6 +70,97 @@ class RepositoryManager extends node_events_1.EventEmitter {
|
|
69
70
|
socketManager_1.socketManager.emitGlobal(EVENT_DEFAULT_PROVIDERS_END, {});
|
70
71
|
});
|
71
72
|
}
|
73
|
+
/**
|
74
|
+
* Will go through all available assets and get a list of
|
75
|
+
* providers that are not referenced anywhere.
|
76
|
+
*
|
77
|
+
* It will also make sure to not include the latest version of an asset.
|
78
|
+
*
|
79
|
+
*/
|
80
|
+
async getUnusedProviders() {
|
81
|
+
const allDefinitions = await definitionsManager_1.definitionsManager.getDefinitions();
|
82
|
+
const blocks = [];
|
83
|
+
const plans = [];
|
84
|
+
const providerMap = new Map();
|
85
|
+
const providerVersions = {};
|
86
|
+
const unusedProviders = new Set();
|
87
|
+
allDefinitions.forEach((d) => {
|
88
|
+
if (d.definition.kind === 'core/plan') {
|
89
|
+
plans.push(d);
|
90
|
+
return;
|
91
|
+
}
|
92
|
+
if (d.definition.kind.startsWith('core/')) {
|
93
|
+
const ref = (0, nodejs_utils_1.normalizeKapetaUri)(`${d.definition.metadata.name}:${d.version}`);
|
94
|
+
providerMap.set(ref, d);
|
95
|
+
if (!providerVersions[d.definition.metadata.name]) {
|
96
|
+
providerVersions[d.definition.metadata.name] = new Set();
|
97
|
+
}
|
98
|
+
providerVersions[d.definition.metadata.name].add(d.version);
|
99
|
+
unusedProviders.add(ref);
|
100
|
+
return;
|
101
|
+
}
|
102
|
+
blocks.push(d);
|
103
|
+
});
|
104
|
+
const latestVersions = {};
|
105
|
+
Object.entries(providerVersions).forEach(([name, versions]) => {
|
106
|
+
const versionArray = Array.from(versions);
|
107
|
+
versionArray.sort((a, b) => {
|
108
|
+
return (0, nodejs_utils_1.parseVersion)(a).compareTo((0, nodejs_utils_1.parseVersion)(b)) * -1;
|
109
|
+
});
|
110
|
+
latestVersions[name] = versionArray[0];
|
111
|
+
});
|
112
|
+
function markDependencyAsUsed(dep) {
|
113
|
+
const uri = (0, nodejs_utils_1.parseKapetaUri)(dep.name);
|
114
|
+
const ref = uri.toNormalizedString();
|
115
|
+
if (unusedProviders.has(ref)) {
|
116
|
+
unusedProviders.delete(ref);
|
117
|
+
}
|
118
|
+
}
|
119
|
+
plans.forEach((plan) => {
|
120
|
+
const dependencies = (0, schemas_1.resolveDependencies)(plan.definition);
|
121
|
+
dependencies.forEach(markDependencyAsUsed);
|
122
|
+
});
|
123
|
+
blocks.forEach((block) => {
|
124
|
+
const blockTypeKind = (0, nodejs_utils_1.normalizeKapetaUri)(block.definition.kind);
|
125
|
+
unusedProviders.delete(blockTypeKind);
|
126
|
+
const blockTypeProvider = providerMap.get(blockTypeKind);
|
127
|
+
if (!blockTypeProvider) {
|
128
|
+
console.warn('No provider found for block type', block.definition.kind);
|
129
|
+
return;
|
130
|
+
}
|
131
|
+
const dependencies = (0, schemas_1.resolveDependencies)(block.definition, blockTypeProvider.definition);
|
132
|
+
dependencies.forEach(markDependencyAsUsed);
|
133
|
+
});
|
134
|
+
return Array.from(unusedProviders).filter((ref) => {
|
135
|
+
const uri = (0, nodejs_utils_1.parseKapetaUri)(ref);
|
136
|
+
if (uri.version == 'local') {
|
137
|
+
// Don't delete local assets
|
138
|
+
return false;
|
139
|
+
}
|
140
|
+
// Don't delete the latest version of an asset
|
141
|
+
return latestVersions[uri.fullName] !== uri.version;
|
142
|
+
});
|
143
|
+
}
|
144
|
+
async getUpdatableAssets(allNames) {
|
145
|
+
const names = Array.from(new Set(allNames));
|
146
|
+
const currentVersions = await Promise.all(names.map((name) => definitionsManager_1.definitionsManager.getLatestDefinition(name).catch(() => undefined)));
|
147
|
+
const latestVersions = await Promise.all(names.map((name) => this._registryService.getLatestVersion(name).catch(() => undefined)));
|
148
|
+
return names
|
149
|
+
.map((name, index) => {
|
150
|
+
const currentVersion = currentVersions[index];
|
151
|
+
const latestVersion = latestVersions[index];
|
152
|
+
if (!currentVersion || !latestVersion) {
|
153
|
+
// Shouldn't happen unless the registry is down or an asset was deleted
|
154
|
+
return undefined;
|
155
|
+
}
|
156
|
+
const ref = (0, nodejs_utils_1.normalizeKapetaUri)(`${name}:${latestVersion.version}`);
|
157
|
+
if (currentVersion.version === latestVersion.version) {
|
158
|
+
return undefined;
|
159
|
+
}
|
160
|
+
return ref;
|
161
|
+
})
|
162
|
+
.filter((ref) => !!ref);
|
163
|
+
}
|
72
164
|
async scheduleInstallation(refs) {
|
73
165
|
//We make sure to only install one asset at a time - otherwise unexpected things might happen
|
74
166
|
const createInstaller = (ref) => {
|
package/dist/esm/index.js
CHANGED
@@ -58,6 +58,7 @@ const DefaultProviderInstaller_1 = require("./src/utils/DefaultProviderInstaller
|
|
58
58
|
const authManager_1 = require("./src/authManager");
|
59
59
|
const codeGeneratorManager_1 = require("./src/codeGeneratorManager");
|
60
60
|
const Sentry = __importStar(require("@sentry/node"));
|
61
|
+
const assetManager_1 = require("./src/assetManager");
|
61
62
|
Sentry.init({
|
62
63
|
dsn: 'https://0b7cc946d82c591473d6f95fff5e210b@o4505820837249024.ingest.sentry.io/4506212692000768',
|
63
64
|
enabled: process.env.NODE_ENV !== 'development',
|
@@ -231,6 +232,7 @@ exports.default = {
|
|
231
232
|
catch (e) {
|
232
233
|
console.error('Failed to install default providers.', e);
|
233
234
|
}
|
235
|
+
assetManager_1.assetManager.startUpgradeInterval();
|
234
236
|
resolve({ host, port, dockerStatus: containerManager_1.containerManager.isAlive() });
|
235
237
|
});
|
236
238
|
currentServer.host = host;
|
package/dist/esm/src/api.js
CHANGED
@@ -10,13 +10,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
const express_promise_router_1 = __importDefault(require("express-promise-router"));
|
11
11
|
const cors_1 = require("./middleware/cors");
|
12
12
|
const nodejs_api_client_1 = require("@kapeta/nodejs-api-client");
|
13
|
-
const
|
13
|
+
const nodejs_registry_utils_1 = require("@kapeta/nodejs-registry-utils");
|
14
14
|
const { createAPIRoute } = require('@kapeta/web-microfrontend/server');
|
15
15
|
const packageJson = require('../package.json');
|
16
16
|
const router = (0, express_promise_router_1.default)();
|
17
|
-
const remoteServices = local_cluster_config_1.default.getClusterConfig().remoteServices ?? {};
|
18
17
|
router.use('/', cors_1.corsHandler);
|
19
|
-
router.use('/registry', createAPIRoute(
|
18
|
+
router.use('/registry', createAPIRoute(nodejs_registry_utils_1.Config.data?.registry?.url ?? 'https://registry.kapeta.com', {
|
20
19
|
nonce: false,
|
21
20
|
userAgent: `KapetaDesktopCluster/${packageJson.version}`,
|
22
21
|
tokenFetcher: () => {
|
@@ -16,6 +16,7 @@ export interface EnrichedAsset {
|
|
16
16
|
ymlPath: string;
|
17
17
|
}
|
18
18
|
declare class AssetManager {
|
19
|
+
startUpgradeInterval(): void;
|
19
20
|
/**
|
20
21
|
*
|
21
22
|
* @param {string[]} [assetKinds]
|
@@ -31,6 +32,8 @@ declare class AssetManager {
|
|
31
32
|
importFile(filePath: string): Promise<EnrichedAsset[]>;
|
32
33
|
unregisterAsset(ref: string): Promise<void>;
|
33
34
|
installAsset(ref: string, wait?: boolean): Promise<import("./taskManager").Task<void>[] | undefined>;
|
35
|
+
private cleanupUnusedProviders;
|
36
|
+
private upgradeAllProviders;
|
34
37
|
private maybeGenerateCode;
|
35
38
|
}
|
36
39
|
export declare const assetManager: AssetManager;
|
@@ -20,7 +20,9 @@ const definitionsManager_1 = require("./definitionsManager");
|
|
20
20
|
const taskManager_1 = require("./taskManager");
|
21
21
|
const cacheManager_1 = require("./cacheManager");
|
22
22
|
const node_uuid_1 = __importDefault(require("node-uuid"));
|
23
|
+
const node_os_1 = __importDefault(require("node:os"));
|
23
24
|
const CACHE_TTL = 60 * 60 * 1000; // 1 hour
|
25
|
+
const UPGRADE_CHECK_INTERVAL = 10 * 60 * 1000; // 10 minutes
|
24
26
|
const toKey = (ref) => `assetManager:asset:${ref}`;
|
25
27
|
function enrichAsset(asset) {
|
26
28
|
return {
|
@@ -47,6 +49,21 @@ function parseRef(ref) {
|
|
47
49
|
return [out[0].toLowerCase(), out[1].toLowerCase()];
|
48
50
|
}
|
49
51
|
class AssetManager {
|
52
|
+
startUpgradeInterval() {
|
53
|
+
console.debug('Checking for upgrades...');
|
54
|
+
this.upgradeAllProviders()
|
55
|
+
.then((task) => {
|
56
|
+
return task && task.wait();
|
57
|
+
})
|
58
|
+
.catch((e) => {
|
59
|
+
console.error('Failed to upgrade providers', e);
|
60
|
+
})
|
61
|
+
.finally(() => {
|
62
|
+
setTimeout(() => {
|
63
|
+
this.startUpgradeInterval();
|
64
|
+
}, UPGRADE_CHECK_INTERVAL);
|
65
|
+
});
|
66
|
+
}
|
50
67
|
/**
|
51
68
|
*
|
52
69
|
* @param {string[]} [assetKinds]
|
@@ -191,6 +208,44 @@ class AssetManager {
|
|
191
208
|
definitionsManager_1.definitionsManager.clearCache();
|
192
209
|
return await repositoryManager_1.repositoryManager.ensureAsset(uri.handle, uri.name, uri.version, wait);
|
193
210
|
}
|
211
|
+
async cleanupUnusedProviders() {
|
212
|
+
const unusedProviders = await repositoryManager_1.repositoryManager.getUnusedProviders();
|
213
|
+
if (unusedProviders.length < 1) {
|
214
|
+
return;
|
215
|
+
}
|
216
|
+
console.log('Cleaning up unused providers: ', unusedProviders);
|
217
|
+
await Promise.all(unusedProviders.map((ref) => {
|
218
|
+
return this.unregisterAsset(ref);
|
219
|
+
}));
|
220
|
+
}
|
221
|
+
async upgradeAllProviders() {
|
222
|
+
const providers = await definitionsManager_1.definitionsManager.getProviderDefinitions();
|
223
|
+
const names = providers.map((p) => p.definition.metadata.name);
|
224
|
+
const refs = await repositoryManager_1.repositoryManager.getUpdatableAssets(names);
|
225
|
+
if (refs.length < 1) {
|
226
|
+
await this.cleanupUnusedProviders();
|
227
|
+
return;
|
228
|
+
}
|
229
|
+
console.log('Installing updates', refs);
|
230
|
+
const updateAll = async () => {
|
231
|
+
try {
|
232
|
+
//We change to a temp dir to avoid issues with the current working directory
|
233
|
+
process.chdir(node_os_1.default.tmpdir());
|
234
|
+
await nodejs_registry_utils_1.Actions.install(new progressListener_1.ProgressListener(), refs, {});
|
235
|
+
await this.cleanupUnusedProviders();
|
236
|
+
}
|
237
|
+
catch (e) {
|
238
|
+
console.error(`Failed to update assets: ${refs.join(',')}`, e);
|
239
|
+
throw e;
|
240
|
+
}
|
241
|
+
cacheManager_1.cacheManager.flush();
|
242
|
+
definitionsManager_1.definitionsManager.clearCache();
|
243
|
+
};
|
244
|
+
return taskManager_1.taskManager.add(`asset:update`, updateAll, {
|
245
|
+
name: `Installing ${refs.length} updates`,
|
246
|
+
group: 'asset:update:check',
|
247
|
+
});
|
248
|
+
}
|
194
249
|
async maybeGenerateCode(ref, ymlPath, block) {
|
195
250
|
ref = (0, nodejs_utils_1.normalizeKapetaUri)(ref);
|
196
251
|
if (await codeGeneratorManager_1.codeGeneratorManager.canGenerateCode(block)) {
|
@@ -11,6 +11,7 @@ declare class DefinitionsManager {
|
|
11
11
|
exists(ref: string): Promise<boolean>;
|
12
12
|
getProviderDefinitions(): Promise<DefinitionInfo[]>;
|
13
13
|
getDefinition(ref: string): Promise<DefinitionInfo | undefined>;
|
14
|
+
getLatestDefinition(name: string): Promise<DefinitionInfo | undefined>;
|
14
15
|
getVersions(assetName: string): Promise<DefinitionInfo[]>;
|
15
16
|
clearCache(): void;
|
16
17
|
}
|
@@ -136,6 +136,19 @@ class DefinitionsManager {
|
|
136
136
|
return (0, nodejs_utils_1.parseKapetaUri)(`${d.definition.metadata.name}:${d.version}`).id === uri.id;
|
137
137
|
});
|
138
138
|
}
|
139
|
+
async getLatestDefinition(name) {
|
140
|
+
const definitions = await this.getDefinitions();
|
141
|
+
const allVersions = definitions.filter((d) => {
|
142
|
+
return d.version !== 'local' && d.definition.metadata.name === name;
|
143
|
+
});
|
144
|
+
if (allVersions.length === 0) {
|
145
|
+
return;
|
146
|
+
}
|
147
|
+
allVersions.sort((a, b) => {
|
148
|
+
return (0, nodejs_utils_1.parseVersion)(a.version).compareTo((0, nodejs_utils_1.parseVersion)(b.version)) * -1;
|
149
|
+
});
|
150
|
+
return allVersions[0];
|
151
|
+
}
|
139
152
|
async getVersions(assetName) {
|
140
153
|
const uri = (0, nodejs_utils_1.parseKapetaUri)(assetName);
|
141
154
|
const definitions = await this.getDefinitions();
|
@@ -19,6 +19,15 @@ declare class RepositoryManager extends EventEmitter {
|
|
19
19
|
setSourceOfChangeFor(file: string, source: SourceOfChange): Promise<void>;
|
20
20
|
clearSourceOfChangeFor(file: string): Promise<void>;
|
21
21
|
ensureDefaultProviders(): Promise<void>;
|
22
|
+
/**
|
23
|
+
* Will go through all available assets and get a list of
|
24
|
+
* providers that are not referenced anywhere.
|
25
|
+
*
|
26
|
+
* It will also make sure to not include the latest version of an asset.
|
27
|
+
*
|
28
|
+
*/
|
29
|
+
getUnusedProviders(): Promise<string[]>;
|
30
|
+
getUpdatableAssets(allNames: string[]): Promise<string[]>;
|
22
31
|
private scheduleInstallation;
|
23
32
|
ensureAsset(handle: string, name: string, version: string, wait?: boolean): Promise<undefined | Task[]>;
|
24
33
|
}
|
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.repositoryManager = void 0;
|
11
11
|
const node_os_1 = __importDefault(require("node:os"));
|
12
12
|
const socketManager_1 = require("./socketManager");
|
13
|
+
const schemas_1 = require("@kapeta/schemas");
|
13
14
|
const nodejs_registry_utils_1 = require("@kapeta/nodejs-registry-utils");
|
14
15
|
const definitionsManager_1 = require("./definitionsManager");
|
15
16
|
const taskManager_1 = require("./taskManager");
|
@@ -69,6 +70,97 @@ class RepositoryManager extends node_events_1.EventEmitter {
|
|
69
70
|
socketManager_1.socketManager.emitGlobal(EVENT_DEFAULT_PROVIDERS_END, {});
|
70
71
|
});
|
71
72
|
}
|
73
|
+
/**
|
74
|
+
* Will go through all available assets and get a list of
|
75
|
+
* providers that are not referenced anywhere.
|
76
|
+
*
|
77
|
+
* It will also make sure to not include the latest version of an asset.
|
78
|
+
*
|
79
|
+
*/
|
80
|
+
async getUnusedProviders() {
|
81
|
+
const allDefinitions = await definitionsManager_1.definitionsManager.getDefinitions();
|
82
|
+
const blocks = [];
|
83
|
+
const plans = [];
|
84
|
+
const providerMap = new Map();
|
85
|
+
const providerVersions = {};
|
86
|
+
const unusedProviders = new Set();
|
87
|
+
allDefinitions.forEach((d) => {
|
88
|
+
if (d.definition.kind === 'core/plan') {
|
89
|
+
plans.push(d);
|
90
|
+
return;
|
91
|
+
}
|
92
|
+
if (d.definition.kind.startsWith('core/')) {
|
93
|
+
const ref = (0, nodejs_utils_1.normalizeKapetaUri)(`${d.definition.metadata.name}:${d.version}`);
|
94
|
+
providerMap.set(ref, d);
|
95
|
+
if (!providerVersions[d.definition.metadata.name]) {
|
96
|
+
providerVersions[d.definition.metadata.name] = new Set();
|
97
|
+
}
|
98
|
+
providerVersions[d.definition.metadata.name].add(d.version);
|
99
|
+
unusedProviders.add(ref);
|
100
|
+
return;
|
101
|
+
}
|
102
|
+
blocks.push(d);
|
103
|
+
});
|
104
|
+
const latestVersions = {};
|
105
|
+
Object.entries(providerVersions).forEach(([name, versions]) => {
|
106
|
+
const versionArray = Array.from(versions);
|
107
|
+
versionArray.sort((a, b) => {
|
108
|
+
return (0, nodejs_utils_1.parseVersion)(a).compareTo((0, nodejs_utils_1.parseVersion)(b)) * -1;
|
109
|
+
});
|
110
|
+
latestVersions[name] = versionArray[0];
|
111
|
+
});
|
112
|
+
function markDependencyAsUsed(dep) {
|
113
|
+
const uri = (0, nodejs_utils_1.parseKapetaUri)(dep.name);
|
114
|
+
const ref = uri.toNormalizedString();
|
115
|
+
if (unusedProviders.has(ref)) {
|
116
|
+
unusedProviders.delete(ref);
|
117
|
+
}
|
118
|
+
}
|
119
|
+
plans.forEach((plan) => {
|
120
|
+
const dependencies = (0, schemas_1.resolveDependencies)(plan.definition);
|
121
|
+
dependencies.forEach(markDependencyAsUsed);
|
122
|
+
});
|
123
|
+
blocks.forEach((block) => {
|
124
|
+
const blockTypeKind = (0, nodejs_utils_1.normalizeKapetaUri)(block.definition.kind);
|
125
|
+
unusedProviders.delete(blockTypeKind);
|
126
|
+
const blockTypeProvider = providerMap.get(blockTypeKind);
|
127
|
+
if (!blockTypeProvider) {
|
128
|
+
console.warn('No provider found for block type', block.definition.kind);
|
129
|
+
return;
|
130
|
+
}
|
131
|
+
const dependencies = (0, schemas_1.resolveDependencies)(block.definition, blockTypeProvider.definition);
|
132
|
+
dependencies.forEach(markDependencyAsUsed);
|
133
|
+
});
|
134
|
+
return Array.from(unusedProviders).filter((ref) => {
|
135
|
+
const uri = (0, nodejs_utils_1.parseKapetaUri)(ref);
|
136
|
+
if (uri.version == 'local') {
|
137
|
+
// Don't delete local assets
|
138
|
+
return false;
|
139
|
+
}
|
140
|
+
// Don't delete the latest version of an asset
|
141
|
+
return latestVersions[uri.fullName] !== uri.version;
|
142
|
+
});
|
143
|
+
}
|
144
|
+
async getUpdatableAssets(allNames) {
|
145
|
+
const names = Array.from(new Set(allNames));
|
146
|
+
const currentVersions = await Promise.all(names.map((name) => definitionsManager_1.definitionsManager.getLatestDefinition(name).catch(() => undefined)));
|
147
|
+
const latestVersions = await Promise.all(names.map((name) => this._registryService.getLatestVersion(name).catch(() => undefined)));
|
148
|
+
return names
|
149
|
+
.map((name, index) => {
|
150
|
+
const currentVersion = currentVersions[index];
|
151
|
+
const latestVersion = latestVersions[index];
|
152
|
+
if (!currentVersion || !latestVersion) {
|
153
|
+
// Shouldn't happen unless the registry is down or an asset was deleted
|
154
|
+
return undefined;
|
155
|
+
}
|
156
|
+
const ref = (0, nodejs_utils_1.normalizeKapetaUri)(`${name}:${latestVersion.version}`);
|
157
|
+
if (currentVersion.version === latestVersion.version) {
|
158
|
+
return undefined;
|
159
|
+
}
|
160
|
+
return ref;
|
161
|
+
})
|
162
|
+
.filter((ref) => !!ref);
|
163
|
+
}
|
72
164
|
async scheduleInstallation(refs) {
|
73
165
|
//We make sure to only install one asset at a time - otherwise unexpected things might happen
|
74
166
|
const createInstaller = (ref) => {
|
package/index.ts
CHANGED
@@ -32,6 +32,7 @@ import { defaultProviderInstaller } from './src/utils/DefaultProviderInstaller';
|
|
32
32
|
import { authManager } from './src/authManager';
|
33
33
|
import { codeGeneratorManager } from './src/codeGeneratorManager';
|
34
34
|
import * as Sentry from '@sentry/node';
|
35
|
+
import { assetManager } from './src/assetManager';
|
35
36
|
|
36
37
|
Sentry.init({
|
37
38
|
dsn: 'https://0b7cc946d82c591473d6f95fff5e210b@o4505820837249024.ingest.sentry.io/4506212692000768',
|
@@ -245,6 +246,8 @@ export default {
|
|
245
246
|
console.error('Failed to install default providers.', e);
|
246
247
|
}
|
247
248
|
|
249
|
+
assetManager.startUpgradeInterval();
|
250
|
+
|
248
251
|
resolve({ host, port, dockerStatus: containerManager.isAlive() });
|
249
252
|
});
|
250
253
|
currentServer.host = host;
|
package/package.json
CHANGED
package/src/api.ts
CHANGED
@@ -6,18 +6,17 @@
|
|
6
6
|
import Router from 'express-promise-router';
|
7
7
|
import { corsHandler } from './middleware/cors';
|
8
8
|
import { KapetaAPI } from '@kapeta/nodejs-api-client';
|
9
|
-
import
|
9
|
+
import { Config } from '@kapeta/nodejs-registry-utils';
|
10
10
|
const { createAPIRoute } = require('@kapeta/web-microfrontend/server');
|
11
11
|
const packageJson = require('../package.json');
|
12
12
|
|
13
13
|
const router = Router();
|
14
14
|
|
15
|
-
const remoteServices = ClusterConfiguration.getClusterConfig().remoteServices ?? {};
|
16
15
|
router.use('/', corsHandler);
|
17
16
|
|
18
17
|
router.use(
|
19
18
|
'/registry',
|
20
|
-
createAPIRoute(
|
19
|
+
createAPIRoute(Config.data?.registry?.url ?? 'https://registry.kapeta.com', {
|
21
20
|
nonce: false,
|
22
21
|
userAgent: `KapetaDesktopCluster/${packageJson.version}`,
|
23
22
|
tokenFetcher: () => {
|
package/src/assetManager.ts
CHANGED
@@ -18,8 +18,10 @@ import { taskManager } from './taskManager';
|
|
18
18
|
import { SourceOfChange } from './types';
|
19
19
|
import { cacheManager } from './cacheManager';
|
20
20
|
import uuid from 'node-uuid';
|
21
|
+
import os from 'node:os';
|
21
22
|
|
22
23
|
const CACHE_TTL = 60 * 60 * 1000; // 1 hour
|
24
|
+
const UPGRADE_CHECK_INTERVAL = 10 * 60 * 1000; // 10 minutes
|
23
25
|
|
24
26
|
const toKey = (ref: string) => `assetManager:asset:${ref}`;
|
25
27
|
|
@@ -64,6 +66,22 @@ function parseRef(ref: string) {
|
|
64
66
|
}
|
65
67
|
|
66
68
|
class AssetManager {
|
69
|
+
public startUpgradeInterval() {
|
70
|
+
console.debug('Checking for upgrades...');
|
71
|
+
this.upgradeAllProviders()
|
72
|
+
.then((task) => {
|
73
|
+
return task && task.wait();
|
74
|
+
})
|
75
|
+
.catch((e) => {
|
76
|
+
console.error('Failed to upgrade providers', e);
|
77
|
+
})
|
78
|
+
.finally(() => {
|
79
|
+
setTimeout(() => {
|
80
|
+
this.startUpgradeInterval();
|
81
|
+
}, UPGRADE_CHECK_INTERVAL);
|
82
|
+
});
|
83
|
+
}
|
84
|
+
|
67
85
|
/**
|
68
86
|
*
|
69
87
|
* @param {string[]} [assetKinds]
|
@@ -258,6 +276,52 @@ class AssetManager {
|
|
258
276
|
return await repositoryManager.ensureAsset(uri.handle, uri.name, uri.version, wait);
|
259
277
|
}
|
260
278
|
|
279
|
+
private async cleanupUnusedProviders(): Promise<void> {
|
280
|
+
const unusedProviders = await repositoryManager.getUnusedProviders();
|
281
|
+
if (unusedProviders.length < 1) {
|
282
|
+
return;
|
283
|
+
}
|
284
|
+
|
285
|
+
console.log('Cleaning up unused providers: ', unusedProviders);
|
286
|
+
await Promise.all(
|
287
|
+
unusedProviders.map((ref) => {
|
288
|
+
return this.unregisterAsset(ref);
|
289
|
+
})
|
290
|
+
);
|
291
|
+
}
|
292
|
+
|
293
|
+
private async upgradeAllProviders() {
|
294
|
+
const providers = await definitionsManager.getProviderDefinitions();
|
295
|
+
const names = providers.map((p) => p.definition.metadata.name);
|
296
|
+
|
297
|
+
const refs = await repositoryManager.getUpdatableAssets(names);
|
298
|
+
|
299
|
+
if (refs.length < 1) {
|
300
|
+
await this.cleanupUnusedProviders();
|
301
|
+
return;
|
302
|
+
}
|
303
|
+
|
304
|
+
console.log('Installing updates', refs);
|
305
|
+
const updateAll = async () => {
|
306
|
+
try {
|
307
|
+
//We change to a temp dir to avoid issues with the current working directory
|
308
|
+
process.chdir(os.tmpdir());
|
309
|
+
await Actions.install(new ProgressListener(), refs, {});
|
310
|
+
await this.cleanupUnusedProviders();
|
311
|
+
} catch (e) {
|
312
|
+
console.error(`Failed to update assets: ${refs.join(',')}`, e);
|
313
|
+
throw e;
|
314
|
+
}
|
315
|
+
cacheManager.flush();
|
316
|
+
definitionsManager.clearCache();
|
317
|
+
};
|
318
|
+
|
319
|
+
return taskManager.add(`asset:update`, updateAll, {
|
320
|
+
name: `Installing ${refs.length} updates`,
|
321
|
+
group: 'asset:update:check',
|
322
|
+
});
|
323
|
+
}
|
324
|
+
|
261
325
|
private async maybeGenerateCode(ref: string, ymlPath: string, block: Definition) {
|
262
326
|
ref = normalizeKapetaUri(ref);
|
263
327
|
if (await codeGeneratorManager.canGenerateCode(block)) {
|
@@ -4,7 +4,7 @@
|
|
4
4
|
*/
|
5
5
|
|
6
6
|
import ClusterConfiguration, { DefinitionInfo } from '@kapeta/local-cluster-config';
|
7
|
-
import { parseKapetaUri, normalizeKapetaUri } from '@kapeta/nodejs-utils';
|
7
|
+
import { parseKapetaUri, normalizeKapetaUri, parseVersion } from '@kapeta/nodejs-utils';
|
8
8
|
import { cacheManager, doCached } from './cacheManager';
|
9
9
|
import { KapetaAPI } from '@kapeta/nodejs-api-client';
|
10
10
|
import { Plan } from '@kapeta/schemas';
|
@@ -170,6 +170,23 @@ class DefinitionsManager {
|
|
170
170
|
});
|
171
171
|
}
|
172
172
|
|
173
|
+
public async getLatestDefinition(name: string) {
|
174
|
+
const definitions = await this.getDefinitions();
|
175
|
+
const allVersions = definitions.filter((d) => {
|
176
|
+
return d.version !== 'local' && d.definition.metadata.name === name;
|
177
|
+
});
|
178
|
+
|
179
|
+
if (allVersions.length === 0) {
|
180
|
+
return;
|
181
|
+
}
|
182
|
+
|
183
|
+
allVersions.sort((a, b) => {
|
184
|
+
return parseVersion(a.version).compareTo(parseVersion(b.version)) * -1;
|
185
|
+
});
|
186
|
+
|
187
|
+
return allVersions[0];
|
188
|
+
}
|
189
|
+
|
173
190
|
public async getVersions(assetName: string) {
|
174
191
|
const uri = parseKapetaUri(assetName);
|
175
192
|
const definitions = await this.getDefinitions();
|
package/src/repositoryManager.ts
CHANGED
@@ -5,16 +5,17 @@
|
|
5
5
|
|
6
6
|
import os from 'node:os';
|
7
7
|
import { socketManager } from './socketManager';
|
8
|
-
import { Dependency } from '@kapeta/schemas';
|
9
|
-
import { Actions, Config, RegistryService } from '@kapeta/nodejs-registry-utils';
|
8
|
+
import { DependencyReference, Dependency, resolveDependencies } from '@kapeta/schemas';
|
9
|
+
import { Actions, AssetVersion, Config, RegistryService } from '@kapeta/nodejs-registry-utils';
|
10
10
|
import { definitionsManager } from './definitionsManager';
|
11
11
|
import { Task, taskManager } from './taskManager';
|
12
|
-
import { normalizeKapetaUri } from '@kapeta/nodejs-utils';
|
12
|
+
import { normalizeKapetaUri, parseKapetaUri, parseVersion } from '@kapeta/nodejs-utils';
|
13
13
|
import { ProgressListener } from './progressListener';
|
14
14
|
import { RepositoryWatcher } from './RepositoryWatcher';
|
15
15
|
import { SourceOfChange } from './types';
|
16
16
|
import { cacheManager } from './cacheManager';
|
17
17
|
import { EventEmitter } from 'node:events';
|
18
|
+
import { DefinitionInfo } from '@kapeta/local-cluster-config';
|
18
19
|
|
19
20
|
const EVENT_DEFAULT_PROVIDERS_START = 'default-providers-start';
|
20
21
|
const EVENT_DEFAULT_PROVIDERS_END = 'default-providers-end';
|
@@ -77,6 +78,116 @@ class RepositoryManager extends EventEmitter {
|
|
77
78
|
});
|
78
79
|
}
|
79
80
|
|
81
|
+
/**
|
82
|
+
* Will go through all available assets and get a list of
|
83
|
+
* providers that are not referenced anywhere.
|
84
|
+
*
|
85
|
+
* It will also make sure to not include the latest version of an asset.
|
86
|
+
*
|
87
|
+
*/
|
88
|
+
public async getUnusedProviders(): Promise<string[]> {
|
89
|
+
const allDefinitions: DefinitionInfo[] = await definitionsManager.getDefinitions();
|
90
|
+
const blocks: DefinitionInfo[] = [];
|
91
|
+
const plans: DefinitionInfo[] = [];
|
92
|
+
const providerMap = new Map<string, DefinitionInfo>();
|
93
|
+
const providerVersions: { [name: string]: Set<string> } = {};
|
94
|
+
const unusedProviders = new Set<string>();
|
95
|
+
allDefinitions.forEach((d) => {
|
96
|
+
if (d.definition.kind === 'core/plan') {
|
97
|
+
plans.push(d);
|
98
|
+
return;
|
99
|
+
}
|
100
|
+
|
101
|
+
if (d.definition.kind.startsWith('core/')) {
|
102
|
+
const ref = normalizeKapetaUri(`${d.definition.metadata.name}:${d.version}`);
|
103
|
+
providerMap.set(ref, d);
|
104
|
+
if (!providerVersions[d.definition.metadata.name]) {
|
105
|
+
providerVersions[d.definition.metadata.name] = new Set<string>();
|
106
|
+
}
|
107
|
+
providerVersions[d.definition.metadata.name].add(d.version);
|
108
|
+
unusedProviders.add(ref);
|
109
|
+
return;
|
110
|
+
}
|
111
|
+
blocks.push(d);
|
112
|
+
});
|
113
|
+
|
114
|
+
const latestVersions: { [name: string]: string } = {};
|
115
|
+
Object.entries(providerVersions).forEach(([name, versions]) => {
|
116
|
+
const versionArray = Array.from(versions);
|
117
|
+
versionArray.sort((a, b) => {
|
118
|
+
return parseVersion(a).compareTo(parseVersion(b)) * -1;
|
119
|
+
});
|
120
|
+
latestVersions[name] = versionArray[0];
|
121
|
+
});
|
122
|
+
|
123
|
+
function markDependencyAsUsed(dep: DependencyReference) {
|
124
|
+
const uri = parseKapetaUri(dep.name);
|
125
|
+
const ref = uri.toNormalizedString();
|
126
|
+
if (unusedProviders.has(ref)) {
|
127
|
+
unusedProviders.delete(ref);
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
plans.forEach((plan) => {
|
132
|
+
const dependencies = resolveDependencies(plan.definition);
|
133
|
+
dependencies.forEach(markDependencyAsUsed);
|
134
|
+
});
|
135
|
+
|
136
|
+
blocks.forEach((block) => {
|
137
|
+
const blockTypeKind = normalizeKapetaUri(block.definition.kind);
|
138
|
+
unusedProviders.delete(blockTypeKind);
|
139
|
+
const blockTypeProvider = providerMap.get(blockTypeKind);
|
140
|
+
if (!blockTypeProvider) {
|
141
|
+
console.warn('No provider found for block type', block.definition.kind);
|
142
|
+
return;
|
143
|
+
}
|
144
|
+
const dependencies = resolveDependencies(block.definition, blockTypeProvider.definition);
|
145
|
+
dependencies.forEach(markDependencyAsUsed);
|
146
|
+
});
|
147
|
+
|
148
|
+
return Array.from(unusedProviders).filter((ref) => {
|
149
|
+
const uri = parseKapetaUri(ref);
|
150
|
+
if (uri.version == 'local') {
|
151
|
+
// Don't delete local assets
|
152
|
+
return false;
|
153
|
+
}
|
154
|
+
|
155
|
+
// Don't delete the latest version of an asset
|
156
|
+
return latestVersions[uri.fullName] !== uri.version;
|
157
|
+
});
|
158
|
+
}
|
159
|
+
|
160
|
+
public async getUpdatableAssets(allNames: string[]): Promise<string[]> {
|
161
|
+
const names = Array.from(new Set<string>(allNames));
|
162
|
+
|
163
|
+
const currentVersions = await Promise.all(
|
164
|
+
names.map((name) => definitionsManager.getLatestDefinition(name).catch(() => undefined))
|
165
|
+
);
|
166
|
+
|
167
|
+
const latestVersions = await Promise.all(
|
168
|
+
names.map((name) => this._registryService.getLatestVersion(name).catch(() => undefined))
|
169
|
+
);
|
170
|
+
|
171
|
+
return names
|
172
|
+
.map((name, index) => {
|
173
|
+
const currentVersion: DefinitionInfo | undefined = currentVersions[index];
|
174
|
+
const latestVersion: AssetVersion | undefined = latestVersions[index];
|
175
|
+
if (!currentVersion || !latestVersion) {
|
176
|
+
// Shouldn't happen unless the registry is down or an asset was deleted
|
177
|
+
return undefined;
|
178
|
+
}
|
179
|
+
|
180
|
+
const ref = normalizeKapetaUri(`${name}:${latestVersion.version}`);
|
181
|
+
|
182
|
+
if (currentVersion.version === latestVersion.version) {
|
183
|
+
return undefined;
|
184
|
+
}
|
185
|
+
|
186
|
+
return ref;
|
187
|
+
})
|
188
|
+
.filter((ref) => !!ref) as string[];
|
189
|
+
}
|
190
|
+
|
80
191
|
private async scheduleInstallation(refs: string[]): Promise<Task[]> {
|
81
192
|
//We make sure to only install one asset at a time - otherwise unexpected things might happen
|
82
193
|
const createInstaller = (ref: string) => {
|