diff --git a/packages/core/pipeline/src/access/api.ts b/packages/core/pipeline/src/access/api.ts index 905d2d91..b0a18dc9 100644 --- a/packages/core/pipeline/src/access/api.ts +++ b/packages/core/pipeline/src/access/api.ts @@ -6,7 +6,7 @@ export type AccessInputDefine = FormItemProps & { required?: boolean; }; export type AccessDefine = Registrable & { - inputs?: { + input?: { [key: string]: AccessInputDefine; }; }; diff --git a/packages/core/pipeline/src/access/decorator.ts b/packages/core/pipeline/src/access/decorator.ts index 10e1975d..3457afb0 100644 --- a/packages/core/pipeline/src/access/decorator.ts +++ b/packages/core/pipeline/src/access/decorator.ts @@ -20,7 +20,7 @@ export function IsAccess(define: AccessDefine): ClassDecorator { inputs[property] = input; } } - _.merge(define, { inputs }); + _.merge(define, { input: inputs }); Reflect.defineMetadata(ACCESS_CLASS_KEY, define, target); target.define = define; accessRegistry.register(define.name, { @@ -30,9 +30,9 @@ export function IsAccess(define: AccessDefine): ClassDecorator { }; } -export function IsAccessInput(input?: AccessInputDefine): PropertyDecorator { +export function AccessInput(input?: AccessInputDefine): PropertyDecorator { return (target, propertyKey) => { - target = Decorator.target(target); + target = Decorator.target(target, propertyKey); // const _type = Reflect.getMetadata("design:type", target, propertyKey); Reflect.defineMetadata(ACCESS_INPUT_KEY, input, target, propertyKey); }; diff --git a/packages/core/pipeline/src/core/executor.ts b/packages/core/pipeline/src/core/executor.ts index fa82dd5b..b569e3bf 100644 --- a/packages/core/pipeline/src/core/executor.ts +++ b/packages/core/pipeline/src/core/executor.ts @@ -9,6 +9,7 @@ import { Logger } from "log4js"; import { request } from "../utils/util.request"; import { IAccessService } from "../access"; import { RegistryItem } from "../registry"; +import { Decorator } from "../decorator"; export class Executor { userId: any; @@ -149,21 +150,17 @@ export class Executor { // @ts-ignore const define: PluginDefine = plugin.define; //从outputContext读取输入参数 - _.forEach(define.input, (item, key) => { + Decorator.inject(define.input, instance, step.input, (item, key) => { if (item.component?.name === "pi-output-selector") { const contextKey = step.input[key]; if (contextKey != null) { step.input[key] = this.runtime.context[contextKey]; } - } else { - instance[key] = step.input[key]; } }); - _.forEach(define.autowire, (item, key: string) => { - instance[key] = context[key]; - }); - + Decorator.inject(define.autowire, instance, context); + await instance.onInit(); await instance.execute(); //输出到output context diff --git a/packages/core/pipeline/src/decorator/common.ts b/packages/core/pipeline/src/decorator/common.ts new file mode 100644 index 00000000..c458a648 --- /dev/null +++ b/packages/core/pipeline/src/decorator/common.ts @@ -0,0 +1,17 @@ +import { Decorator } from "./index"; + +export type AutowireProp = { + name?: string; + type?: any; +}; +export const AUTOWIRE_KEY = "pipeline:autowire"; + +export function Autowire(props?: AutowireProp): PropertyDecorator { + return (target, propertyKey) => { + const _type = Reflect.getMetadata("design:type", target, propertyKey); + target = Decorator.target(target, propertyKey); + props = props || {}; + props.type = _type; + Reflect.defineMetadata(AUTOWIRE_KEY, props || {}, target, propertyKey); + }; +} diff --git a/packages/core/pipeline/src/decorator/index.ts b/packages/core/pipeline/src/decorator/index.ts index 5947df5b..0af2b940 100644 --- a/packages/core/pipeline/src/decorator/index.ts +++ b/packages/core/pipeline/src/decorator/index.ts @@ -1,28 +1,2 @@ -const propertyMap: any = {}; -function attachProperty(target: any, propertyKey: string | symbol) { - let props = propertyMap[target]; - if (props == null) { - props = {}; - propertyMap[target] = props; - } - props[propertyKey] = true; -} - -function getClassProperties(target: any) { - return propertyMap[target] || {}; -} - -function target(target: any, propertyKey?: string | symbol) { - if (typeof target === "object" && target.constructor) { - target = target.constructor; - } - if (propertyKey != null) { - attachProperty(target, propertyKey); - } - return target; -} -export const Decorator = { - target, - attachProperty, - getClassProperties, -}; +export * from "./utils"; +export * from "./common"; diff --git a/packages/core/pipeline/src/decorator/utils.ts b/packages/core/pipeline/src/decorator/utils.ts new file mode 100644 index 00000000..076b1e12 --- /dev/null +++ b/packages/core/pipeline/src/decorator/utils.ts @@ -0,0 +1,42 @@ +import _ from "lodash"; + +const propertyMap: any = {}; +function attachProperty(target: any, propertyKey: string | symbol) { + let props = propertyMap[target]; + if (props == null) { + props = {}; + propertyMap[target] = props; + } + props[propertyKey] = true; +} + +function getClassProperties(target: any) { + return propertyMap[target] || {}; +} + +function target(target: any, propertyKey?: string | symbol) { + if (typeof target === "object" && target.constructor) { + target = target.constructor; + } + if (propertyKey != null) { + attachProperty(target, propertyKey); + } + return target; +} + +function inject(define: any, instance: any, context: any, preHandler?: (item: any, key: string, instance: any, context: any) => void) { + _.forEach(define, (item, key) => { + if (preHandler) { + preHandler(item, key, instance, context); + } + if (context[key] != undefined) { + instance[key] = context[key]; + } + }); +} +export const Decorator = { + target, + attachProperty, + getClassProperties, + inject, +}; diff --git a/packages/core/pipeline/src/dns-provider/abstract-dns-provider.ts b/packages/core/pipeline/src/dns-provider/abstract-dns-provider.ts deleted file mode 100644 index 92454c0f..00000000 --- a/packages/core/pipeline/src/dns-provider/abstract-dns-provider.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { AbstractRegistrable } from "../registry"; -import { CreateRecordOptions, IDnsProvider, DnsProviderDefine, RemoveRecordOptions } from "./api"; -import { AbstractAccess } from "../access"; -import { Logger } from "log4js"; -import { AxiosInstance } from "axios"; -export abstract class AbstractDnsProvider extends AbstractRegistrable implements IDnsProvider { - access!: AbstractAccess; - logger!: Logger; - http!: AxiosInstance; - doInit(options: { access: AbstractAccess; logger: Logger; http: AxiosInstance }) { - this.access = options.access; - this.logger = options.logger; - this.http = options.http; - this.onInit(); - } - - protected abstract onInit(): void; - - abstract createRecord(options: CreateRecordOptions): Promise; - - abstract removeRecord(options: RemoveRecordOptions): Promise; -} diff --git a/packages/core/pipeline/src/index.ts b/packages/core/pipeline/src/index.ts index 28f928b7..91dd1a00 100644 --- a/packages/core/pipeline/src/index.ts +++ b/packages/core/pipeline/src/index.ts @@ -2,8 +2,8 @@ export * from "./core"; export * from "./d.ts"; export * from "./access"; export * from "./registry"; -export * from "./dns-provider"; export * from "./plugin"; export * from "./utils"; export * from "./midway"; export * from "./context"; +export * from "./decorator"; diff --git a/packages/core/pipeline/src/plugin/decorator.ts b/packages/core/pipeline/src/plugin/decorator.ts index 265a834f..f8f0a830 100644 --- a/packages/core/pipeline/src/plugin/decorator.ts +++ b/packages/core/pipeline/src/plugin/decorator.ts @@ -2,6 +2,7 @@ import _ from "lodash"; import { pluginRegistry } from "./registry"; import { PluginDefine, TaskInputDefine, TaskOutputDefine } from "./api"; import { Decorator } from "../decorator"; +import { AUTOWIRE_KEY } from "../decorator"; // 提供一个唯一 key export const PLUGIN_CLASS_KEY = "pipeline:plugin"; @@ -20,7 +21,7 @@ export function IsTaskPlugin(define: PluginDefine): ClassDecorator { inputs[property] = input; } - const autowire = Reflect.getMetadata(PLUGIN_AUTOWIRE_KEY, target, property); + const autowire = Reflect.getMetadata(AUTOWIRE_KEY, target, property); if (autowire) { autowires[property] = autowire; } @@ -59,19 +60,3 @@ export function TaskOutput(output?: TaskOutputDefine): PropertyDecorator { Reflect.defineMetadata(PLUGIN_OUTPUT_KEY, output, target, propertyKey); }; } - -export type AutowireProp = { - name?: string; - type?: any; -}; -export const PLUGIN_AUTOWIRE_KEY = "pipeline:plugin:autowire"; - -export function Autowire(props?: AutowireProp): PropertyDecorator { - return (target, propertyKey) => { - const _type = Reflect.getMetadata("design:type", target, propertyKey); - target = Decorator.target(target, propertyKey); - props = props || {}; - props.type = _type; - Reflect.defineMetadata(PLUGIN_AUTOWIRE_KEY, props || {}, target, propertyKey); - }; -} diff --git a/packages/core/pipeline/src/registry/registry.ts b/packages/core/pipeline/src/registry/registry.ts index 42fb2758..29d869c0 100644 --- a/packages/core/pipeline/src/registry/registry.ts +++ b/packages/core/pipeline/src/registry/registry.ts @@ -20,7 +20,7 @@ export class Registry { this.storage[key] = value; } - get(name: string) { + get(name: string): RegistryItem { if (!name) { throw new Error("插件名称不能为空"); } diff --git a/packages/core/pipeline/src/utils/util.log.ts b/packages/core/pipeline/src/utils/util.log.ts index 847ef828..0cfd0fa2 100644 --- a/packages/core/pipeline/src/utils/util.log.ts +++ b/packages/core/pipeline/src/utils/util.log.ts @@ -32,4 +32,4 @@ export function buildLogger(write: (text: string) => void) { }); return logger; } -export type LOGGER = Logger; +export type ILogger = Logger; diff --git a/packages/core/pipeline/test/echo-plugin.ts b/packages/core/pipeline/test/echo-plugin.ts index b169316e..f40a8d53 100644 --- a/packages/core/pipeline/test/echo-plugin.ts +++ b/packages/core/pipeline/test/echo-plugin.ts @@ -1,4 +1,4 @@ -import { IsTaskPlugin, TaskInput, ITaskPlugin, LOGGER, Autowire, TaskOutput } from "../src"; +import { IsTaskPlugin, TaskInput, ITaskPlugin, ILogger, Autowire, TaskOutput } from "../src"; @IsTaskPlugin({ name: "EchoPlugin", @@ -15,7 +15,7 @@ export class EchoPlugin implements ITaskPlugin { cert!: any; @Autowire() - logger!: LOGGER; + logger!: ILogger; @TaskOutput({ title: "cert info", diff --git a/packages/plugins/plugin-aliyun/.eslintrc b/packages/plugins/plugin-aliyun/.eslintrc index 218e910f..751e28ba 100644 --- a/packages/plugins/plugin-aliyun/.eslintrc +++ b/packages/plugins/plugin-aliyun/.eslintrc @@ -15,6 +15,7 @@ "@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/ban-ts-ignore": "off", "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-empty-function": "off", // "no-unused-expressions": "off", "max-len": [0, 160, 2, { "ignoreUrls": true }] } diff --git a/packages/plugins/plugin-aliyun/src/access/aliyun-access.ts b/packages/plugins/plugin-aliyun/src/access/aliyun-access.ts index 0dda30d2..05178321 100644 --- a/packages/plugins/plugin-aliyun/src/access/aliyun-access.ts +++ b/packages/plugins/plugin-aliyun/src/access/aliyun-access.ts @@ -1,4 +1,4 @@ -import { IsAccess, IsAccessInput } from "@certd/pipeline"; +import { IsAccess, AccessInput } from "@certd/pipeline"; @IsAccess({ name: "aliyun", @@ -6,7 +6,7 @@ import { IsAccess, IsAccessInput } from "@certd/pipeline"; desc: "", }) export class AliyunAccess { - @IsAccessInput({ + @AccessInput({ title: "accessKeyId", component: { placeholder: "accessKeyId", @@ -14,7 +14,7 @@ export class AliyunAccess { required: true, }) accessKeyId = ""; - @IsAccessInput({ + @AccessInput({ title: "accessKeySecret", component: { placeholder: "accessKeySecret", diff --git a/packages/plugins/plugin-aliyun/src/dns-provider/aliyun-dns-provider.ts b/packages/plugins/plugin-aliyun/src/dns-provider/aliyun-dns-provider.ts index b4696b7e..52f7a237 100644 --- a/packages/plugins/plugin-aliyun/src/dns-provider/aliyun-dns-provider.ts +++ b/packages/plugins/plugin-aliyun/src/dns-provider/aliyun-dns-provider.ts @@ -1,7 +1,8 @@ import Core from "@alicloud/pop-core"; import _ from "lodash"; -import { CreateRecordOptions, IDnsProvider, IsDnsProvider, RemoveRecordOptions } from "@certd/pipeline"; -import { Logger } from "log4js"; +import { CreateRecordOptions, IDnsProvider, IsDnsProvider, RemoveRecordOptions } from "@certd/plugin-cert"; +import { Autowire, ILogger } from "@certd/pipeline"; +import { AliyunAccess } from "../access"; @IsDnsProvider({ name: "aliyun", @@ -11,8 +12,10 @@ import { Logger } from "log4js"; }) export class AliyunDnsProvider implements IDnsProvider { client: any; - access: any; - logger!: Logger; + @Autowire() + access!: AliyunAccess; + @Autowire() + logger!: ILogger; async onInit() { const access: any = this.access; this.client = new Core({ diff --git a/packages/plugins/plugin-aliyun/src/plugin/deploy-to-ack-ingress/index.ts b/packages/plugins/plugin-aliyun/src/plugin/deploy-to-ack-ingress/index.ts index c02d0a9e..892bd979 100644 --- a/packages/plugins/plugin-aliyun/src/plugin/deploy-to-ack-ingress/index.ts +++ b/packages/plugins/plugin-aliyun/src/plugin/deploy-to-ack-ingress/index.ts @@ -1,101 +1,119 @@ -import { AbstractPlugin, IsTask, RunStrategy, TaskInput, TaskOutput, TaskPlugin, utils } from "@certd/pipeline"; +import { Autowire, IAccessService, IsTaskPlugin, ITaskPlugin, ILogger, RunStrategy, TaskInput, utils } from "@certd/pipeline"; // @ts-ignore import { ROAClient } from "@alicloud/pop-core"; import { AliyunAccess } from "../../access"; import { K8sClient } from "@certd/plugin-util"; import { appendTimeSuffix } from "../../utils"; +import { CertInfo } from "@certd/plugin-cert"; -@IsTask(() => { - return { - name: "DeployCertToAliyunAckIngress", - title: "部署到阿里云AckIngress", - input: { - clusterId: { - title: "集群id", - component: { - placeholder: "集群id", - }, - }, - secretName: { - title: "保密字典Id", - component: { - placeholder: "保密字典Id", - }, - required: true, - }, - regionId: { - title: "大区", - value: "cn-shanghai", - component: { - placeholder: "集群所属大区", - }, - required: true, - }, - namespace: { - title: "命名空间", - value: "default", - component: { - placeholder: "命名空间", - }, - required: true, - }, - ingressName: { - title: "ingress名称", - value: "", - component: { - placeholder: "ingress名称", - }, - required: true, - helper: "可以传入一个数组", - }, - ingressClass: { - title: "ingress类型", - value: "nginx", - component: { - placeholder: "暂时只支持nginx类型", - }, - required: true, - }, - isPrivateIpAddress: { - title: "是否私网ip", - value: false, - component: { - placeholder: "集群连接端点是否是私网ip", - }, - helper: "如果您当前certd运行在同一个私网下,可以选择是。", - required: true, - }, - cert: { - title: "域名证书", - helper: "请选择前置任务输出的域名证书", - component: { - name: "pi-output-selector", - }, - required: true, - }, - accessId: { - title: "Access授权", - helper: "阿里云授权AccessKeyId、AccessKeySecret", - component: { - name: "pi-access-selector", - type: "aliyun", - }, - required: true, - }, +@IsTaskPlugin({ + name: "DeployCertToAliyunAckIngress", + title: "部署到阿里云AckIngress", + input: {}, + output: {}, + default: { + strategy: { + runStrategy: RunStrategy.SkipWhenSucceed, }, - output: {}, - default: { - strategy: { - runStrategy: RunStrategy.SkipWhenSucceed, - }, - }, - }; + }, }) -export class DeployCertToAliyunAckIngressPlugin extends AbstractPlugin implements TaskPlugin { - async execute(input: TaskInput): Promise { +export class DeployCertToAliyunAckIngressPlugin implements ITaskPlugin { + @TaskInput({ + title: "集群id", + component: { + placeholder: "集群id", + }, + }) + clusterId!: string; + + @TaskInput({ + title: "保密字典Id", + component: { + placeholder: "保密字典Id", + }, + required: true, + }) + secretName!: string | string[]; + + @TaskInput({ + title: "大区", + value: "cn-shanghai", + component: { + placeholder: "集群所属大区", + }, + required: true, + }) + regionId!: string; + + @TaskInput({ + title: "命名空间", + value: "default", + component: { + placeholder: "命名空间", + }, + required: true, + }) + namespace!: string; + @TaskInput({ + title: "ingress名称", + value: "", + component: { + placeholder: "ingress名称", + }, + required: true, + helper: "可以传入一个数组", + }) + ingressName!: string; + @TaskInput({ + title: "ingress类型", + value: "nginx", + component: { + placeholder: "暂时只支持nginx类型", + }, + required: true, + }) + ingressClass!: string; + @TaskInput({ + title: "是否私网ip", + value: false, + component: { + placeholder: "集群连接端点是否是私网ip", + }, + helper: "如果您当前certd运行在同一个私网下,可以选择是。", + required: true, + }) + isPrivateIpAddress!: boolean; + @TaskInput({ + title: "域名证书", + helper: "请选择前置任务输出的域名证书", + component: { + name: "pi-output-selector", + }, + required: true, + }) + cert!: CertInfo; + @TaskInput({ + title: "Access授权", + helper: "阿里云授权AccessKeyId、AccessKeySecret", + component: { + name: "pi-access-selector", + type: "aliyun", + }, + required: true, + }) + accessId!: string; + + @Autowire() + accessService!: IAccessService; + @Autowire() + logger!: ILogger; + + // eslint-disable-next-line @typescript-eslint/no-empty-function + async onInit(): Promise {} + async execute(): Promise { console.log("开始部署证书到阿里云cdn"); - const { regionId, ingressClass, clusterId, isPrivateIpAddress, cert } = input; - const access = (await this.accessService.getById(input.accessId)) as AliyunAccess; + const { regionId, ingressClass, clusterId, isPrivateIpAddress, cert } = this; + const access = (await this.accessService.getById(this.accessId)) as AliyunAccess; const client = this.getClient(access, regionId); const kubeConfigStr = await this.getKubeConfig(client, clusterId, isPrivateIpAddress); @@ -106,17 +124,16 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractPlugin implement throw new Error("暂未实现"); // await this.patchQcloudCertSecret({ k8sClient, props, context }) } else { - await this.patchNginxCertSecret({ cert, k8sClient, input }); + await this.patchNginxCertSecret({ cert, k8sClient }); } await utils.sleep(3000); // 停留2秒,等待secret部署完成 // await this.restartIngress({ k8sClient, props }) - return {}; } - async restartIngress(options: { k8sClient: any; input: TaskInput }) { - const { k8sClient, input } = options; - const { namespace } = input; + async restartIngress(options: { k8sClient: any }) { + const { k8sClient } = options; + const { namespace } = this; const body = { metadata: { @@ -136,7 +153,7 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractPlugin implement return false; } for (const tls of item.spec.tls) { - if (tls.secretName === input.secretName) { + if (tls.secretName === this.secretName) { return true; } } @@ -151,14 +168,14 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractPlugin implement } } - async patchNginxCertSecret(options: { cert: any; k8sClient: any; input: TaskInput }) { - const { cert, k8sClient, input } = options; + async patchNginxCertSecret(options: { cert: any; k8sClient: any }) { + const { cert, k8sClient } = options; const crt = cert.crt; const key = cert.key; const crtBase64 = Buffer.from(crt).toString("base64"); const keyBase64 = Buffer.from(key).toString("base64"); - const { namespace, secretName } = input; + const { namespace, secretName } = this; const body = { data: { @@ -171,7 +188,7 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractPlugin implement }, }, }; - let secretNames = secretName; + let secretNames: any = secretName; if (typeof secretName === "string") { secretNames = [secretName]; } diff --git a/packages/plugins/plugin-aliyun/src/plugin/deploy-to-cdn/index.ts b/packages/plugins/plugin-aliyun/src/plugin/deploy-to-cdn/index.ts index daad4443..bfe5bc8a 100644 --- a/packages/plugins/plugin-aliyun/src/plugin/deploy-to-cdn/index.ts +++ b/packages/plugins/plugin-aliyun/src/plugin/deploy-to-cdn/index.ts @@ -1,9 +1,8 @@ -import { Autowire, IAccessService, IsTaskPlugin, ITaskPlugin, LOGGER, RunStrategy, TaskInput } from "@certd/pipeline"; +import { Autowire, IAccessService, ILogger, IsTaskPlugin, ITaskPlugin, RunStrategy, TaskInput } from "@certd/pipeline"; import dayjs from "dayjs"; import Core from "@alicloud/pop-core"; import RPCClient from "@alicloud/pop-core"; import { AliyunAccess } from "../../access"; -import { Inject } from "@midwayjs/core"; @IsTaskPlugin({ name: "DeployCertToAliyunCDN", @@ -50,11 +49,11 @@ export class DeployCertToAliyunCDN implements ITaskPlugin { }) accessId!: string; - @Inject() + @Autowire() accessService!: IAccessService; @Autowire() - logger!: LOGGER; + logger!: ILogger; // eslint-disable-next-line @typescript-eslint/no-empty-function async onInit() {} async execute(): Promise { diff --git a/packages/plugins/plugin-aliyun/src/plugin/upload-to-aliyun/index.ts b/packages/plugins/plugin-aliyun/src/plugin/upload-to-aliyun/index.ts index 680c4988..ea5737fa 100644 --- a/packages/plugins/plugin-aliyun/src/plugin/upload-to-aliyun/index.ts +++ b/packages/plugins/plugin-aliyun/src/plugin/upload-to-aliyun/index.ts @@ -17,7 +17,6 @@ import { Logger } from "log4js"; export class UploadCertToAliyun implements ITaskPlugin { @TaskInput({ title: "证书名称", - helper: "证书上传后将以此参数作为名称前缀", }) name!: string; @@ -66,6 +65,9 @@ export class UploadCertToAliyun implements ITaskPlugin { @Autowire() logger!: Logger; + // eslint-disable-next-line @typescript-eslint/no-empty-function + async onInit() {} + async execute(): Promise { console.log("开始部署证书到阿里云cdn"); const access = (await this.accessService.getById(this.accessId)) as AliyunAccess; diff --git a/packages/plugins/plugin-aliyun/src/plugins/deploy-to-ack-ingress/index.js b/packages/plugins/plugin-aliyun/src/plugins/deploy-to-ack-ingress/index.js deleted file mode 100644 index fe5738fe..00000000 --- a/packages/plugins/plugin-aliyun/src/plugins/deploy-to-ack-ingress/index.js +++ /dev/null @@ -1,199 +0,0 @@ -import { AbstractAliyunPlugin } from '../abstract-aliyun.js' -import Core from '@alicloud/pop-core' -import { K8sClient } from '@certd/plugin-common' -const ROAClient = Core.ROAClient - -const define = { - name: 'deployCertToAliyunAckIngress', - title: '部署到阿里云AckIngress', - input: { - clusterId: { - title: '集群id', - component: { - placeholder: '集群id' - } - }, - secretName: { - title: '保密字典Id', - component: { - placeholder: '保密字典Id' - }, - required: true - }, - regionId: { - title: '大区', - value: 'cn-shanghai', - component: { - placeholder: '集群所属大区' - }, - required: true - }, - namespace: { - title: '命名空间', - value: 'default', - component: { - placeholder: '命名空间' - }, - required: true - }, - ingressName: { - title: 'ingress名称', - value: '', - component: { - placeholder: 'ingress名称' - }, - required: true, - helper: '可以传入一个数组' - }, - ingressClass: { - title: 'ingress类型', - value: 'nginx', - component: { - placeholder: '暂时只支持nginx类型' - }, - required: true - }, - isPrivateIpAddress: { - title: '是否私网ip', - value: false, - component: { - placeholder: '集群连接端点是否是私网ip' - }, - helper: '如果您当前certd运行在同一个私网下,可以选择是。', - required: true - }, - accessProvider: { - title: 'Access授权', - type: [String, Object], - helper: 'AccessKey、AccessSecret', - component: { - name: 'access-selector', - type: 'aliyun' - }, - required: true - } - }, - output: { - - } -} - -export class DeployCertToAliyunAckIngress extends AbstractAliyunPlugin { - static define () { - return define - } - - async execute ({ cert, props, context }) { - const accessProvider = this.getAccessProvider(props.accessProvider) - const client = this.getClient(accessProvider, props.regionId) - - const kubeConfigStr = await this.getKubeConfig(client, props.clusterId, props.isPrivateIpAddress) - - this.logger.info('kubeconfig已成功获取') - const k8sClient = new K8sClient(kubeConfigStr) - const ingressType = props.ingressClass || 'qcloud' - if (ingressType === 'qcloud') { - throw new Error('暂未实现') - // await this.patchQcloudCertSecret({ k8sClient, props, context }) - } else { - await this.patchNginxCertSecret({ cert, k8sClient, props, context }) - } - - await this.sleep(3000) // 停留2秒,等待secret部署完成 - // await this.restartIngress({ k8sClient, props }) - return true - } - - async restartIngress ({ k8sClient, props }) { - const { namespace } = props - - const body = { - metadata: { - labels: { - certd: this.appendTimeSuffix('certd') - } - } - } - const ingressList = await k8sClient.getIngressList({ namespace }) - console.log('ingressList:', ingressList) - if (!ingressList || !ingressList.body || !ingressList.body.items) { - return - } - const ingressNames = ingressList.body.items.filter(item => { - if (!item.spec.tls) { - return false - } - for (const tls of item.spec.tls) { - if (tls.secretName === props.secretName) { - return true - } - } - return false - }).map(item => { - return item.metadata.name - }) - for (const ingress of ingressNames) { - await k8sClient.patchIngress({ namespace, ingressName: ingress, body }) - this.logger.info(`ingress已重启:${ingress}`) - } - } - - async patchNginxCertSecret ({ cert, k8sClient, props, context }) { - const crt = cert.crt - const key = cert.key - const crtBase64 = Buffer.from(crt).toString('base64') - const keyBase64 = Buffer.from(key).toString('base64') - - const { namespace, secretName } = props - - const body = { - data: { - 'tls.crt': crtBase64, - 'tls.key': keyBase64 - }, - metadata: { - labels: { - certd: this.appendTimeSuffix('certd') - } - } - } - let secretNames = secretName - if (typeof secretName === 'string') { - secretNames = [secretName] - } - for (const secret of secretNames) { - await k8sClient.patchSecret({ namespace, secretName: secret, body }) - this.logger.info(`CertSecret已更新:${secret}`) - } - } - - getClient (aliyunProvider, regionId) { - return new ROAClient({ - accessKeyId: aliyunProvider.accessKeyId, - accessKeySecret: aliyunProvider.accessKeySecret, - endpoint: `https://cs.${regionId}.aliyuncs.com`, - apiVersion: '2015-12-15' - }) - } - - async getKubeConfig (client, clusterId, isPrivateIpAddress = false) { - const httpMethod = 'GET' - const uriPath = `/k8s/${clusterId}/user_config` - const queries = { - PrivateIpAddress: isPrivateIpAddress - } - const body = '{}' - const headers = { - 'Content-Type': 'application/json' - } - const requestOption = {} - - try { - const res = await client.request(httpMethod, uriPath, queries, body, headers, requestOption) - return res.config - } catch (e) { - console.error('请求出错:', e) - throw e - } - } -} diff --git a/packages/plugins/plugin-aliyun/src/plugins/upload-to-aliyun/index.js b/packages/plugins/plugin-aliyun/src/plugins/upload-to-aliyun/index.js deleted file mode 100644 index e0128000..00000000 --- a/packages/plugins/plugin-aliyun/src/plugins/upload-to-aliyun/index.js +++ /dev/null @@ -1,106 +0,0 @@ -import Core from '@alicloud/pop-core' -import { AbstractAliyunPlugin } from '../abstract-aliyun.js' -import { ZoneOptions } from '../../utils/index.js' - -const define = { - name: 'uploadCertToAliyun', - title: '上传证书到阿里云', - desc: '', - input: { - name: { - title: '证书名称', - helper: '证书上传后将以此参数作为名称前缀' - }, - regionId: { - title: '大区', - value: 'cn-hangzhou', - component: { - name: 'a-select', - vModel: 'value', - options: ZoneOptions - }, - required: true - }, - accessProvider: { - title: 'Access授权', - helper: 'Access授权', - component: { - name: 'access-selector', - type: 'aliyun' - }, - required: true - } - }, - output: { - aliyunCertId: { - type: String, - desc: '上传成功后的阿里云CertId' - } - } -} - -export class UploadCertToAliyun extends AbstractAliyunPlugin { - static define () { - return define - } - - getClient (aliyunProvider) { - return new Core({ - accessKeyId: aliyunProvider.accessKeyId, - accessKeySecret: aliyunProvider.accessKeySecret, - endpoint: 'https://cas.aliyuncs.com', - apiVersion: '2018-07-13' - }) - } - - async execute ({ cert, props, context }) { - const { name, accessProvider } = props - const certName = this.appendTimeSuffix(name || cert.domain) - const params = { - RegionId: props.regionId || 'cn-hangzhou', - Name: certName, - Cert: cert.crt, - Key: cert.key - } - - const requestOption = { - method: 'POST' - } - - const provider = this.getAccessProvider(accessProvider) - const client = this.getClient(provider) - const ret = await client.request('CreateUserCertificate', params, requestOption) - this.checkRet(ret) - this.logger.info('证书上传成功:aliyunCertId=', ret.CertId) - context.aliyunCertId = ret.CertId - } - - /** - * 没用,现在阿里云证书不允许删除 - * @param accessProviders - * @param cert - * @param props - * @param context - * @returns {Promise} - */ - async rollback ({ cert, props, context }) { - const { accessProvider } = props - const { aliyunCertId } = context - this.logger.info('准备删除阿里云证书:', aliyunCertId) - const params = { - RegionId: props.regionId || 'cn-hangzhou', - CertId: aliyunCertId - } - - const requestOption = { - method: 'POST' - } - - const provider = this.getAccessProvider(accessProvider) - const client = this.getClient(provider) - const ret = await client.request('DeleteUserCertificate', params, requestOption) - this.checkRet(ret) - this.logger.info('证书删除成功:', aliyunCertId) - delete context.aliyunCertId - } -} diff --git a/packages/plugins/plugin-all/.eslintrc b/packages/plugins/plugin-all/.eslintrc index 218e910f..751e28ba 100644 --- a/packages/plugins/plugin-all/.eslintrc +++ b/packages/plugins/plugin-all/.eslintrc @@ -15,6 +15,7 @@ "@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/ban-ts-ignore": "off", "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-empty-function": "off", // "no-unused-expressions": "off", "max-len": [0, 160, 2, { "ignoreUrls": true }] } diff --git a/packages/plugins/plugin-all/src/index.ts b/packages/plugins/plugin-all/src/index.ts index 0a46928c..97fd09b7 100644 --- a/packages/plugins/plugin-all/src/index.ts +++ b/packages/plugins/plugin-all/src/index.ts @@ -1,4 +1,4 @@ -// export * from "@certd/plugin-aliyun"; export * from "@certd/plugin-cert"; +export * from "@certd/plugin-aliyun"; export * from "@certd/plugin-tencent"; -// export * from "@certd/plugin-host"; +export * from "@certd/plugin-host"; diff --git a/packages/plugins/plugin-cert/.eslintrc b/packages/plugins/plugin-cert/.eslintrc index 218e910f..751e28ba 100644 --- a/packages/plugins/plugin-cert/.eslintrc +++ b/packages/plugins/plugin-cert/.eslintrc @@ -15,6 +15,7 @@ "@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/ban-ts-ignore": "off", "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-empty-function": "off", // "no-unused-expressions": "off", "max-len": [0, 160, 2, { "ignoreUrls": true }] } diff --git a/packages/core/pipeline/src/dns-provider/api.ts b/packages/plugins/plugin-cert/src/dns-provider/api.ts similarity index 77% rename from packages/core/pipeline/src/dns-provider/api.ts rename to packages/plugins/plugin-cert/src/dns-provider/api.ts index 16e7ea01..3693f75f 100644 --- a/packages/core/pipeline/src/dns-provider/api.ts +++ b/packages/plugins/plugin-cert/src/dns-provider/api.ts @@ -1,7 +1,10 @@ -import { Registrable } from "../registry"; +import { Registrable } from "@certd/pipeline"; export type DnsProviderDefine = Registrable & { accessType: string; + autowire?: { + [key: string]: any; + }; }; export type CreateRecordOptions = { @@ -14,6 +17,7 @@ export type RemoveRecordOptions = CreateRecordOptions & { }; export interface IDnsProvider { + onInit(): Promise; createRecord(options: CreateRecordOptions): Promise; removeRecord(options: RemoveRecordOptions): Promise; } diff --git a/packages/core/pipeline/src/dns-provider/decorator.ts b/packages/plugins/plugin-cert/src/dns-provider/decorator.ts similarity index 57% rename from packages/core/pipeline/src/dns-provider/decorator.ts rename to packages/plugins/plugin-cert/src/dns-provider/decorator.ts index 1b1a1c54..7a560683 100644 --- a/packages/core/pipeline/src/dns-provider/decorator.ts +++ b/packages/plugins/plugin-cert/src/dns-provider/decorator.ts @@ -1,7 +1,8 @@ // src/decorator/memoryCache.decorator.ts import { dnsProviderRegistry } from "./registry"; import { DnsProviderDefine } from "./api"; -import { Decorator } from "../decorator"; +import { Decorator, AUTOWIRE_KEY } from "@certd/pipeline"; +import _ from "lodash"; // 提供一个唯一 key export const DNS_PROVIDER_CLASS_KEY = "pipeline:dns-provider"; @@ -9,6 +10,16 @@ export const DNS_PROVIDER_CLASS_KEY = "pipeline:dns-provider"; export function IsDnsProvider(define: DnsProviderDefine): ClassDecorator { return (target: any) => { target = Decorator.target(target); + const autowires: any = {}; + const properties = Decorator.getClassProperties(target); + for (const property in properties) { + const autowire = Reflect.getMetadata(AUTOWIRE_KEY, target, property); + if (autowire) { + autowires[property] = autowire; + } + } + _.merge(define, { autowire: autowires }); + Reflect.defineMetadata(DNS_PROVIDER_CLASS_KEY, define, target); target.define = define; diff --git a/packages/core/pipeline/src/dns-provider/index.ts b/packages/plugins/plugin-cert/src/dns-provider/index.ts similarity index 100% rename from packages/core/pipeline/src/dns-provider/index.ts rename to packages/plugins/plugin-cert/src/dns-provider/index.ts diff --git a/packages/core/pipeline/src/dns-provider/registry.ts b/packages/plugins/plugin-cert/src/dns-provider/registry.ts similarity index 60% rename from packages/core/pipeline/src/dns-provider/registry.ts rename to packages/plugins/plugin-cert/src/dns-provider/registry.ts index ff6cabd1..fe0c64d6 100644 --- a/packages/core/pipeline/src/dns-provider/registry.ts +++ b/packages/plugins/plugin-cert/src/dns-provider/registry.ts @@ -1,4 +1,4 @@ -import { Registry } from "../registry"; +import { Registry } from "@certd/pipeline"; // @ts-ignore export const dnsProviderRegistry = new Registry(); diff --git a/packages/plugins/plugin-cert/src/index.ts b/packages/plugins/plugin-cert/src/index.ts index 39b9a61b..6765bc10 100644 --- a/packages/plugins/plugin-cert/src/index.ts +++ b/packages/plugins/plugin-cert/src/index.ts @@ -1 +1,2 @@ export * from "./plugin"; +export * from "./dns-provider"; diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts index 5f918af1..07a65404 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts @@ -1,10 +1,10 @@ // @ts-ignore import * as acme from "@certd/acme-client"; import _ from "lodash"; -import { IDnsProvider } from "@certd/pipeline"; import { Challenge } from "@certd/acme-client/types/rfc8555"; import { Logger } from "log4js"; import { IContext } from "@certd/pipeline/src/core/context"; +import { IDnsProvider } from "../../dns-provider"; export class AcmeService { userContext: IContext; diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts index bd3266e7..e767b6f6 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts @@ -1,26 +1,46 @@ -import { - Autowire, - dnsProviderRegistry, - HttpClient, - IAccessService, - IContext, - IsTaskPlugin, - ITaskPlugin, - RunStrategy, - TaskInput, - TaskOutput, -} from "@certd/pipeline"; +import { Autowire, HttpClient, IAccessService, IContext, IsTaskPlugin, ITaskPlugin, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline"; import forge from "node-forge"; import dayjs from "dayjs"; import { AcmeService } from "./acme"; import _ from "lodash"; import { Logger } from "log4js"; - -export type CertInfo = { +import { Decorator } from "@certd/pipeline/src/decorator"; +import { DnsProviderDefine, dnsProviderRegistry } from "../../dns-provider"; +import fs from "fs"; +import os from "os"; +export class CertInfo { crt: string; key: string; csr: string; -}; + + detail: any; + expires: number; + constructor(opts: { crt: string; key: string; csr: string }) { + this.crt = opts.crt; + this.key = opts.key; + this.csr = opts.csr; + + const { detail, expires } = this.getCrtDetail(this.crt); + this.detail = detail; + this.expires = expires.getTime(); + } + + getCrtDetail(crt: string) { + const pki = forge.pki; + const detail = pki.certificateFromPem(crt.toString()); + const expires = detail.validity.notAfter; + return { detail, expires }; + } + + saveToFile(type: "crt" | "key", path?: string) { + if (path == null) { + //写入临时目录 + path = `${os.tmpdir()}/certd/tmp/${Math.floor(Math.random() * 1000000)}/cert.${type}`; + } + fs.writeFileSync(path, this[type]); + return path; + } +} @IsTaskPlugin({ name: "CertApply", title: "证书申请", @@ -199,11 +219,16 @@ export class CertApplyPlugin implements ITaskPlugin { ); this.logger.info("开始申请证书,", email, domains); - const dnsProviderClass = dnsProviderRegistry.get(dnsProviderType); + const dnsProviderPlugin = dnsProviderRegistry.get(dnsProviderType); + const DnsProviderClass = dnsProviderPlugin.target; + const dnsProviderDefine = dnsProviderPlugin.define as DnsProviderDefine; const access = await this.accessService.getById(dnsProviderAccessId); + // @ts-ignore - const dnsProvider: AbstractDnsProvider = new dnsProviderClass(); - dnsProvider.doInit({ access, logger: this.logger, http: this.http }); + const dnsProvider: IDnsProvider = new DnsProviderClass(); + const context = { access, logger: this.logger, http: this.http }; + Decorator.inject(dnsProviderDefine.autowire, dnsProvider, context); + await dnsProvider.onInit(); const cert = await this.acme.order({ email, @@ -239,23 +264,11 @@ export class CertApplyPlugin implements ITaskPlugin { } async readCurrentCert() { - const cert: CertInfo = await this.pipelineContext.get("cert"); + const cert: any = await this.pipelineContext.get("cert"); if (cert == null) { return undefined; } - const { detail, expires } = this.getCrtDetail(cert.crt); - return { - ...cert, - detail, - expires: expires.getTime(), - }; - } - - getCrtDetail(crt: string) { - const pki = forge.pki; - const detail = pki.certificateFromPem(crt.toString()); - const expires = detail.validity.notAfter; - return { detail, expires }; + return new CertInfo(cert); } /** diff --git a/packages/plugins/plugin-host/.eslintrc b/packages/plugins/plugin-host/.eslintrc index 218e910f..751e28ba 100644 --- a/packages/plugins/plugin-host/.eslintrc +++ b/packages/plugins/plugin-host/.eslintrc @@ -15,6 +15,7 @@ "@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/ban-ts-ignore": "off", "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-empty-function": "off", // "no-unused-expressions": "off", "max-len": [0, 160, 2, { "ignoreUrls": true }] } diff --git a/packages/plugins/plugin-host/package.json b/packages/plugins/plugin-host/package.json index 3ba37b79..218a91c5 100644 --- a/packages/plugins/plugin-host/package.json +++ b/packages/plugins/plugin-host/package.json @@ -15,31 +15,31 @@ "ssh2": "^0.8.9" }, "devDependencies": { - "log4js": "^6.7.1", - "dayjs": "^1.9.7", - "lodash-es": "^4.17.20", - "@types/lodash": "^4.14.186", - "vue-tsc": "^0.38.9", "@alicloud/cs20151215": "^3.0.3", "@alicloud/openapi-client": "^0.4.0", "@alicloud/pop-core": "^1.7.10", "@midwayjs/core": "^3.0.0", "@midwayjs/decorator": "^3.0.0", "@types/chai": "^4.3.3", + "@types/lodash": "^4.14.186", "@types/mocha": "^10.0.0", "@types/node-forge": "^1.3.0", + "@types/ssh2": "^1.11.6", "@typescript-eslint/eslint-plugin": "^5.38.1", "@typescript-eslint/parser": "^5.38.1", "chai": "^4.3.6", + "dayjs": "^1.9.7", "eslint": "^8.24.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-import": "^2.26.0", "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^4.2.1", + "lodash-es": "^4.17.20", "log4js": "^6.3.0", "mocha": "^10.1.0", "ts-node": "^10.9.1", "typescript": "^4.8.4", - "vite": "^3.1.0" + "vite": "^3.1.0", + "vue-tsc": "^0.38.9" } } diff --git a/packages/plugins/plugin-host/src/access/ssh-access.ts b/packages/plugins/plugin-host/src/access/ssh-access.ts index 7d81ef6e..51bee037 100644 --- a/packages/plugins/plugin-host/src/access/ssh-access.ts +++ b/packages/plugins/plugin-host/src/access/ssh-access.ts @@ -1,48 +1,47 @@ -import { AbstractAccess, IsAccess } from "@certd/pipeline"; +import { AccessInput, IAccess, IsAccess } from "@certd/pipeline"; @IsAccess({ name: "ssh", title: "主机登录授权", desc: "", - input: { - host: { - title: "主机地址", - component: { - placeholder: "主机域名或IP地址", - }, - required: true, - }, - port: { - title: "端口", - value: "22", - component: { - placeholder: "22", - }, - rules: [{ required: true, message: "此项必填" }], - }, - username: { - title: "用户名", - value: "root", - rules: [{ required: true, message: "此项必填" }], - }, - password: { - title: "密码", - component: { - name: "a-input-password", - vModel: "value", - }, - helper: "登录密码或密钥必填一项", - }, - privateKey: { - title: "密钥", - helper: "密钥或密码必填一项", - }, - }, + input: {}, }) -export class SshAccess extends AbstractAccess { - host = ""; - port = 22; - username = "root"; - password?: string; - privateKey?: string; +export class SshAccess implements IAccess { + @AccessInput({ + title: "主机地址", + component: { + placeholder: "主机域名或IP地址", + }, + required: true, + }) + host!: string; + @AccessInput({ + title: "端口", + value: "22", + component: { + placeholder: "22", + }, + rules: [{ required: true, message: "此项必填" }], + }) + port!: string; + @AccessInput({ + title: "用户名", + value: "root", + rules: [{ required: true, message: "此项必填" }], + }) + username!: string; + @AccessInput({ + title: "密码", + component: { + name: "a-input-password", + vModel: "value", + }, + helper: "登录密码或密钥必填一项", + }) + password!: string; + @AccessInput({ + title: "密钥", + helper: "密钥或密码必填一项", + }) + privateKey!: string; } diff --git a/packages/plugins/plugin-host/src/lib/ssh.ts b/packages/plugins/plugin-host/src/lib/ssh.ts index 191b11c5..79246d2d 100644 --- a/packages/plugins/plugin-host/src/lib/ssh.ts +++ b/packages/plugins/plugin-host/src/lib/ssh.ts @@ -1,10 +1,11 @@ +// @ts-ignore import ssh2 from "ssh2"; import path from "path"; import _ from "lodash"; -import { Logger } from "log4js"; +import { ILogger } from "@certd/pipeline"; export class SshClient { - logger: Logger; - constructor(logger: Logger) { + logger: ILogger; + constructor(logger: ILogger) { this.logger = logger; } /** diff --git a/packages/plugins/plugin-host/src/plugin/host-shell-execute/index.ts b/packages/plugins/plugin-host/src/plugin/host-shell-execute/index.ts index f9c31008..a8eff03e 100644 --- a/packages/plugins/plugin-host/src/plugin/host-shell-execute/index.ts +++ b/packages/plugins/plugin-host/src/plugin/host-shell-execute/index.ts @@ -1,47 +1,56 @@ -import { IsTask, TaskInput, TaskOutput, TaskPlugin, AbstractPlugin, RunStrategy } from "@certd/pipeline"; +import { Autowire, IAccessService, IsTaskPlugin, ILogger, RunStrategy, TaskInput, ITaskPlugin } from "@certd/pipeline"; import { SshClient } from "../../lib/ssh"; +import { CertInfo } from "@certd/plugin-cert"; -@IsTask(() => { - return { - name: "hostShellExecute", - title: "执行远程主机脚本命令", - input: { - accessId: { - title: "主机登录配置", - helper: "登录", - component: { - name: "pi-access-selector", - type: "ssh", - }, - required: true, - }, - cert: { - title: "域名证书", - helper: "请选择前置任务输出的域名证书", - component: { - name: "pi-output-selector", - }, - required: true, - }, - script: { - title: "shell脚本命令", - component: { - name: "a-textarea", - vModel: "value", - }, - }, +@IsTaskPlugin({ + name: "hostShellExecute", + title: "执行远程主机脚本命令", + input: {}, + default: { + strategy: { + runStrategy: RunStrategy.SkipWhenSucceed, }, - default: { - strategy: { - runStrategy: RunStrategy.SkipWhenSucceed, - }, - }, - output: {}, - }; + }, + output: {}, }) -export class HostShellExecutePlugin extends AbstractPlugin implements TaskPlugin { - async execute(input: TaskInput): Promise { - const { script, accessId } = input; +export class HostShellExecutePlugin implements ITaskPlugin { + @TaskInput({ + title: "主机登录配置", + helper: "登录", + component: { + name: "pi-access-selector", + type: "ssh", + }, + required: true, + }) + accessId!: string; + @TaskInput({ + title: "域名证书", + helper: "请选择前置任务输出的域名证书", + component: { + name: "pi-output-selector", + }, + required: true, + }) + cert!: CertInfo; + @TaskInput({ + title: "shell脚本命令", + component: { + name: "a-textarea", + vModel: "value", + }, + }) + script!: string; + + @Autowire() + accessService!: IAccessService; + @Autowire() + logger!: ILogger; + + // eslint-disable-next-line @typescript-eslint/no-empty-function + async onInit() {} + async execute(): Promise { + const { script, accessId } = this; const connectConf = this.accessService.getById(accessId); const sshClient = new SshClient(this.logger); const ret = await sshClient.exec({ @@ -49,6 +58,5 @@ export class HostShellExecutePlugin extends AbstractPlugin implements TaskPlugin script, }); this.logger.info("exec res:", ret); - return {}; } } diff --git a/packages/plugins/plugin-host/src/plugin/upload-to-host/index.ts b/packages/plugins/plugin-host/src/plugin/upload-to-host/index.ts index d99d94c9..967c0a5f 100644 --- a/packages/plugins/plugin-host/src/plugin/upload-to-host/index.ts +++ b/packages/plugins/plugin-host/src/plugin/upload-to-host/index.ts @@ -1,71 +1,87 @@ -import { IsTask, TaskInput, TaskOutput, TaskPlugin, AbstractPlugin, RunStrategy } from "@certd/pipeline"; +import { Autowire, IAccessService, IsTaskPlugin, ITaskPlugin, ILogger, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline"; import { SshClient } from "../../lib/ssh"; +import { CertInfo } from "@certd/plugin-cert"; +import * as fs from "fs"; -@IsTask(() => { - return { - name: "uploadCertToHost", - title: "上传证书到主机", - input: { - crtPath: { - title: "证书保存路径", - }, - keyPath: { - title: "私钥保存路径", - }, - cert: { - title: "域名证书", - helper: "请选择前置任务输出的域名证书", - component: { - name: "pi-output-selector", - }, - required: true, - }, - accessId: { - title: "主机登录配置", - helper: "access授权", - component: { - name: "pi-access-selector", - type: "ssh", - }, - rules: [{ required: true, message: "此项必填" }], - }, - sudo: { - title: "是否sudo", - component: { - name: "a-checkbox", - vModel: "checked", - }, - }, +@IsTaskPlugin({ + name: "uploadCertToHost", + title: "上传证书到主机", + default: { + strategy: { + runStrategy: RunStrategy.SkipWhenSucceed, }, - default: { - strategy: { - runStrategy: RunStrategy.SkipWhenSucceed, - }, - }, - output: { - hostCrtPath: { - title: "上传成功后的证书路径", - }, - hostKeyPath: { - title: "上传成功后的私钥路径", - }, - }, - }; + }, }) -export class UploadCertToHostPlugin extends AbstractPlugin implements TaskPlugin { - async execute(input: TaskInput): Promise { - const { crtPath, keyPath, cert, accessId, sudo } = input; +export class UploadCertToHostPlugin implements ITaskPlugin { + @TaskInput({ + title: "证书保存路径", + }) + crtPath!: string; + @TaskInput({ + title: "私钥保存路径", + }) + keyPath!: string; + @TaskInput({ + title: "域名证书", + helper: "请选择前置任务输出的域名证书", + component: { + name: "pi-output-selector", + }, + required: true, + }) + cert!: CertInfo; + @TaskInput({ + title: "主机登录配置", + helper: "access授权", + component: { + name: "pi-access-selector", + type: "ssh", + }, + rules: [{ required: true, message: "此项必填" }], + }) + accessId!: string; + @TaskInput({ + title: "是否sudo", + component: { + name: "a-checkbox", + vModel: "checked", + }, + }) + sudo!: boolean; + + @Autowire() + accessService!: IAccessService; + @Autowire() + logger!: ILogger; + + @TaskOutput({ + title: "证书保存路径", + }) + hostCrtPath!: string; + + @TaskOutput({ + title: "私钥保存路径", + }) + hostKeyPath!: string; + + async onInit() {} + async execute(): Promise { + const { crtPath, keyPath, cert, accessId, sudo } = this; const connectConf = this.accessService.getById(accessId); const sshClient = new SshClient(this.logger); + + const saveCrtPath = cert.saveToFile("crt"); + const saveKeyPath = cert.saveToFile("key"); + await sshClient.uploadFiles({ connectConf, transports: [ { - localPath: cert.crtPath, + localPath: saveCrtPath, remotePath: crtPath, }, { - localPath: cert.keyPath, + localPath: saveKeyPath, remotePath: keyPath, }, ], @@ -73,9 +89,12 @@ export class UploadCertToHostPlugin extends AbstractPlugin implements TaskPlugin }); this.logger.info("证书上传成功:crtPath=", crtPath, ",keyPath=", keyPath); - return { - hostCrtPath: crtPath, - hostKeyPath: keyPath, - }; + //删除临时文件 + fs.unlinkSync(saveCrtPath); + fs.unlinkSync(saveKeyPath); + + //输出 + this.hostCrtPath = crtPath; + this.hostKeyPath = keyPath; } } diff --git a/packages/plugins/plugin-tencent/.eslintrc b/packages/plugins/plugin-tencent/.eslintrc index 218e910f..751e28ba 100644 --- a/packages/plugins/plugin-tencent/.eslintrc +++ b/packages/plugins/plugin-tencent/.eslintrc @@ -15,6 +15,7 @@ "@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/ban-ts-ignore": "off", "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-empty-function": "off", // "no-unused-expressions": "off", "max-len": [0, 160, 2, { "ignoreUrls": true }] } diff --git a/packages/plugins/plugin-tencent/package.json b/packages/plugins/plugin-tencent/package.json index 24c07493..3961aec4 100644 --- a/packages/plugins/plugin-tencent/package.json +++ b/packages/plugins/plugin-tencent/package.json @@ -13,6 +13,7 @@ "dependencies": { "@certd/pipeline": "^0.3.0", "@certd/plugin-util": "^0.3.0", + "@certd/plugin-cert": "^0.3.0", "tencentcloud-sdk-nodejs": "^4.0.44" }, "devDependencies": { diff --git a/packages/plugins/plugin-tencent/src/access/dnspod-access.ts b/packages/plugins/plugin-tencent/src/access/dnspod-access.ts index 144adf51..b5429a2e 100644 --- a/packages/plugins/plugin-tencent/src/access/dnspod-access.ts +++ b/packages/plugins/plugin-tencent/src/access/dnspod-access.ts @@ -1,4 +1,4 @@ -import { IsAccess, IsAccessInput } from "@certd/pipeline"; +import { IsAccess, AccessInput } from "@certd/pipeline"; @IsAccess({ name: "dnspod", @@ -6,7 +6,7 @@ import { IsAccess, IsAccessInput } from "@certd/pipeline"; desc: "腾讯云的域名解析接口已迁移到dnspod", }) export class DnspodAccess { - @IsAccessInput({ + @AccessInput({ title: "token", component: { placeholder: "开放接口token", @@ -14,7 +14,7 @@ export class DnspodAccess { rules: [{ required: true, message: "该项必填" }], }) token = ""; - @IsAccessInput({ + @AccessInput({ title: "账户id", component: { placeholder: "dnspod接口账户id", diff --git a/packages/plugins/plugin-tencent/src/access/tencent-access.ts b/packages/plugins/plugin-tencent/src/access/tencent-access.ts index 6df676e1..27ba8d9f 100644 --- a/packages/plugins/plugin-tencent/src/access/tencent-access.ts +++ b/packages/plugins/plugin-tencent/src/access/tencent-access.ts @@ -1,11 +1,11 @@ -import { IsAccess, IsAccessInput } from "@certd/pipeline"; +import { IsAccess, AccessInput } from "@certd/pipeline"; @IsAccess({ name: "tencent", title: "腾讯云", }) export class TencentAccess { - @IsAccessInput({ + @AccessInput({ title: "secretId", component: { placeholder: "secretId", @@ -13,7 +13,7 @@ export class TencentAccess { rules: [{ required: true, message: "该项必填" }], }) secretId = ""; - @IsAccessInput({ + @AccessInput({ title: "secretKey", component: { placeholder: "secretKey", diff --git a/packages/plugins/plugin-tencent/src/dns-provider/dnspod-dns-provider.ts b/packages/plugins/plugin-tencent/src/dns-provider/dnspod-dns-provider.ts index a6efba69..a745a51d 100644 --- a/packages/plugins/plugin-tencent/src/dns-provider/dnspod-dns-provider.ts +++ b/packages/plugins/plugin-tencent/src/dns-provider/dnspod-dns-provider.ts @@ -1,8 +1,7 @@ -import { CreateRecordOptions, HttpClient, IDnsProvider, IsDnsProvider, RemoveRecordOptions } from "@certd/pipeline"; +import { Autowire, HttpClient, ILogger } from "@certd/pipeline"; +import { CreateRecordOptions, IDnsProvider, IsDnsProvider, RemoveRecordOptions } from "@certd/plugin-cert"; import _ from "lodash"; import { DnspodAccess } from "../access"; -import { Inject } from "@midwayjs/decorator"; -import { ILogger } from "@midwayjs/core"; @IsDnsProvider({ name: "dnspod", @@ -11,12 +10,12 @@ import { ILogger } from "@midwayjs/core"; accessType: "dnspod", }) export class DnspodDnsProvider implements IDnsProvider { - @Inject() + @Autowire() http!: HttpClient; - @Inject() + @Autowire() access!: DnspodAccess; - @Inject() + @Autowire() logger!: ILogger; loginToken: any; diff --git a/packages/plugins/plugin-tencent/src/plugin/deploy-to-cdn/index.ts b/packages/plugins/plugin-tencent/src/plugin/deploy-to-cdn/index.ts index 102443a8..8fecb5a6 100644 --- a/packages/plugins/plugin-tencent/src/plugin/deploy-to-cdn/index.ts +++ b/packages/plugins/plugin-tencent/src/plugin/deploy-to-cdn/index.ts @@ -1,7 +1,7 @@ -import { IAccessService, IsTaskPlugin, RunStrategy, TaskInput, ITaskPlugin, LOGGER } from "@certd/pipeline"; +import { Autowire, IAccessService, IsTaskPlugin, ITaskPlugin, ILogger, RunStrategy, TaskInput } from "@certd/pipeline"; import tencentcloud from "tencentcloud-sdk-nodejs/index"; import { TencentAccess } from "../../access"; -import { Inject } from "@midwayjs/decorator"; +import { CertInfo } from "@certd/plugin-cert"; @IsTaskPlugin({ name: "DeployCertToTencentCDN", @@ -22,7 +22,7 @@ export class DeployToCdnPlugin implements ITaskPlugin { }, required: true, }) - cert!: any; + cert!: CertInfo; @TaskInput({ title: "Access提供者", @@ -47,11 +47,11 @@ export class DeployToCdnPlugin implements ITaskPlugin { }) domainName!: string; - @Inject() + @Autowire() accessService!: IAccessService; - @Inject() - logger!: LOGGER; + @Autowire() + logger!: ILogger; // eslint-disable-next-line @typescript-eslint/no-empty-function async onInit() {} diff --git a/packages/plugins/plugin-tencent/src/plugin/deploy-to-clb/index.ts b/packages/plugins/plugin-tencent/src/plugin/deploy-to-clb/index.ts index 70eb4de5..a8cf7609 100644 --- a/packages/plugins/plugin-tencent/src/plugin/deploy-to-clb/index.ts +++ b/packages/plugins/plugin-tencent/src/plugin/deploy-to-clb/index.ts @@ -1,8 +1,7 @@ -import { IAccessService, IsTaskPlugin, ITaskPlugin, LOGGER, RunStrategy, TaskInput, utils } from "@certd/pipeline"; +import { Autowire, IAccessService, IsTaskPlugin, ITaskPlugin, ILogger, RunStrategy, TaskInput, utils } from "@certd/pipeline"; import tencentcloud from "tencentcloud-sdk-nodejs/index"; import { TencentAccess } from "../../access"; import dayjs from "dayjs"; -import { Inject } from "@midwayjs/decorator"; @IsTaskPlugin({ name: "DeployCertToTencentCLB", @@ -72,11 +71,11 @@ export class DeployToClbPlugin implements ITaskPlugin { }) accessId!: string; - @Inject() + @Autowire() accessService!: IAccessService; - @Inject() - logger!: LOGGER; + @Autowire() + logger!: ILogger; // eslint-disable-next-line @typescript-eslint/no-empty-function async onInit() {} diff --git a/packages/plugins/plugin-tencent/src/plugin/upload-to-tencent/index.ts b/packages/plugins/plugin-tencent/src/plugin/upload-to-tencent/index.ts index 6514b92b..67f2f77f 100644 --- a/packages/plugins/plugin-tencent/src/plugin/upload-to-tencent/index.ts +++ b/packages/plugins/plugin-tencent/src/plugin/upload-to-tencent/index.ts @@ -1,4 +1,4 @@ -import { Autowire, IAccessService, IsTaskPlugin, ITaskPlugin, RunStrategy, TaskInput, TaskOutput, LOGGER } from "@certd/pipeline"; +import { Autowire, IAccessService, IsTaskPlugin, ITaskPlugin, RunStrategy, TaskInput, TaskOutput, ILogger } from "@certd/pipeline"; import tencentcloud from "tencentcloud-sdk-nodejs/index"; import dayjs from "dayjs"; @@ -46,7 +46,7 @@ export class UploadToTencentPlugin implements ITaskPlugin { accessService!: IAccessService; @Autowire() - logger!: LOGGER; + logger!: ILogger; // eslint-disable-next-line @typescript-eslint/no-empty-function async onInit() {} diff --git a/packages/plugins/plugin-util/.eslintrc b/packages/plugins/plugin-util/.eslintrc index 218e910f..751e28ba 100644 --- a/packages/plugins/plugin-util/.eslintrc +++ b/packages/plugins/plugin-util/.eslintrc @@ -15,6 +15,7 @@ "@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/ban-ts-ignore": "off", "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-empty-function": "off", // "no-unused-expressions": "off", "max-len": [0, 160, 2, { "ignoreUrls": true }] } diff --git a/packages/server/certd-client b/packages/server/certd-client index b7422ab4..8c7b3853 160000 --- a/packages/server/certd-client +++ b/packages/server/certd-client @@ -1 +1 @@ -Subproject commit b7422ab48ef81f5c98129bacb69d0eefdfe50645 +Subproject commit 8c7b3853be27df392dff765d39c6c53de09418bd diff --git a/packages/server/certd-server b/packages/server/certd-server index 5901fb5a..a5681f15 160000 --- a/packages/server/certd-server +++ b/packages/server/certd-server @@ -1 +1 @@ -Subproject commit 5901fb5a440a7cebe3a2b6dfaec1b014e30b3a0c +Subproject commit a5681f154468fc5c4aac7e4a0ce090cfffc00e9e