From cfd3b66be9ebf53a26693057e70ed60c3f116be9 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Mon, 14 Apr 2025 23:31:59 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E6=94=AF=E6=8C=81=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E8=AF=81=E4=B9=A6=E5=88=B0=E5=8D=8E=E4=B8=BA=E4=BA=91CCM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/certd-server/export-plugin-yaml.js | 53 ++++++++++++ .../plugins/upload-to-ccm/ccm-client.ts | 59 +++++++++++++ .../upload-to-ccm/huawei-upload-to-ccm.yaml | 61 ++++++++++++++ .../plugins/upload-to-ccm/index.ts | 82 +++++++++++++++++++ 4 files changed, 255 insertions(+) create mode 100644 packages/ui/certd-server/export-plugin-yaml.js create mode 100644 packages/ui/certd-server/src/plugins/plugin-huawei/plugins/upload-to-ccm/ccm-client.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-huawei/plugins/upload-to-ccm/huawei-upload-to-ccm.yaml create mode 100644 packages/ui/certd-server/src/plugins/plugin-huawei/plugins/upload-to-ccm/index.ts diff --git a/packages/ui/certd-server/export-plugin-yaml.js b/packages/ui/certd-server/export-plugin-yaml.js new file mode 100644 index 00000000..f9b885ab --- /dev/null +++ b/packages/ui/certd-server/export-plugin-yaml.js @@ -0,0 +1,53 @@ +// 扫描目录,列出文件,然后加载为模块 + +import { join } from 'path'; +import fs from 'fs' +import { pathToFileURL } from "node:url"; +import path from 'path' +function scanDir(dir) { + const files = fs.readdirSync(dir); + const result = []; + // 扫描目录及子目录 + for (const file of files) { + if (file.includes("index.js")) { + continue; + } + + const filePath = join(dir, file); + const stat = fs.statSync(filePath); + if (stat.isDirectory()) { + result.push(...scanDir(filePath)); + } else { + if (!file.endsWith(".js")) { + continue; + } + result.push(filePath); + } + } + return result +} + +export default async function loadModules(dir) { + const files = scanDir(dir); + const modules = {} + for (const file of files) { + + try { + // 转换为 file:// URL(Windows 必需) + const moduleUrl = pathToFileURL(file).href + const module = await import(moduleUrl) + + // 如果模块有默认导出,优先使用 + modules[file] = module.default || module + } catch (err) { + console.error(`加载模块 ${file} 失败:`, err) + } + } + return modules; +} + +const modules = await loadModules('./dist/plugins'); + +for (const key in modules) { + console.log(key) +} diff --git a/packages/ui/certd-server/src/plugins/plugin-huawei/plugins/upload-to-ccm/ccm-client.ts b/packages/ui/certd-server/src/plugins/plugin-huawei/plugins/upload-to-ccm/ccm-client.ts new file mode 100644 index 00000000..7d58dcf6 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-huawei/plugins/upload-to-ccm/ccm-client.ts @@ -0,0 +1,59 @@ +//@ts-ignore +import { HcClient } from "@huaweicloud/huaweicloud-sdk-core/HcClient"; + +export class HuaweiCcmClient { + //@ts-ignore + hcClient: HcClient; + + //@ts-ignore + constructor(client: HcClient) { + this.hcClient = client; + } + + /** + */ + importCertificate(req: { + name: string, + certificate: string, + private_key: string, + duplicate_check: boolean, + }) { + const options: any = { + method: "POST", + url: "/v3/scm/certificates/import", + pathParams: {}, + queryParams: {}, + contentType: "application/json", + headers: { + "Content-Type": "application/json" + }, + /** + * name + * string 是 + * 证书名称。字符长度为3~63位, 请输入英文字符,数字,下划线,中划线,英文句点。 + * + * certificate + * string 是 + * 证书内容,可包含中间证书及根证书。若certificate_chain字段传入证书链,则该字段只取证书本身。回车换行需要使用转义字符\n或者\r\n替换。 + * + * certificate_chain + * string 否 + * 证书链,非必填,可通过certificate字段传入。回车换行需要使用转义字符\n或者\r\n替换。 + * + * private_key + * string 是 + * 证书私钥。 + * 不能上传带有口令保护的私钥,回车换行需要使用转义字符\n或者\r\n替换。 + * + * duplicate_check + */ + data: { + ...req + } + + }; + // @ts-ignore + options["responseHeaders"] = ["X-Request-Id"]; + return this.hcClient.sendRequest(options); + } +} diff --git a/packages/ui/certd-server/src/plugins/plugin-huawei/plugins/upload-to-ccm/huawei-upload-to-ccm.yaml b/packages/ui/certd-server/src/plugins/plugin-huawei/plugins/upload-to-ccm/huawei-upload-to-ccm.yaml new file mode 100644 index 00000000..33fc3529 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-huawei/plugins/upload-to-ccm/huawei-upload-to-ccm.yaml @@ -0,0 +1,61 @@ +name: HuaweiUploadToCCM +title: 华为-上传证书至CCM +desc: 上传证书至华为云CCM +type: plugin +pluginType: deploy +author: certd +version: 1.0.0 +icon: 'svg:icon-huawei' +group: huawei +default: + strategy: + runStrategy: 1, +input: # 插件的输入参数 + cert: + title: 前置任务证书 + helper: 请选择前置任务产生的证书 # 帮助说明 + component: + name: output-selector # 输入组件名称 + vModel: modelValue # 组件参数 + from: + - ApplyCert + - ApplyCertLego + - ApplyCertUpload + required: true + certDomains: + title: 当前证书域名 + component: + name: cert-domains-getter + mergeScript: | + return { + component:{ + inputKey: ctx.compute(({form})=>{ + return form.cert + }), + } + } + required: true + accessId: + title: Access授权 + helper: xxxx的授权 + component: + name: access-selector # 授权选择组件名称 + type: aliyun # 授权类型 + required: true + key1: + title: 输入示例1 + required: false + key2: + title: 可选项 + component: + name: a-select + vMode: value + options: + - value: "1" + label: 选项1 + - value: "2" + label: 选项2 + required: false +#output: # 输出参数,一般插件都不需要配置此项 +# outputName: +# diff --git a/packages/ui/certd-server/src/plugins/plugin-huawei/plugins/upload-to-ccm/index.ts b/packages/ui/certd-server/src/plugins/plugin-huawei/plugins/upload-to-ccm/index.ts new file mode 100644 index 00000000..039d24de --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-huawei/plugins/upload-to-ccm/index.ts @@ -0,0 +1,82 @@ +import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline"; +import { HuaweiAccess } from "../../access/index.js"; +import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert"; +import { createCertDomainGetterInputDefine } from "@certd/plugin-lib"; +import { resetLogConfigure } from "@certd/basic"; + + +@IsTaskPlugin({ + name: 'HauweiUploadToCCM', + title: '华为云-上传证书至CCM', + icon: 'svg:icon-huawei', + group: pluginGroups.huawei.key, + desc: '上传证书到华为云CCM', + default: { + strategy: { + runStrategy: RunStrategy.SkipWhenSucceed, + }, + }, +}) +export class HauweiUploadToCCM extends AbstractTaskPlugin { + @TaskInput({ + title: "域名证书", + helper: "请选择前置任务输出的域名证书", + component: { + name: "output-selector", + from: [...CertApplyPluginNames] + }, + required: true + }) + cert!: CertInfo; + + @TaskInput(createCertDomainGetterInputDefine({ props: { required: false } })) + certDomains!: string[]; + + @TaskInput({ + title: "Access授权", + helper: "华为云授权AccessKeyId、AccessKeySecret", + component: { + name: "access-selector", + type: "huawei" + }, + required: true + }) + accessId!: string; + @TaskOutput({ + title: '华为云CertId', + }) + huaweiCertId!: string; + + async execute(): Promise { + this.logger.info("开始部署证书到华为云CCM"); + const { client } = await this.getCcmClient(); + + const res = await client.importCertificate({ + name: this.appendTimeSuffix("certd"), + certificate: this.cert.crt, + private_key: this.cert.key, + duplicate_check: false + }); + this.huaweiCertId = res.certificate_id; + this.logger.info(`上传证书到华为云ccm完成,certificate_id:${this.huaweiCertId}`); + } + + async getCcmClient() { + const access = await this.getAccess(this.accessId); + const { BasicCredentials } = await import("@huaweicloud/huaweicloud-sdk-core"); + const { ClientBuilder } = await import("@huaweicloud/huaweicloud-sdk-core/ClientBuilder.js"); + //@ts-ignore + const {HuaweiCcmClient} = await import("./ccm-client.js") + + //恢复华为云把log4j的config改了的问题 + resetLogConfigure(); + + const credentials = new BasicCredentials().withAk(access.accessKeyId).withSk(access.accessKeySecret); + const client = new ClientBuilder((hcClient) => { + return new HuaweiCcmClient(hcClient); + }).withCredential(credentials).withEndpoint("https://scm.cn-north-4.myhuaweicloud.com").build(); + return { + client + }; + } +}