perf: 支持部署到华为云obs

v2-dev-buy
xiaojunnuo 2025-08-25 23:22:17 +08:00
parent 5419b1439a
commit 9feb9d04b3
4 changed files with 204 additions and 20 deletions

View File

@ -82,6 +82,7 @@
"cross-env": "^7.0.3",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.7",
"esdk-obs-nodejs": "^3.25.6",
"form-data": "^4.0.0",
"glob": "^11.0.0",
"https-proxy-agent": "^7.0.5",

View File

@ -0,0 +1,185 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
import { HuaweiAccess } from "../../access/index.js";
import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert";
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib";
@IsTaskPlugin({
name: 'HauweiDeployCertToOBS',
title: '华为云-部署证书至OBS',
icon: 'svg:icon-huawei',
group: pluginGroups.huawei.key,
desc: '',
default: {
strategy: {
runStrategy: RunStrategy.SkipWhenSucceed,
},
},
})
export class HauweiDeployCertToOBS extends AbstractTaskPlugin {
@TaskInput({
title: '域名证书',
helper: '请选择前置任务输出的域名证书\n如果你选择使用ccm证书ID则需要在[域名管理页面右上角开启SCM授权](https://console.huaweicloud.com/cdn/#/cdn/domain)',
component: {
name: 'output-selector',
from: [...CertApplyPluginNames,'HauweiUploadToCCM'],
},
required: true,
})
cert!: CertInfo | string;
@TaskInput(createCertDomainGetterInputDefine({ props: { required: false } }))
certDomains!: string[];
@TaskInput({
title: 'Access授权',
helper: '华为云授权AccessKeyId、AccessKeySecret',
component: {
name: 'access-selector',
type: 'huawei',
},
required: true,
})
accessId!: string;
@TaskInput(
createRemoteSelectInputDefine({
title: '存储桶',
helper: '请选择存储桶',
action: HauweiDeployCertToOBS.prototype.onGetBucketList.name,
})
)
bucketList!: string[];
@TaskInput(
createRemoteSelectInputDefine({
title: '自定义域名',
helper: '请选择自定义域名',
action: HauweiDeployCertToOBS.prototype.onGetDomainList.name,
watches: ['bucketList'],
})
)
domainList!: string[];
async execute(): Promise<void> {
if (!this.cert) {
throw new Error('域名证书不能为空');
}
this.logger.info('开始部署证书到华为云obs');
for (const domainStr of this.domainList) {
const [location, bucket,domain] = domainStr.split('_');
await this.setDomainCert({
location,
bucket,
domain,
cert: this.cert
});
}
this.logger.info('部署证书到华为云cdn完成');
}
checkRet(ret: any){
if (ret?.CommonMsg?.Status>300){
throw new Error(`${ret?.CommonMsg?.Code}${ret?.CommonMsg?.Message}`);
}
}
async getObsClient(opts:{region?:string,bucket?:string} = {}) {
const { region,bucket } = opts;
const regionStr = region? `${region}.`: 'cn-north-4.';
const bucketStr = bucket? `${bucket}.` : '';
const access = await this.getAccess<HuaweiAccess>(this.accessId);
const sdk = await import('esdk-obs-nodejs');
const obsClient = new sdk.default({
// 推荐通过环境变量获取AKSK这里也可以使用其他外部引入方式传入如果使用硬编码可能会存在泄露风险
// 您可以登录访问管理控制台获取访问密钥AK/SK获取方式请参见https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html
access_key_id: access.accessKeyId,
secret_access_key: access.accessKeySecret,
// 【可选】如果使用临时AK/SK和SecurityToken访问OBS同样建议您尽量避免使用硬编码以降低信息泄露风险。您可以通过环境变量获取访问密钥AK/SK也可以使用其他外部引入方式传入
// security_token: process.env.SECURITY_TOKEN,
// endpoint填写Bucket对应的Endpoint, 这里以华北-北京四为例,其他地区请按实际情况填写
server: `https://${bucketStr}obs.${regionStr}myhuaweicloud.com`,
});
return obsClient
}
async onGetBucketList(data: any) {
const obsClient = await this.getObsClient();
const res = await obsClient.listBuckets({
QueryLocation:true
})
this.checkRet(res)
const list = res.InterfaceResult?.Buckets
if (!list || list.length === 0) {
return []
}
return list.map(item => {
return {
value: `${item.Location}_${item.BucketName}`,
label: `${item.BucketName}<${item.Location}>`,
};
});
}
async onGetDomainList(data:any) {
if (!this.bucketList || this.bucketList.length === 0) {
return []
}
const optionList = []
for (const item of this.bucketList) {
const [location,bucket] = item.split('_')
const obsClient = await this.getObsClient({region:location});
const res = await obsClient.getBucketCustomDomain({
Bucket: bucket,
})
this.checkRet(res)
const list = res.InterfaceResult?.Domains
if (!list || list.length === 0) {
continue
}
const options= list.map(item => {
return {
value: `${location}_${bucket}_${item.DomainName}`,
label: `${item.DomainName}<${bucket}_${location}>`,
domain: item.DomainName,
};
});
optionList.push(...options)
}
return this.ctx.utils.options.buildGroupOptions( optionList,this.certDomains)
}
async setDomainCert(opts:{location:string,bucket:string,domain:string,cert:string|CertInfo}){
const {location,bucket,domain,cert} = opts
const obsClient = await this.getObsClient({region:location});
const params:any = {
Bucket: bucket,
DomainName: domain,
Name: this.buildCertName( domain)
};
if (typeof cert === 'string'){
params.CertificateId= cert
}else{
params.Certificate= cert.crt
params.PrivateKey = cert.key
}
const res = await obsClient.setBucketCustomDomain(params)
this.checkRet(res)
}
}
new HauweiDeployCertToOBS();

View File

@ -1,2 +1,3 @@
export * from './deploy-to-cdn/index.js'
export * from './upload-to-ccm/index.js'
export * from './deploy-to-obs/index.js'

View File

@ -1602,6 +1602,9 @@ importers:
dayjs:
specifier: ^1.11.7
version: 1.11.13
esdk-obs-nodejs:
specifier: ^3.25.6
version: 3.25.6
form-data:
specifier: ^4.0.0
version: 4.0.2
@ -1629,9 +1632,6 @@ importers:
koa-send:
specifier: ^5.0.1
version: 5.0.1
ksyun-sdk-node:
specifier: ^1.2.4
version: 1.2.4(encoding@0.1.13)
kubernetes-client:
specifier: ^9.0.0
version: 9.0.0
@ -7390,6 +7390,10 @@ packages:
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
engines: {node: '>=12'}
esdk-obs-nodejs@3.25.6:
resolution: {integrity: sha512-bDEznGBoSjqmFNjkL0PvkMzF6o50wa+1PSKQ1tT5CtBP/yw7Egx0c/kIVsu5Raqcip1SjKu7muzslG4xo/skew==}
engines: {node: '>=0.12.7'}
eslint-config-prettier@8.10.0:
resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==}
hasBin: true
@ -9189,9 +9193,6 @@ packages:
kolorist@1.8.0:
resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
ksyun-sdk-node@1.2.4:
resolution: {integrity: sha512-W/c1nhnZskadPP7ObmizMh+jJeHXWka0HkS8lcZfLWxwEH83B8iMFF0DrtSaDCjQRuBpgzwDLGbbp+U1D1rXlQ==}
kubernetes-client@9.0.0:
resolution: {integrity: sha512-Qy8o42dZVHB9P+cIiKdWpQbz/65l/qW1fDYvlzzeSLftmL1Ne3HEiM+0TmKAwNuRW0pTJN2tRWhcccToclxJ8g==}
engines: {node: '>=10.13.0'}
@ -21386,6 +21387,13 @@ snapshots:
escape-string-regexp@5.0.0: {}
esdk-obs-nodejs@3.25.6:
dependencies:
fast-xml-parser: 4.5.0
log4js: 6.9.1
transitivePeerDependencies:
- supports-color
eslint-config-prettier@8.10.0(eslint@7.32.0):
dependencies:
eslint: 7.32.0
@ -21527,13 +21535,13 @@ snapshots:
resolve: 1.22.10
semver: 6.3.1
eslint-plugin-prettier@3.4.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@7.32.0)(prettier@2.8.8):
eslint-plugin-prettier@3.4.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@2.8.8):
dependencies:
eslint: 7.32.0
prettier: 2.8.8
prettier-linter-helpers: 1.0.0
optionalDependencies:
eslint-config-prettier: 8.10.0(eslint@8.57.0)
eslint-config-prettier: 8.10.0(eslint@7.32.0)
eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8):
dependencies:
@ -23518,17 +23526,6 @@ snapshots:
kolorist@1.8.0: {}
ksyun-sdk-node@1.2.4(encoding@0.1.13):
dependencies:
abort-controller: 3.0.0
core-js: 3.42.0
crypto-js: 4.2.0
dayjs: 1.11.13
node-fetch: 2.7.0(encoding@0.1.13)
qs: 6.14.0
transitivePeerDependencies:
- encoding
kubernetes-client@9.0.0:
dependencies:
'@kubernetes/client-node': 0.10.2
@ -24252,7 +24249,7 @@ snapshots:
eslint: 7.32.0
eslint-config-prettier: 8.10.0(eslint@7.32.0)
eslint-plugin-node: 11.1.0(eslint@7.32.0)
eslint-plugin-prettier: 3.4.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@7.32.0)(prettier@2.8.8)
eslint-plugin-prettier: 3.4.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@2.8.8)
execa: 5.1.1
inquirer: 7.3.3
json5: 2.2.3