@uofx/cli 1.0.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/LICENSE +40 -0
- package/README.md +444 -0
- package/THIRD-PARTY-NOTICES.txt +894 -0
- package/dist/application/dtos/index.js +24 -0
- package/dist/application/dtos/request/delete-instance.request.dto.js +3 -0
- package/dist/application/dtos/request/get-config.request.dto.js +3 -0
- package/dist/application/dtos/request/get-credentials.request.dto.js +3 -0
- package/dist/application/dtos/request/index.js +27 -0
- package/dist/application/dtos/request/install-instance.request.dto.js +3 -0
- package/dist/application/dtos/request/list-charts.request.dto.js +3 -0
- package/dist/application/dtos/request/set-config.request.dto.js +16 -0
- package/dist/application/dtos/request/setup-environment.request.dto.js +16 -0
- package/dist/application/dtos/request/show-logs.request.dto.js +19 -0
- package/dist/application/dtos/request/start-instance.request.dto.js +3 -0
- package/dist/application/dtos/request/stop-instance.request.dto.js +3 -0
- package/dist/application/dtos/response/credentials.response.dto.js +3 -0
- package/dist/application/dtos/response/delete-instance.response.dto.js +3 -0
- package/dist/application/dtos/response/index.js +26 -0
- package/dist/application/dtos/response/install-instance.response.dto.js +3 -0
- package/dist/application/dtos/response/instance-list.response.dto.js +3 -0
- package/dist/application/dtos/response/instance-status.response.dto.js +3 -0
- package/dist/application/dtos/response/setup-result.response.dto.js +3 -0
- package/dist/application/dtos/response/show-logs.response.dto.js +3 -0
- package/dist/application/dtos/response/start-instance.response.dto.js +3 -0
- package/dist/application/dtos/response/stop-instance.response.dto.js +3 -0
- package/dist/application/index.js +25 -0
- package/dist/application/interfaces/index.js +24 -0
- package/dist/application/interfaces/use-case.interface.js +3 -0
- package/dist/application/use-cases/config/get-config.use-case.js +66 -0
- package/dist/application/use-cases/config/set-config.use-case.js +49 -0
- package/dist/application/use-cases/credentials/get-credentials.use-case.js +57 -0
- package/dist/application/use-cases/index.js +28 -0
- package/dist/application/use-cases/instance/delete-instance.use-case.js +81 -0
- package/dist/application/use-cases/instance/index.js +23 -0
- package/dist/application/use-cases/instance/install-instance.use-case.js +424 -0
- package/dist/application/use-cases/instance/list-charts.use-case.js +43 -0
- package/dist/application/use-cases/instance/list-instances.use-case.js +62 -0
- package/dist/application/use-cases/instance/start-instance.use-case.js +154 -0
- package/dist/application/use-cases/instance/stop-instance.use-case.js +55 -0
- package/dist/application/use-cases/logs/show-logs.use-case.js +66 -0
- package/dist/application/use-cases/setup/setup-environment.use-case.js +53 -0
- package/dist/cli.js +286 -0
- package/dist/constants/config-defaults.js +23 -0
- package/dist/constants/defaults.js +89 -0
- package/dist/constants/deployment.js +39 -0
- package/dist/constants/environments.js +93 -0
- package/dist/constants/index.js +53 -0
- package/dist/constants/oci-artifacts.js +25 -0
- package/dist/constants/paths.js +92 -0
- package/dist/constants/timeouts.js +60 -0
- package/dist/di/container.js +34 -0
- package/dist/di/index.js +22 -0
- package/dist/di/modules/application.module.js +54 -0
- package/dist/di/modules/infrastructure.module.js +206 -0
- package/dist/di/modules/interceptor.module.js +68 -0
- package/dist/di/modules/presentation.module.js +31 -0
- package/dist/di/tokens.js +149 -0
- package/dist/domain/decorators/sensitive.decorator.js +39 -0
- package/dist/domain/entities/credentials-resolver.entity.js +127 -0
- package/dist/domain/entities/credentials.entity.js +65 -0
- package/dist/domain/entities/delete-instance-validation.entity.js +100 -0
- package/dist/domain/entities/deployment-parameters.entity.js +120 -0
- package/dist/domain/entities/environment-validation.entity.js +125 -0
- package/dist/domain/entities/index.js +29 -0
- package/dist/domain/entities/instance-lifecycle-state.entity.js +100 -0
- package/dist/domain/entities/instance-list-aggregator.entity.js +104 -0
- package/dist/domain/entities/instance-metadata.entity.js +86 -0
- package/dist/domain/entities/instance-status.entity.js +79 -0
- package/dist/domain/entities/instance.entity.js +128 -0
- package/dist/domain/entities/log-filter.entity.js +141 -0
- package/dist/domain/index.js +29 -0
- package/dist/domain/interfaces/safe-loggable.interface.js +3 -0
- package/dist/domain/ports/app-config.port.js +3 -0
- package/dist/domain/ports/base-image.port.js +3 -0
- package/dist/domain/ports/chart-version.port.js +3 -0
- package/dist/domain/ports/correlation-id.port.js +3 -0
- package/dist/domain/ports/credentials.port.js +3 -0
- package/dist/domain/ports/deployment.port.js +3 -0
- package/dist/domain/ports/error-handler.port.js +3 -0
- package/dist/domain/ports/index.js +46 -0
- package/dist/domain/ports/instance-manager.port.js +3 -0
- package/dist/domain/ports/instance-metadata.port.js +8 -0
- package/dist/domain/ports/instance-storage.port.js +3 -0
- package/dist/domain/ports/k8s-deployer.port.js +3 -0
- package/dist/domain/ports/logger.port.js +14 -0
- package/dist/domain/ports/output.port.js +3 -0
- package/dist/domain/ports/runtime-environment.port.js +6 -0
- package/dist/domain/ports/user-interaction.port.js +9 -0
- package/dist/domain/ports/user-settings.port.js +3 -0
- package/dist/domain/types/index.js +22 -0
- package/dist/domain/types/logger.types.js +29 -0
- package/dist/domain/types/validation.types.js +9 -0
- package/dist/domain/value-objects/acr-credentials.value-object.js +92 -0
- package/dist/domain/value-objects/chart-version.value-object.js +124 -0
- package/dist/domain/value-objects/config-log-level.value-object.js +84 -0
- package/dist/domain/value-objects/connection-info.value-object.js +65 -0
- package/dist/domain/value-objects/index.js +25 -0
- package/dist/domain/value-objects/instance-name.value-object.js +91 -0
- package/dist/domain/value-objects/jwt-key.value-object.js +97 -0
- package/dist/domain/value-objects/mssql-password.value-object.js +140 -0
- package/dist/domain/value-objects/rsa-key-pair.value-object.js +181 -0
- package/dist/index.js +6 -0
- package/dist/infrastructure/config/app-config.interface.js +3 -0
- package/dist/infrastructure/config/app-config.service.js +280 -0
- package/dist/infrastructure/config/config-validator.js +31 -0
- package/dist/infrastructure/config/crypto.service.js +125 -0
- package/dist/infrastructure/deployment/deployment.adapter.js +118 -0
- package/dist/infrastructure/deployment/interfaces/acr-credential-manager.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/app-manager.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/helm-registry.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/infra-manager.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/k8s-job-runner.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/mssql-database-init.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/mssql-helm-deployment.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/mssql-storage.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/mssql-user-manager.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/oci-artifact.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/secret-manager.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/service-manager.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/version-compatibility.interface.js +3 -0
- package/dist/infrastructure/deployment/services/acr-credential-manager.service.js +144 -0
- package/dist/infrastructure/deployment/services/app-manager.service.js +193 -0
- package/dist/infrastructure/deployment/services/base-helm-deployment.service.js +163 -0
- package/dist/infrastructure/deployment/services/helm-registry.service.js +126 -0
- package/dist/infrastructure/deployment/services/infra-manager.service.js +130 -0
- package/dist/infrastructure/deployment/services/k8s-job-runner.service.js +194 -0
- package/dist/infrastructure/deployment/services/mssql-database-init.service.js +139 -0
- package/dist/infrastructure/deployment/services/mssql-helm-deployment.service.js +100 -0
- package/dist/infrastructure/deployment/services/mssql-storage.service.js +54 -0
- package/dist/infrastructure/deployment/services/mssql-user-manager.service.js +66 -0
- package/dist/infrastructure/deployment/services/oci-artifact.service.js +289 -0
- package/dist/infrastructure/deployment/services/secret-manager.service.js +179 -0
- package/dist/infrastructure/deployment/services/service-manager.service.js +82 -0
- package/dist/infrastructure/deployment/services/version-compatibility.service.js +291 -0
- package/dist/infrastructure/environment/interfaces/hardware-info.interface.js +3 -0
- package/dist/infrastructure/environment/interfaces/network-checker.interface.js +3 -0
- package/dist/infrastructure/environment/services/hardware-info.service.js +135 -0
- package/dist/infrastructure/environment/services/network-checker.service.js +142 -0
- package/dist/infrastructure/environment/windows-environment.adapter.js +162 -0
- package/dist/infrastructure/errors/app-error.js +73 -0
- package/dist/infrastructure/errors/error-handler.interface.js +3 -0
- package/dist/infrastructure/errors/error-handler.js +218 -0
- package/dist/infrastructure/errors/exit-codes.js +27 -0
- package/dist/infrastructure/errors/index.js +25 -0
- package/dist/infrastructure/execution/builders/base-command.builder.js +122 -0
- package/dist/infrastructure/execution/builders/host-command.builder.js +58 -0
- package/dist/infrastructure/execution/builders/windows-host-command.builder.js +50 -0
- package/dist/infrastructure/execution/builders/wsl-command.builder.js +29 -0
- package/dist/infrastructure/execution/command-builder.js +252 -0
- package/dist/infrastructure/execution/command-executor.service.js +230 -0
- package/dist/infrastructure/execution/environments/wsl-execution.environment.js +70 -0
- package/dist/infrastructure/execution/execution-environment.factory.js +53 -0
- package/dist/infrastructure/execution/index.js +25 -0
- package/dist/infrastructure/execution/interfaces/command-builder.interface.js +3 -0
- package/dist/infrastructure/execution/interfaces/command-executor.interface.js +3 -0
- package/dist/infrastructure/execution/interfaces/execution-environment-factory.interface.js +3 -0
- package/dist/infrastructure/execution/interfaces/execution-environment.interface.js +7 -0
- package/dist/infrastructure/execution/interfaces/host-command-builder.interface.js +3 -0
- package/dist/infrastructure/execution/interfaces/index.js +23 -0
- package/dist/infrastructure/execution/interfaces/script-executor.interface.js +3 -0
- package/dist/infrastructure/execution/script-executor.service.js +171 -0
- package/dist/infrastructure/http/http-client.service.js +176 -0
- package/dist/infrastructure/http/index.js +18 -0
- package/dist/infrastructure/http/interfaces/http-client.interface.js +3 -0
- package/dist/infrastructure/interceptors/index.js +8 -0
- package/dist/infrastructure/interceptors/interceptor.factory.js +44 -0
- package/dist/infrastructure/interceptors/interceptor.interface.js +3 -0
- package/dist/infrastructure/interceptors/logging.interceptor.js +171 -0
- package/dist/infrastructure/logger/correlation-id.adapter.js +68 -0
- package/dist/infrastructure/logger/index.js +23 -0
- package/dist/infrastructure/logger/interfaces/index.js +22 -0
- package/dist/infrastructure/logger/interfaces/log-reader.repository.interface.js +7 -0
- package/dist/infrastructure/logger/interfaces/log-writer.repository.interface.js +7 -0
- package/dist/infrastructure/logger/logger.adapter.js +274 -0
- package/dist/infrastructure/logger/services/file-log-reader.repository.js +148 -0
- package/dist/infrastructure/logger/services/file-log-writer.repository.js +307 -0
- package/dist/infrastructure/logger/services/index.js +22 -0
- package/dist/infrastructure/persistence/index.js +25 -0
- package/dist/infrastructure/persistence/instance-metadata.adapter.js +100 -0
- package/dist/infrastructure/persistence/instance-storage.adapter.js +64 -0
- package/dist/infrastructure/persistence/interfaces/config.repository.interface.js +3 -0
- package/dist/infrastructure/persistence/interfaces/index.js +22 -0
- package/dist/infrastructure/persistence/interfaces/instance.repository.interface.js +3 -0
- package/dist/infrastructure/persistence/services/file-system-config.repository.js +168 -0
- package/dist/infrastructure/persistence/services/file-system-instance.repository.js +170 -0
- package/dist/infrastructure/persistence/services/index.js +22 -0
- package/dist/infrastructure/persistence/user-settings.adapter.js +55 -0
- package/dist/infrastructure/platform-detector.js +71 -0
- package/dist/infrastructure/platforms/windows/interfaces/microk8s.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/rootfs-manager.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/windows-features.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/windows-info.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-config.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-info.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-instance-inspection.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-instance-lifecycle.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-instance-naming.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-manager.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-resources.interface.js +8 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-updater.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wslconfig-parser.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/parsers/wsl-version.parser.js +133 -0
- package/dist/infrastructure/platforms/windows/services/microk8s.service.js +168 -0
- package/dist/infrastructure/platforms/windows/services/rootfs-manager.service.js +336 -0
- package/dist/infrastructure/platforms/windows/services/windows-features.service.js +191 -0
- package/dist/infrastructure/platforms/windows/services/windows-info.service.js +138 -0
- package/dist/infrastructure/platforms/windows/services/wsl-config.service.js +171 -0
- package/dist/infrastructure/platforms/windows/services/wsl-info.service.js +226 -0
- package/dist/infrastructure/platforms/windows/services/wsl-instance-inspection.service.js +325 -0
- package/dist/infrastructure/platforms/windows/services/wsl-instance-lifecycle.service.js +442 -0
- package/dist/infrastructure/platforms/windows/services/wsl-instance-naming.service.js +93 -0
- package/dist/infrastructure/platforms/windows/services/wsl-updater.service.js +273 -0
- package/dist/infrastructure/platforms/windows/services/wslconfig-parser.service.js +222 -0
- package/dist/infrastructure/platforms/windows/wsl-base-image.adapter.js +41 -0
- package/dist/infrastructure/platforms/windows/wsl-instance-manager.adapter.js +150 -0
- package/dist/infrastructure/utils/error-formatter.util.js +29 -0
- package/dist/infrastructure/utils/file-operations.util.js +201 -0
- package/dist/infrastructure/utils/input-validator.util.js +152 -0
- package/dist/infrastructure/utils/retry.util.js +98 -0
- package/dist/presentation/controllers/config.controller.js +146 -0
- package/dist/presentation/controllers/credentials.controller.js +105 -0
- package/dist/presentation/controllers/index.js +25 -0
- package/dist/presentation/controllers/instance.controller.js +363 -0
- package/dist/presentation/controllers/logs.controller.js +103 -0
- package/dist/presentation/controllers/setup.controller.js +175 -0
- package/dist/presentation/interfaces/cli-options.interface.js +8 -0
- package/dist/presentation/prompts/acr-credentials.prompt.js +76 -0
- package/dist/presentation/prompts/index.js +21 -0
- package/dist/presentation/ui/cli-progress.service.js +193 -0
- package/dist/presentation/ui/constants/output-symbols.js +42 -0
- package/dist/presentation/ui/index.js +27 -0
- package/dist/presentation/ui/interaction.service.js +276 -0
- package/dist/presentation/ui/interfaces/cli-progress.interface.js +9 -0
- package/dist/presentation/ui/interfaces/output-formatter.interface.js +23 -0
- package/dist/presentation/ui/log-level.enum.js +66 -0
- package/dist/presentation/ui/output-builder.service.js +378 -0
- package/dist/presentation/ui/output-formatter.service.js +393 -0
- package/package.json +65 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.SecretManagerService = void 0;
|
|
16
|
+
const tsyringe_1 = require("tsyringe");
|
|
17
|
+
const tokens_1 = require("../../../di/tokens");
|
|
18
|
+
const sensitive_decorator_1 = require("../../../domain/decorators/sensitive.decorator");
|
|
19
|
+
/**
|
|
20
|
+
* Secret 管理服務
|
|
21
|
+
*
|
|
22
|
+
* 管理 Kubernetes Secret 的建立與讀取
|
|
23
|
+
* 透過 DI 注入 CommandExecutorService,所有操作需傳入 instanceName 指定目標 WSL 實例
|
|
24
|
+
*
|
|
25
|
+
* 實作 ISecretManagerService
|
|
26
|
+
*/
|
|
27
|
+
let SecretManagerService = class SecretManagerService {
|
|
28
|
+
constructor(envFactory, logger) {
|
|
29
|
+
this.envFactory = envFactory;
|
|
30
|
+
this.logger = logger;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 檢查命名空間是否存在
|
|
34
|
+
*/
|
|
35
|
+
async checkNamespaceExists(instanceName, namespace) {
|
|
36
|
+
try {
|
|
37
|
+
const env = this.envFactory.getForInstance(instanceName);
|
|
38
|
+
const builder = env.kubectl('get namespace')
|
|
39
|
+
.arg(namespace);
|
|
40
|
+
const res = await builder.exec();
|
|
41
|
+
return res.exitCode === 0;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 建立命名空間
|
|
49
|
+
*/
|
|
50
|
+
async createNamespace(instanceName, namespace) {
|
|
51
|
+
const env = this.envFactory.getForInstance(instanceName);
|
|
52
|
+
const builder = env.kubectl('create namespace')
|
|
53
|
+
.arg(namespace);
|
|
54
|
+
const result = await builder.exec();
|
|
55
|
+
if (result.exitCode !== 0) {
|
|
56
|
+
throw new Error(`Failed to create namespace: ${result.stderr}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 建立全域設定 Secret
|
|
61
|
+
* @param instanceName 實例名稱
|
|
62
|
+
* @param saPassword SA 密碼
|
|
63
|
+
* @param adminPassword 管理員密碼
|
|
64
|
+
* @param rsaKeys RSA 金鑰組
|
|
65
|
+
* @param jwtKey JWT 金鑰
|
|
66
|
+
* @param progress 進度通知回調
|
|
67
|
+
*/
|
|
68
|
+
async createGlobalConfigSecret(instanceName, saPassword, adminPassword, rsaKeys, jwtKey, output) {
|
|
69
|
+
const secretName = 'uofx-install-config';
|
|
70
|
+
const namespace = 'uofx-system';
|
|
71
|
+
// 確保命名空間存在
|
|
72
|
+
if (!(await this.checkNamespaceExists(instanceName, namespace))) {
|
|
73
|
+
this.logger.debug(`[Secret] Creating namespace ${namespace}...`);
|
|
74
|
+
await this.createNamespace(instanceName, namespace);
|
|
75
|
+
}
|
|
76
|
+
// 使用 stringData 建立 Secret (kubectl 會處理 base64 編碼)
|
|
77
|
+
this.logger.debug(`[Secret] Creating global config secret...`);
|
|
78
|
+
const secretManifest = {
|
|
79
|
+
apiVersion: 'v1',
|
|
80
|
+
kind: 'Secret',
|
|
81
|
+
metadata: {
|
|
82
|
+
name: secretName,
|
|
83
|
+
namespace: namespace,
|
|
84
|
+
},
|
|
85
|
+
type: 'Opaque',
|
|
86
|
+
stringData: {
|
|
87
|
+
'sa-password': saPassword,
|
|
88
|
+
'admin-password': adminPassword,
|
|
89
|
+
'rsa-signin-private': rsaKeys.signInRsa.privateKey,
|
|
90
|
+
'rsa-signin-public': rsaKeys.signInRsa.publicKey,
|
|
91
|
+
'rsa-uofx-private': rsaKeys.uofxRsa.privateKey,
|
|
92
|
+
'rsa-uofx-public': rsaKeys.uofxRsa.publicKey,
|
|
93
|
+
'jwt-signing-key': jwtKey,
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
// 使用 kubectl apply -f - 從 stdin 輸入
|
|
97
|
+
const env = this.envFactory.getForInstance(instanceName);
|
|
98
|
+
const builder = env.kubectl('apply')
|
|
99
|
+
.arg('-f', '-')
|
|
100
|
+
.sensitiveStdin(JSON.stringify(secretManifest));
|
|
101
|
+
const result = await builder.exec();
|
|
102
|
+
if (result.exitCode !== 0) {
|
|
103
|
+
throw new Error(`Failed to create global config secret: ${result.stderr}`);
|
|
104
|
+
}
|
|
105
|
+
output?.success(`Global config secret created in ${namespace}`).flush();
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 取得全域設定 Secret
|
|
109
|
+
* @param instanceName 實例名稱
|
|
110
|
+
* @returns 全域設定物件,若不存在則回傳 null
|
|
111
|
+
*/
|
|
112
|
+
async getGlobalConfigSecret(instanceName) {
|
|
113
|
+
const secretName = 'uofx-install-config';
|
|
114
|
+
const namespace = 'uofx-system';
|
|
115
|
+
try {
|
|
116
|
+
const env = this.envFactory.getForInstance(instanceName);
|
|
117
|
+
const builder = env.kubectl('get secret')
|
|
118
|
+
.arg(secretName)
|
|
119
|
+
.arg('-n', namespace)
|
|
120
|
+
.arg('-o', 'json');
|
|
121
|
+
const result = await builder.exec();
|
|
122
|
+
if (result.exitCode !== 0) {
|
|
123
|
+
this.logger.error(new Error(`kubectl exited with code ${result.exitCode}`));
|
|
124
|
+
this.logger.error(new Error(`Stderr: ${result.stderr}`));
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
const secret = JSON.parse(result.stdout);
|
|
128
|
+
const data = secret.data;
|
|
129
|
+
// 驗證必要欄位
|
|
130
|
+
if (!data['sa-password']) {
|
|
131
|
+
this.logger.error(new Error('sa-password not found in secret data'));
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
if (!data['admin-password']) {
|
|
135
|
+
this.logger.error(new Error('admin-password not found in secret data'));
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
instanceName,
|
|
140
|
+
saPassword: Buffer.from(data['sa-password'], 'base64').toString('utf-8'),
|
|
141
|
+
adminPassword: Buffer.from(data['admin-password'], 'base64').toString('utf-8'),
|
|
142
|
+
signInRsaPrivateKey: Buffer.from(data['rsa-signin-private'], 'base64').toString('utf-8'),
|
|
143
|
+
signInRsaPublicKey: Buffer.from(data['rsa-signin-public'], 'base64').toString('utf-8'),
|
|
144
|
+
uofxRsaPrivateKey: Buffer.from(data['rsa-uofx-private'], 'base64').toString('utf-8'),
|
|
145
|
+
uofxRsaPublicKey: Buffer.from(data['rsa-uofx-public'], 'base64').toString('utf-8'),
|
|
146
|
+
jwtSigningKey: Buffer.from(data['jwt-signing-key'], 'base64').toString('utf-8'),
|
|
147
|
+
connectionStringUofxDb: Buffer.from(data['connection-string-uofxdb'] || '', 'base64').toString('utf-8'),
|
|
148
|
+
connectionStringUofxSearchDb: Buffer.from(data['connection-string-uofxsearchdb'] || '', 'base64').toString('utf-8')
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
this.logger.error(error, { context: 'Error reading global config secret' });
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
exports.SecretManagerService = SecretManagerService;
|
|
158
|
+
__decorate([
|
|
159
|
+
__param(1, (0, sensitive_decorator_1.Sensitive)()),
|
|
160
|
+
__param(2, (0, sensitive_decorator_1.Sensitive)()),
|
|
161
|
+
__param(3, (0, sensitive_decorator_1.Sensitive)()),
|
|
162
|
+
__param(4, (0, sensitive_decorator_1.Sensitive)()),
|
|
163
|
+
__metadata("design:type", Function),
|
|
164
|
+
__metadata("design:paramtypes", [String, String, String, Object, String, Object]),
|
|
165
|
+
__metadata("design:returntype", Promise)
|
|
166
|
+
], SecretManagerService.prototype, "createGlobalConfigSecret", null);
|
|
167
|
+
__decorate([
|
|
168
|
+
(0, sensitive_decorator_1.SensitiveReturn)(),
|
|
169
|
+
__metadata("design:type", Function),
|
|
170
|
+
__metadata("design:paramtypes", [String]),
|
|
171
|
+
__metadata("design:returntype", Promise)
|
|
172
|
+
], SecretManagerService.prototype, "getGlobalConfigSecret", null);
|
|
173
|
+
exports.SecretManagerService = SecretManagerService = __decorate([
|
|
174
|
+
(0, tsyringe_1.injectable)(),
|
|
175
|
+
__param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IExecutionEnvironmentFactory)),
|
|
176
|
+
__param(1, (0, tsyringe_1.inject)(tokens_1.TOKENS.ILoggerPort)),
|
|
177
|
+
__metadata("design:paramtypes", [Object, Object])
|
|
178
|
+
], SecretManagerService);
|
|
179
|
+
//# sourceMappingURL=secret-manager.service.js.map
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.ServiceManagerService = void 0;
|
|
16
|
+
const tsyringe_1 = require("tsyringe");
|
|
17
|
+
const tokens_1 = require("../../../di/tokens");
|
|
18
|
+
const deployment_parameters_entity_1 = require("../../../domain/entities/deployment-parameters.entity");
|
|
19
|
+
const sensitive_decorator_1 = require("../../../domain/decorators/sensitive.decorator");
|
|
20
|
+
const base_helm_deployment_service_1 = require("./base-helm-deployment.service");
|
|
21
|
+
/**
|
|
22
|
+
* Service Manager Service
|
|
23
|
+
*
|
|
24
|
+
* 負責 uofx-service Helm chart 的部署管理
|
|
25
|
+
* 繼承 BaseHelmDeploymentService 使用模板方法模式
|
|
26
|
+
*/
|
|
27
|
+
let ServiceManagerService = class ServiceManagerService extends base_helm_deployment_service_1.BaseHelmDeploymentService {
|
|
28
|
+
constructor(envFactory, helmRegistry, logger) {
|
|
29
|
+
super(helmRegistry, logger, envFactory);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 部署 uofx-service 服務定義
|
|
33
|
+
*/
|
|
34
|
+
async deployService(instanceName, params, chartVersion, output) {
|
|
35
|
+
output?.item('arrow', 'Deploying uofx-service chart...').flush();
|
|
36
|
+
await this.deployWithHelm(instanceName, params, chartVersion, output);
|
|
37
|
+
}
|
|
38
|
+
// =========================================================================
|
|
39
|
+
// BaseHelmDeploymentService 抽象方法實作
|
|
40
|
+
// =========================================================================
|
|
41
|
+
getServiceName() {
|
|
42
|
+
return 'Service';
|
|
43
|
+
}
|
|
44
|
+
getDeploymentConfig(chartVersion) {
|
|
45
|
+
return {
|
|
46
|
+
chartName: 'uofx-service',
|
|
47
|
+
chartVersion,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
async installChart(instanceName, chartPath, _params, output) {
|
|
51
|
+
const builder = this.createHelmUpgradeBuilder(instanceName, {
|
|
52
|
+
releaseName: 'uofx-service',
|
|
53
|
+
chartPath,
|
|
54
|
+
wait: true,
|
|
55
|
+
timeout: '10m',
|
|
56
|
+
setArgs: ['podspec.selector.deploy=blue'],
|
|
57
|
+
});
|
|
58
|
+
this.logger.debug('[Service] Deploying service definition chart', {
|
|
59
|
+
chart: 'uofx-service',
|
|
60
|
+
chartPath: chartPath,
|
|
61
|
+
namespace: 'uofx',
|
|
62
|
+
instance: instanceName,
|
|
63
|
+
});
|
|
64
|
+
output?.indent().item('arrow', 'Installing uofx-service chart...').outdent().flush();
|
|
65
|
+
await this.executeWithRetry(builder, 'uofx-service', output);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
exports.ServiceManagerService = ServiceManagerService;
|
|
69
|
+
__decorate([
|
|
70
|
+
__param(1, (0, sensitive_decorator_1.Sensitive)()),
|
|
71
|
+
__metadata("design:type", Function),
|
|
72
|
+
__metadata("design:paramtypes", [String, deployment_parameters_entity_1.DeploymentParameters, String, Object]),
|
|
73
|
+
__metadata("design:returntype", Promise)
|
|
74
|
+
], ServiceManagerService.prototype, "deployService", null);
|
|
75
|
+
exports.ServiceManagerService = ServiceManagerService = __decorate([
|
|
76
|
+
(0, tsyringe_1.injectable)(),
|
|
77
|
+
__param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IExecutionEnvironmentFactory)),
|
|
78
|
+
__param(1, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IHelmRegistry)),
|
|
79
|
+
__param(2, (0, tsyringe_1.inject)(tokens_1.TOKENS.ILoggerPort)),
|
|
80
|
+
__metadata("design:paramtypes", [Object, Object, Object])
|
|
81
|
+
], ServiceManagerService);
|
|
82
|
+
//# sourceMappingURL=service-manager.service.js.map
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
19
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
20
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
21
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
22
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
23
|
+
};
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
42
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
43
|
+
};
|
|
44
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
45
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
46
|
+
};
|
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.VersionCompatibilityService = void 0;
|
|
49
|
+
const tsyringe_1 = require("tsyringe");
|
|
50
|
+
const semver = __importStar(require("semver"));
|
|
51
|
+
const tokens_1 = require("../../../di/tokens");
|
|
52
|
+
const sensitive_decorator_1 = require("../../../domain/decorators/sensitive.decorator");
|
|
53
|
+
const errors_1 = require("../../errors");
|
|
54
|
+
const index_1 = require("../../../constants/index");
|
|
55
|
+
/**
|
|
56
|
+
* 版本相容性檢查服務
|
|
57
|
+
*
|
|
58
|
+
* 負責檢查 Chart 版本與當前 CLI 版本的相容性,包含:
|
|
59
|
+
* - 檢查 Chart 相容性清單
|
|
60
|
+
* - 驗證 Chart 版本
|
|
61
|
+
* - 解析最新的相容 Chart 版本
|
|
62
|
+
*
|
|
63
|
+
* 實作 IVersionCompatibility Domain Port
|
|
64
|
+
*/
|
|
65
|
+
let VersionCompatibilityService = class VersionCompatibilityService {
|
|
66
|
+
constructor(httpClient, appConfig, acrCreds, logger) {
|
|
67
|
+
this.httpClient = httpClient;
|
|
68
|
+
this.appConfig = appConfig;
|
|
69
|
+
this.acrCreds = acrCreds;
|
|
70
|
+
this.logger = logger;
|
|
71
|
+
this.cachedManifest = null;
|
|
72
|
+
this.cliVersion = this.appConfig.getCliVersion();
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 取得 Chart 相容性資訊
|
|
76
|
+
* @returns Chart 相容性物件
|
|
77
|
+
*/
|
|
78
|
+
async getCompatibility() {
|
|
79
|
+
try {
|
|
80
|
+
const manifest = await this.fetchCompatibilityManifest(index_1.OCI_ARTIFACTS.CHART_COMPATIBILITY);
|
|
81
|
+
return this.parseCompatibility(manifest);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
this.logger.error(error instanceof Error ? error : new Error(String(error)), {
|
|
85
|
+
message: 'Failed to fetch chart compatibility'
|
|
86
|
+
});
|
|
87
|
+
// 失敗時拋出錯誤,讓呼叫者處理
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 驗證 Chart 版本是否與當前 CLI 相容
|
|
93
|
+
* @param chartVersion - Chart 版本
|
|
94
|
+
* @throws AppBusinessError 若版本不相容
|
|
95
|
+
*/
|
|
96
|
+
async validateChartVersion(chartVersion) {
|
|
97
|
+
// 如果版本是 'latest' 或本地路徑,跳過檢查
|
|
98
|
+
if (chartVersion === 'latest' || chartVersion.startsWith('.') || chartVersion.startsWith('/') || chartVersion.match(/^[a-zA-Z]:/)) {
|
|
99
|
+
this.logger.debug(`Skipping compatibility check for version: ${chartVersion}`);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const compatibility = await this.getCompatibility();
|
|
103
|
+
// 如果找不到兼容的 Chart(例如配置遺失或提取失敗但未拋出錯誤),我們假設 getCompatibility 成功執行
|
|
104
|
+
if (compatibility.compatibleCharts.length === 0) {
|
|
105
|
+
// 找不到符合此 CLI 版本的規則
|
|
106
|
+
// 或者相容性清單為空
|
|
107
|
+
this.logger.warn(`No compatibility rules found for CLI v${this.cliVersion}`);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (!compatibility.compatibleCharts.includes(chartVersion)) {
|
|
111
|
+
throw new errors_1.AppError(`Chart version ${chartVersion} is not compatible with CLI v${this.cliVersion}`, {
|
|
112
|
+
exitCode: errors_1.EXIT_CODES.BUSINESS_ERROR,
|
|
113
|
+
solution: `Use one of these compatible versions: ${compatibility.compatibleCharts.join(', ')}`,
|
|
114
|
+
context: {
|
|
115
|
+
chartVersion,
|
|
116
|
+
cliVersion: this.cliVersion,
|
|
117
|
+
compatibleCharts: compatibility.compatibleCharts
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* 取得與當前 CLI 相容的最新 Chart 版本
|
|
124
|
+
* @returns 最新的相容版本字串
|
|
125
|
+
* @throws AppBusinessError 若無相容版本
|
|
126
|
+
*/
|
|
127
|
+
async getLatestCompatibleVersion() {
|
|
128
|
+
const compatibility = await this.getCompatibility();
|
|
129
|
+
if (compatibility.compatibleCharts.length === 0) {
|
|
130
|
+
throw new errors_1.AppError(`No compatible chart versions available for CLI v${this.cliVersion}`, {
|
|
131
|
+
exitCode: errors_1.EXIT_CODES.BUSINESS_ERROR,
|
|
132
|
+
solution: 'Check the compatibility manifest configuration or consider updating the CLI version',
|
|
133
|
+
context: {
|
|
134
|
+
cliVersion: this.cliVersion
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
// 過濾出有效的語義化版本
|
|
139
|
+
const validVersions = compatibility.compatibleCharts.filter((v) => semver.valid(v));
|
|
140
|
+
if (validVersions.length === 0) {
|
|
141
|
+
throw new errors_1.AppError(`No valid semver versions in compatibility list for CLI v${this.cliVersion}`, {
|
|
142
|
+
exitCode: errors_1.EXIT_CODES.BUSINESS_ERROR,
|
|
143
|
+
solution: 'Check the compatibility manifest - all chart versions must follow semantic versioning format (e.g., 1.0.0)',
|
|
144
|
+
context: {
|
|
145
|
+
cliVersion: this.cliVersion,
|
|
146
|
+
rawVersions: compatibility.compatibleCharts
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
// 降冪排序並返回第一個(最新)版本
|
|
151
|
+
const sorted = semver.rsort(validVersions);
|
|
152
|
+
const latestVersion = sorted[0];
|
|
153
|
+
this.logger.debug(`Latest compatible version selected: ${latestVersion}`, {
|
|
154
|
+
cliVersion: this.cliVersion,
|
|
155
|
+
allCompatibleVersions: validVersions
|
|
156
|
+
});
|
|
157
|
+
return latestVersion;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* 解析相容性清單,找出符合當前 CLI 的規則
|
|
161
|
+
* @param manifest - 相容性清單
|
|
162
|
+
* @returns Chart 相容性物件
|
|
163
|
+
*/
|
|
164
|
+
parseCompatibility(manifest) {
|
|
165
|
+
// 尋找符合當前 CLI 版本的規則
|
|
166
|
+
const rule = manifest.compatibility.find(r => semver.satisfies(this.cliVersion, r.cliRange));
|
|
167
|
+
if (!rule) {
|
|
168
|
+
this.logger.warn(`No compatibility rule matches CLI v${this.cliVersion}`);
|
|
169
|
+
return {
|
|
170
|
+
cliVersion: this.cliVersion,
|
|
171
|
+
compatibleCharts: []
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
return {
|
|
175
|
+
cliVersion: this.cliVersion,
|
|
176
|
+
compatibleCharts: rule.charts
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* 從 ACR 獲取相容性清單 (Manifest)
|
|
181
|
+
* 使用快取避免重複請求
|
|
182
|
+
* @param repo - Repository 名稱
|
|
183
|
+
* @returns 相容性清單物件
|
|
184
|
+
*/
|
|
185
|
+
async fetchCompatibilityManifest(repo) {
|
|
186
|
+
// 使用快取
|
|
187
|
+
if (this.cachedManifest) {
|
|
188
|
+
return this.cachedManifest;
|
|
189
|
+
}
|
|
190
|
+
const creds = this.acrCreds.getDefaultCredentials();
|
|
191
|
+
if (!creds) {
|
|
192
|
+
throw new Error('ACR credentials not found');
|
|
193
|
+
}
|
|
194
|
+
const registry = `${creds.name}.azurecr.io`;
|
|
195
|
+
const scope = `repository:${repo}:pull`;
|
|
196
|
+
// 1. 取得 Token
|
|
197
|
+
const token = await this.getAcrToken(registry, scope, creds.account, creds.password);
|
|
198
|
+
// 2. 取得 Manifest 以查找 Blob Digest
|
|
199
|
+
const tag = index_1.OCI_ARTIFACT_TAGS.CHART_COMPATIBILITY;
|
|
200
|
+
const manifestUrl = `https://${registry}/v2/${repo}/manifests/${tag}`;
|
|
201
|
+
const manifestResponse = await this.httpClient.getJson(manifestUrl, {
|
|
202
|
+
Authorization: `Bearer ${token}`,
|
|
203
|
+
Accept: 'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json'
|
|
204
|
+
});
|
|
205
|
+
// 3. 取得 Config Blob
|
|
206
|
+
// Manifest 包含 Layers。我們預期 JSON 檔案是其中一層或 Config Blob。
|
|
207
|
+
// 故事需求: "Blob: GET /v2/<repo>/blobs/<digest>"
|
|
208
|
+
// 我們需要知道是哪個 digest。
|
|
209
|
+
// 如果是單一檔案的神器,通常是第一層。
|
|
210
|
+
let digest = '';
|
|
211
|
+
if (manifestResponse.layers && manifestResponse.layers.length > 0) {
|
|
212
|
+
digest = manifestResponse.layers[0].digest;
|
|
213
|
+
}
|
|
214
|
+
else if (manifestResponse.config) {
|
|
215
|
+
// 有時 Config Blob 本身包含資訊,但對於 chart-compatibility,通常是 Layer。
|
|
216
|
+
// 如果它是作為單一檔案推播的,它會是一個 Layer。
|
|
217
|
+
digest = manifestResponse.config.digest;
|
|
218
|
+
}
|
|
219
|
+
if (!digest) {
|
|
220
|
+
throw new Error('Could not find digest in manifest');
|
|
221
|
+
}
|
|
222
|
+
const blobUrl = `https://${registry}/v2/${repo}/blobs/${digest}`;
|
|
223
|
+
const blob = await this.httpClient.getJson(blobUrl, {
|
|
224
|
+
Authorization: `Bearer ${token}`
|
|
225
|
+
});
|
|
226
|
+
// 存入快取
|
|
227
|
+
this.cachedManifest = blob;
|
|
228
|
+
return blob;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* 獲取 ACR 存取 Token
|
|
232
|
+
* @param registry - Registry Host
|
|
233
|
+
* @param scope - 權限範圍
|
|
234
|
+
* @param user - 使用者名稱
|
|
235
|
+
* @param pass - 密碼
|
|
236
|
+
* @returns Access Token
|
|
237
|
+
*/
|
|
238
|
+
async getAcrToken(registry, scope, user, pass) {
|
|
239
|
+
const auth = Buffer.from(`${user}:${pass}`).toString('base64');
|
|
240
|
+
const url = `https://${registry}/oauth2/token?service=${registry}&scope=${scope}`;
|
|
241
|
+
const response = await this.httpClient.getJson(url, {
|
|
242
|
+
Authorization: `Basic ${auth}`
|
|
243
|
+
});
|
|
244
|
+
return response.access_token;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* 取得指定 Chart 版本對應的 Environment 版本
|
|
248
|
+
* @param chartVersion - Chart 版本(如 "2.123.301")
|
|
249
|
+
* @returns Environment 版本(如 "1.26.100")
|
|
250
|
+
* @throws AppError 若找不到對應的 environment 規則
|
|
251
|
+
*/
|
|
252
|
+
async getEnvironmentVersion(chartVersion) {
|
|
253
|
+
const manifest = await this.fetchCompatibilityManifest(index_1.OCI_ARTIFACTS.CHART_COMPATIBILITY);
|
|
254
|
+
// 如果沒有 environment 規則,使用預設版本
|
|
255
|
+
if (!manifest.environment || manifest.environment.length === 0) {
|
|
256
|
+
this.logger.warn('No environment rules in compatibility manifest, using default');
|
|
257
|
+
// 預設回傳 K8s 1.26 對應的版本
|
|
258
|
+
return '1.26.100';
|
|
259
|
+
}
|
|
260
|
+
// 使用 semver.satisfies 匹配 chart 版本到 environment 規則
|
|
261
|
+
const rule = manifest.environment.find(r => semver.satisfies(chartVersion, r.chartRange));
|
|
262
|
+
if (!rule) {
|
|
263
|
+
throw new errors_1.AppError(`No environment version found for chart ${chartVersion}`, {
|
|
264
|
+
exitCode: errors_1.EXIT_CODES.BUSINESS_ERROR,
|
|
265
|
+
solution: 'Check the compatibility manifest for environment rules',
|
|
266
|
+
context: {
|
|
267
|
+
chartVersion,
|
|
268
|
+
availableRules: manifest.environment.map(r => r.chartRange)
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
this.logger.debug(`Environment version for chart ${chartVersion}: ${rule.version}`);
|
|
273
|
+
return rule.version;
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
exports.VersionCompatibilityService = VersionCompatibilityService;
|
|
277
|
+
__decorate([
|
|
278
|
+
__param(3, (0, sensitive_decorator_1.Sensitive)()),
|
|
279
|
+
__metadata("design:type", Function),
|
|
280
|
+
__metadata("design:paramtypes", [String, String, String, String]),
|
|
281
|
+
__metadata("design:returntype", Promise)
|
|
282
|
+
], VersionCompatibilityService.prototype, "getAcrToken", null);
|
|
283
|
+
exports.VersionCompatibilityService = VersionCompatibilityService = __decorate([
|
|
284
|
+
(0, tsyringe_1.injectable)(),
|
|
285
|
+
__param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IHttpClient)),
|
|
286
|
+
__param(1, (0, tsyringe_1.inject)(tokens_1.TOKENS.IAppConfig)),
|
|
287
|
+
__param(2, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IAcrCredentialManager)),
|
|
288
|
+
__param(3, (0, tsyringe_1.inject)(tokens_1.TOKENS.ILoggerPort)),
|
|
289
|
+
__metadata("design:paramtypes", [Object, Object, Object, Object])
|
|
290
|
+
], VersionCompatibilityService);
|
|
291
|
+
//# sourceMappingURL=version-compatibility.service.js.map
|