fix: 修复成功后跳过之后丢失腾讯云证书id的bug

pull/148/head
xiaojunnuo 2024-08-23 23:26:31 +08:00
parent 3345c145b8
commit 37eb762afe
10 changed files with 78 additions and 45 deletions

View File

@ -144,7 +144,6 @@ module.exports = async (client, userOpts) => {
log(`[auto] [${d}] challenge verification threw error: ${e.message}`);
}
}
/* Complete challenge and wait for valid status */
log(`[auto] [${d}] Completing challenge with ACME provider and waiting for valid status`);
await client.completeChallenge(challenge);
@ -236,6 +235,9 @@ module.exports = async (client, userOpts) => {
for (const challengePromises of allChallengePromises) {
i += 1;
log(`开始第${i}`);
if (opts.signal && opts.signal.aborted) {
throw new Error('用户取消');
}
// eslint-disable-next-line no-await-in-loop
await runPromisePa(challengePromises);
}

View File

@ -490,6 +490,9 @@ class AcmeClient {
const keyAuthorization = await this.getChallengeKeyAuthorization(challenge);
const verifyFn = async () => {
if (this.opts.signal && this.opts.signal.aborted) {
throw new Error('用户取消');
}
await verify[challenge.type](authz, challenge, keyAuthorization);
};
@ -513,6 +516,9 @@ class AcmeClient {
*/
async completeChallenge(challenge) {
if (this.opts.signal && this.opts.signal.aborted) {
throw new Error('用户取消');
}
const resp = await this.api.completeChallenge(challenge.url, {});
return resp.data;
}
@ -550,6 +556,10 @@ class AcmeClient {
}
const verifyFn = async (abort) => {
if (this.opts.signal && this.opts.signal.aborted) {
throw new Error('用户取消');
}
const resp = await this.api.apiRequest(item.url, null, [200]);
/* Verify status */

View File

@ -45,6 +45,7 @@ export interface ClientOptions {
backoffMin?: number;
backoffMax?: number;
urlMapping?: UrlMapping;
signal?: AbortSignal;
}
export interface ClientExternalAccountBindingOptions {
@ -61,6 +62,7 @@ export interface ClientAutoOptions {
skipChallengeVerification?: boolean;
challengePriority?: string[];
preferredChain?: string;
signal?: AbortSignal;
}
export class Client {

View File

@ -23,6 +23,7 @@ export type ExecutorOptions = {
emailService: IEmailService;
fileRootDir?: string;
};
export class Executor {
pipeline: Pipeline;
runtime!: RunHistory;
@ -32,7 +33,8 @@ export class Executor {
lastStatusMap!: RunnableCollection;
lastRuntime!: RunHistory;
options: ExecutorOptions;
canceled = false;
abort: AbortController = new AbortController();
onChanged: (history: RunHistory) => Promise<void>;
constructor(options: ExecutorOptions) {
this.options = options;
@ -53,7 +55,7 @@ export class Executor {
}
async cancel() {
this.canceled = true;
this.abort.abort();
this.runtime?.cancel(this.pipeline);
await this.onChanged(this.runtime);
}
@ -102,6 +104,8 @@ export class Executor {
}
}
if (lastResult != null && lastResult === ResultType.success && !inputChanged) {
runnable.status!.output = lastNode?.status?.output;
runnable.status!.files = lastNode?.status?.files;
this.runtime.skip(runnable);
await this.onChanged(this.runtime);
return ResultType.skip;
@ -113,10 +117,15 @@ export class Executor {
// const timeout = runnable.timeout ?? 20 * 60 * 1000;
try {
if (this.canceled) {
if (this.abort.signal.aborted) {
this.runtime.cancel(runnable);
return ResultType.canceled;
}
await run();
if (this.abort.signal.aborted) {
this.runtime.cancel(runnable);
return ResultType.canceled;
}
this.runtime.success(runnable);
return ResultType.success;
} catch (e: any) {
@ -211,16 +220,11 @@ export class Executor {
if (item.component?.name === "pi-output-selector") {
const contextKey = step.input[key];
if (contextKey != null) {
const value = this.runtime.context[contextKey];
if (value == null) {
currentLogger.warn(`[step init] input ${define.title} is null前置任务步骤输出值为空请按如下步骤排查`);
currentLogger.log(`1、检查前置任务证书申请任务是否是配置了成功后跳过如果是请改为正常执行`);
currentLogger.log(
`2、是否曾经删除过前置任务证书申请任务然后又重新添加了如果是请重新编辑当前任务重新选择一下前置任务输出的参数域名证书那一栏`
);
currentLogger.log(`3、以上都不是联系作者吧`);
}
step.input[key] = value;
// "cert": "step.-BNFVPMKPu2O-i9NiOQxP.cert",
const arr = contextKey.split(".");
const id = arr[1];
const outputKey = arr[2];
step.input[key] = this.lastStatusMap.get(id)?.status?.output[outputKey];
}
}
});
@ -241,6 +245,7 @@ export class Executor {
parent: this.runtime.id,
rootDir: this.options.fileRootDir,
}),
signal: this.abort.signal,
};
instance.setCtx(taskCtx);
@ -254,8 +259,8 @@ export class Executor {
//输出上下文变量到output context
_.forEach(define.output, (item: any, key: any) => {
step.status!.output[key] = instance[key];
const stepOutputKey = `step.${step.id}.${key}`;
this.runtime.context[stepOutputKey] = instance[key];
// const stepOutputKey = `step.${step.id}.${key}`;
// this.runtime.context[stepOutputKey] = instance[key];
});
step.status!.files = instance.getFiles();

View File

@ -1,4 +1,4 @@
import { Context, HistoryResult, Pipeline, ResultType, Runnable, RunnableMap, Stage, Step, Task } from "../dt/index.js";
import { HistoryResult, Pipeline, ResultType, Runnable, RunnableMap, Stage, Step, Task } from "../dt/index.js";
import _ from "lodash-es";
import { buildLogger } from "../utils/util.log.js";
import { Logger } from "log4js";
@ -14,15 +14,12 @@ export type RunTrigger = {
export function NewRunHistory(obj: any) {
const history = new RunHistory(obj.id, obj.trigger, obj.pipeline);
history.context = obj.context;
history.logs = obj.logs;
history._loggers = obj.loggers;
return history;
}
export class RunHistory {
id!: string;
//运行时上下文变量
context: Context = {};
pipeline!: Pipeline;
logs: {
[runnableId: string]: string[];

View File

@ -64,6 +64,7 @@ export type TaskInstanceContext = {
http: AxiosInstance;
fileStore: FileStore;
lastStatus?: Runnable;
signal: AbortSignal;
};
export abstract class AbstractTaskPlugin implements ITaskPlugin {

View File

@ -23,6 +23,7 @@ type AcmeServiceOptions = {
skipLocalVerify?: boolean;
useMappingProxy?: boolean;
privateKeyType?: PrivateKeyType;
signal?: AbortSignal;
};
export class AcmeService {
@ -99,6 +100,7 @@ export class AcmeService {
backoffMin: 5000,
backoffMax: 10000,
urlMapping,
signal: this.options.signal,
});
if (conf.accountUrl == null) {
@ -253,6 +255,7 @@ export class AcmeService {
challengeRemoveFn: async (authz: acme.Authorization, challenge: Challenge, keyAuthorization: string, recordItem: any): Promise<any> => {
return await this.challengeRemoveFn(authz, challenge, keyAuthorization, recordItem, dnsProvider);
},
signal: this.options.signal,
});
const cert: CertInfo = {

View File

@ -64,6 +64,7 @@
"svg-captcha": "^1.4.0",
"tencentcloud-sdk-nodejs": "^4.0.44",
"tencentcloud-sdk-nodejs-dnspod": "^4.0.866",
"tencentcloud-sdk-nodejs-teo": "^4.0.919",
"typeorm": "^0.3.11"
},
"devDependencies": {

View File

@ -4,9 +4,8 @@ import { TencentAccess } from '../../access/index.js';
import { CertInfo } from '@certd/plugin-cert';
@IsTaskPlugin({
name: 'DeployCertToTencentEO',
title: '部署到腾讯云EO',
desc: '腾讯云边缘安全加速平台 EO',
name: 'DeployCertToTencentCDN',
title: '部署到腾讯云CDN',
group: pluginGroups.tencent.key,
default: {
strategy: {

View File

@ -1,11 +1,11 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
import tencentcloud from 'tencentcloud-sdk-nodejs';
import tencentcloud from 'tencentcloud-sdk-nodejs-teo';
import { TencentAccess } from '../../access/index.js';
import { CertInfo } from '@certd/plugin-cert';
@IsTaskPlugin({
name: 'DeployCertToTencentCDN',
title: '部署到腾讯云CDN',
name: 'DeployCertToTencentEO',
title: '部署到腾讯云EO',
desc: '腾讯云边缘安全加速平台EO必须配置上传证书到腾讯云任务',
group: pluginGroups.tencent.key,
default: {
strategy: {
@ -13,17 +13,17 @@ import { CertInfo } from '@certd/plugin-cert';
},
},
})
export class DeployToCdnPlugin extends AbstractTaskPlugin {
export class DeployToEOPlugin extends AbstractTaskPlugin {
@TaskInput({
title: '域名证书',
helper: '请选择前置任务输出的域名证书',
title: '已上传证书ID',
helper: '请选择前置任务上传到腾讯云的证书',
component: {
name: 'pi-output-selector',
from: 'CertApply',
from: 'UploadCertToTencent',
},
required: true,
})
cert!: CertInfo;
certId!: string;
@TaskInput({
title: 'Access提供者',
@ -36,6 +36,12 @@ export class DeployToCdnPlugin extends AbstractTaskPlugin {
})
accessId!: string;
@TaskInput({
title: '站点ID',
helper: '类似于zone-xxxx的字符串在站点概览页面左上角或者站点列表页面站点名称下方',
})
zoneId!: string;
@TaskInput({
title: '证书名称',
helper: '证书上传后将以此参数作为名称前缀',
@ -44,9 +50,16 @@ export class DeployToCdnPlugin extends AbstractTaskPlugin {
@TaskInput({
title: 'cdn加速域名',
component: {
name: 'a-select',
vModel: 'value',
mode: 'tags',
open: false,
},
helper: '支持多个域名',
rules: [{ required: true, message: '该项必填' }],
})
domainName!: string;
domainNames!: string[];
// @TaskInput({
// title: "CDN接口",
@ -69,7 +82,7 @@ export class DeployToCdnPlugin extends AbstractTaskPlugin {
}
getClient(accessProvider: TencentAccess) {
const CdnClient = tencentcloud.cdn.v20180606.Client;
const TeoClient = tencentcloud.teo.v20220901.Client;
const clientConfig = {
credential: {
@ -79,31 +92,31 @@ export class DeployToCdnPlugin extends AbstractTaskPlugin {
region: '',
profile: {
httpProfile: {
endpoint: 'cdn.tencentcloudapi.com',
endpoint: 'teo.tencentcloudapi.com',
},
},
};
return new CdnClient(clientConfig);
return new TeoClient(clientConfig);
}
buildParams() {
return {
Https: {
Switch: 'on',
CertInfo: {
Certificate: this.cert.crt,
PrivateKey: this.cert.key,
ZoneId: this.zoneId,
Hosts: this.domainNames,
Mode: 'sslcert',
ServerCertInfo: [
{
CertId: this.certId,
},
},
Domain: this.domainName,
],
};
}
async doRequest(client: any, params: any) {
const ret = await client.UpdateDomainConfig(params);
const ret = await client.ModifyHostsCertificate(params);
this.checkRet(ret);
this.logger.info('设置腾讯云CDN证书成功:', ret.RequestId);
this.logger.info('设置腾讯云EO证书成功:', ret.RequestId);
return ret.RequestId;
}