mirror of https://github.com/certd/certd
perf: 创建证书任务可以选择lege插件
parent
4afbf20c1a
commit
affef13037
|
@ -23,6 +23,7 @@ export type TaskInputDefine = FormItemProps;
|
||||||
|
|
||||||
export type PluginDefine = Registrable & {
|
export type PluginDefine = Registrable & {
|
||||||
default?: any;
|
default?: any;
|
||||||
|
group?: string;
|
||||||
input?: {
|
input?: {
|
||||||
[key: string]: TaskInputDefine;
|
[key: string]: TaskInputDefine;
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { PluginDefine } from "./api";
|
||||||
|
|
||||||
|
export class PluginGroup {
|
||||||
|
key: string;
|
||||||
|
title: string;
|
||||||
|
desc?: string;
|
||||||
|
order: number;
|
||||||
|
plugins: PluginDefine[];
|
||||||
|
constructor(key: string, title: string, order = 0, desc = "") {
|
||||||
|
this.key = key;
|
||||||
|
this.title = title;
|
||||||
|
this.order = order;
|
||||||
|
this.desc = desc;
|
||||||
|
this.plugins = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const pluginGroups = {
|
||||||
|
cert: new PluginGroup("cert", "证书申请", 1),
|
||||||
|
aliyun: new PluginGroup("aliyun", "阿里云", 2),
|
||||||
|
huawei: new PluginGroup("huawei", "华为云", 3),
|
||||||
|
tencent: new PluginGroup("tencent", "腾讯云", 4),
|
||||||
|
host: new PluginGroup("host", "主机", 5),
|
||||||
|
other: new PluginGroup("other", "其他", 7),
|
||||||
|
};
|
|
@ -1,3 +1,4 @@
|
||||||
export * from "./api.js";
|
export * from "./api.js";
|
||||||
export * from "./registry.js";
|
export * from "./registry.js";
|
||||||
export * from "./decorator.js";
|
export * from "./decorator.js";
|
||||||
|
export * from "./group.js";
|
||||||
|
|
|
@ -1,4 +1,16 @@
|
||||||
import { Registry } from "../registry/index.js";
|
import { OnRegisterContext, Registry } from "../registry/index.js";
|
||||||
import { AbstractTaskPlugin } from "./api.js";
|
import { AbstractTaskPlugin } from "./api.js";
|
||||||
|
import { pluginGroups } from "./group.js";
|
||||||
|
|
||||||
export const pluginRegistry = new Registry<AbstractTaskPlugin>("plugin");
|
const onRegister = ({ key, value }: OnRegisterContext<AbstractTaskPlugin>) => {
|
||||||
|
const group = value?.define?.group as string;
|
||||||
|
if (group) {
|
||||||
|
if (pluginGroups.hasOwnProperty(group)) {
|
||||||
|
// @ts-ignore
|
||||||
|
pluginGroups[group].plugins.push(value.define);
|
||||||
|
} else {
|
||||||
|
pluginGroups.other.plugins.push(value.define);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export const pluginRegistry = new Registry<AbstractTaskPlugin>("plugin", onRegister);
|
||||||
|
|
|
@ -4,20 +4,31 @@ export type Registrable = {
|
||||||
name: string;
|
name: string;
|
||||||
title: string;
|
title: string;
|
||||||
desc?: string;
|
desc?: string;
|
||||||
|
group?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RegistryItem<T> = {
|
export type RegistryItem<T> = {
|
||||||
define: Registrable;
|
define: Registrable;
|
||||||
target: T;
|
target: T;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type OnRegisterContext<T> = {
|
||||||
|
registry: Registry<T>;
|
||||||
|
key: string;
|
||||||
|
value: RegistryItem<T>;
|
||||||
|
};
|
||||||
|
export type OnRegister<T> = (ctx: OnRegisterContext<T>) => void;
|
||||||
export class Registry<T> {
|
export class Registry<T> {
|
||||||
type = "";
|
type = "";
|
||||||
storage: {
|
storage: {
|
||||||
[key: string]: RegistryItem<T>;
|
[key: string]: RegistryItem<T>;
|
||||||
} = {};
|
} = {};
|
||||||
|
|
||||||
constructor(type: string) {
|
onRegister?: OnRegister<T>;
|
||||||
|
|
||||||
|
constructor(type: string, onRegister?: OnRegister<T>) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.onRegister = onRegister;
|
||||||
}
|
}
|
||||||
|
|
||||||
register(key: string, value: RegistryItem<T>) {
|
register(key: string, value: RegistryItem<T>) {
|
||||||
|
@ -25,6 +36,13 @@ export class Registry<T> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.storage[key] = value;
|
this.storage[key] = value;
|
||||||
|
if (this.onRegister) {
|
||||||
|
this.onRegister({
|
||||||
|
registry: this,
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
}
|
||||||
logger.info(`注册插件:${this.type}:${key}`);
|
logger.info(`注册插件:${this.type}:${key}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||||
col: {
|
col: {
|
||||||
span: 24,
|
span: 24,
|
||||||
},
|
},
|
||||||
|
order: -1,
|
||||||
helper:
|
helper:
|
||||||
"1、支持通配符域名,例如: *.foo.com、foo.com、*.test.handsfree.work\n" +
|
"1、支持通配符域名,例如: *.foo.com、foo.com、*.test.handsfree.work\n" +
|
||||||
"2、支持多个域名、多个子域名、多个通配符域名打到一个证书上(域名必须是在同一个DNS提供商解析)\n" +
|
"2、支持多个域名、多个子域名、多个通配符域名打到一个证书上(域名必须是在同一个DNS提供商解析)\n" +
|
||||||
|
@ -36,12 +37,14 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||||
vModel: "value",
|
vModel: "value",
|
||||||
},
|
},
|
||||||
required: true,
|
required: true,
|
||||||
|
order: -1,
|
||||||
helper: "请输入邮箱",
|
helper: "请输入邮箱",
|
||||||
})
|
})
|
||||||
email!: string;
|
email!: string;
|
||||||
|
|
||||||
@TaskInput({
|
@TaskInput({
|
||||||
title: "更新天数",
|
title: "更新天数",
|
||||||
|
value: 20,
|
||||||
component: {
|
component: {
|
||||||
name: "a-input-number",
|
name: "a-input-number",
|
||||||
vModel: "value",
|
vModel: "value",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Decorator, IsTaskPlugin, RunStrategy, TaskInput } from "@certd/pipeline";
|
import { Decorator, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
||||||
import type { CertInfo, SSLProvider } from "./acme.js";
|
import type { CertInfo, SSLProvider } from "./acme.js";
|
||||||
import { AcmeService } from "./acme.js";
|
import { AcmeService } from "./acme.js";
|
||||||
import _ from "lodash-es";
|
import _ from "lodash-es";
|
||||||
|
@ -11,7 +11,8 @@ export type { CertInfo };
|
||||||
|
|
||||||
@IsTaskPlugin({
|
@IsTaskPlugin({
|
||||||
name: "CertApply",
|
name: "CertApply",
|
||||||
title: "证书申请",
|
title: "证书申请(JS版)",
|
||||||
|
group: pluginGroups.cert.key,
|
||||||
desc: "免费通配符域名证书申请,支持多个域名打到同一个证书上",
|
desc: "免费通配符域名证书申请,支持多个域名打到同一个证书上",
|
||||||
default: {
|
default: {
|
||||||
input: {
|
input: {
|
||||||
|
@ -46,6 +47,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||||
name: "pi-access-selector",
|
name: "pi-access-selector",
|
||||||
type: "eab",
|
type: "eab",
|
||||||
},
|
},
|
||||||
|
maybeNeed: true,
|
||||||
helper: "如果使用ZeroSSL证书,需要提供EAB授权, 请前往 https://app.zerossl.com/developer 生成 'EAB Credentials for ACME Clients' ",
|
helper: "如果使用ZeroSSL证书,需要提供EAB授权, 请前往 https://app.zerossl.com/developer 生成 'EAB Credentials for ACME Clients' ",
|
||||||
})
|
})
|
||||||
eabAccessId!: number;
|
eabAccessId!: number;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { IsTaskPlugin, RunStrategy, sp, Step, TaskInput } from "@certd/pipeline";
|
import { IsTaskPlugin, pluginGroups, RunStrategy, sp, Step, TaskInput } from "@certd/pipeline";
|
||||||
import type { CertInfo } from "./acme.js";
|
import type { CertInfo } from "./acme.js";
|
||||||
import { CertReader } from "./cert-reader.js";
|
import { CertReader } from "./cert-reader.js";
|
||||||
import { CertApplyBasePlugin } from "./base.js";
|
import { CertApplyBasePlugin } from "./base.js";
|
||||||
|
@ -12,7 +12,8 @@ export type { CertInfo };
|
||||||
@IsTaskPlugin({
|
@IsTaskPlugin({
|
||||||
name: "CertApplyLego",
|
name: "CertApplyLego",
|
||||||
title: "证书申请(Lego)",
|
title: "证书申请(Lego)",
|
||||||
desc: "支持海量DNS解析提供商,推荐使用",
|
group: pluginGroups.cert.key,
|
||||||
|
desc: "支持海量DNS解析提供商,推荐使用,一样的免费通配符域名证书申请,支持多个域名打到同一个证书上",
|
||||||
default: {
|
default: {
|
||||||
input: {
|
input: {
|
||||||
renewDays: 20,
|
renewDays: 20,
|
||||||
|
@ -29,7 +30,9 @@ export class CertApplyLegoPlugin extends CertApplyBasePlugin {
|
||||||
component: {
|
component: {
|
||||||
name: "a-input",
|
name: "a-input",
|
||||||
vModel: "value",
|
vModel: "value",
|
||||||
|
placeholder: "alidns",
|
||||||
},
|
},
|
||||||
|
helper: "你的域名是通过哪家提供商进行解析的,具体应该配置什么请参考lego文档:https://go-acme.github.io/lego/dns/",
|
||||||
required: true,
|
required: true,
|
||||||
})
|
})
|
||||||
dnsType!: string;
|
dnsType!: string;
|
||||||
|
@ -39,7 +42,8 @@ export class CertApplyLegoPlugin extends CertApplyBasePlugin {
|
||||||
component: {
|
component: {
|
||||||
name: "a-textarea",
|
name: "a-textarea",
|
||||||
vModel: "value",
|
vModel: "value",
|
||||||
rows: 6,
|
rows: 4,
|
||||||
|
placeholder: "ALICLOUD_ACCESS_KEY=abcdefghijklmnopqrstuvwx\nALICLOUD_SECRET_KEY=your-secret-key",
|
||||||
},
|
},
|
||||||
required: true,
|
required: true,
|
||||||
helper: "一行一条,例如 appKeyId=xxxxx,具体配置请参考lego文档:https://go-acme.github.io/lego/dns/",
|
helper: "一行一条,例如 appKeyId=xxxxx,具体配置请参考lego文档:https://go-acme.github.io/lego/dns/",
|
||||||
|
@ -52,16 +56,20 @@ export class CertApplyLegoPlugin extends CertApplyBasePlugin {
|
||||||
name: "pi-access-selector",
|
name: "pi-access-selector",
|
||||||
type: "eab",
|
type: "eab",
|
||||||
},
|
},
|
||||||
|
maybeNeed: true,
|
||||||
helper: "如果需要提供EAB授权",
|
helper: "如果需要提供EAB授权",
|
||||||
})
|
})
|
||||||
eabAccessId!: number;
|
legoEabAccessId!: number;
|
||||||
|
|
||||||
@TaskInput({
|
@TaskInput({
|
||||||
title: "自定义LEGO参数",
|
title: "自定义LEGO参数",
|
||||||
component: {
|
component: {
|
||||||
name: "a-input",
|
name: "a-input",
|
||||||
vModel: "value",
|
vModel: "value",
|
||||||
|
placeholder: "--dns-timeout 30",
|
||||||
},
|
},
|
||||||
|
helper: "额外的lego命令行参数,参考文档:https://go-acme.github.io/lego/usage/cli/options/",
|
||||||
|
maybeNeed: true,
|
||||||
})
|
})
|
||||||
customArgs = "";
|
customArgs = "";
|
||||||
|
|
||||||
|
@ -73,8 +81,8 @@ export class CertApplyLegoPlugin extends CertApplyBasePlugin {
|
||||||
this.userContext = this.ctx.userContext;
|
this.userContext = this.ctx.userContext;
|
||||||
this.http = this.ctx.http;
|
this.http = this.ctx.http;
|
||||||
this.lastStatus = this.ctx.lastStatus as Step;
|
this.lastStatus = this.ctx.lastStatus as Step;
|
||||||
if (this.eabAccessId) {
|
if (this.legoEabAccessId) {
|
||||||
this.eab = await this.ctx.accessService.getById(this.eabAccessId);
|
this.eab = await this.ctx.accessService.getById(this.legoEabAccessId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async onInit(): Promise<void> {}
|
async onInit(): Promise<void> {}
|
||||||
|
|
|
@ -5,7 +5,7 @@ RUN npm install -g pnpm@8.15.7 --registry=https://registry.npmmirror.com
|
||||||
RUN pnpm config set registry https://registry.npmmirror.com/
|
RUN pnpm config set registry https://registry.npmmirror.com/
|
||||||
|
|
||||||
RUN cd /workspace/certd-client && pnpm install && npm run build
|
RUN cd /workspace/certd-client && pnpm install && npm run build
|
||||||
RUN cd /workspace/certd-server && pnpm install && npm run build
|
RUN cd /workspace/certd-server && pnpm install && npm run build-on-docker
|
||||||
|
|
||||||
RUN cp /workspace/certd-client/dist/* /workspace/certd-server/public/ -rf
|
RUN cp /workspace/certd-client/dist/* /workspace/certd-server/public/ -rf
|
||||||
|
|
||||||
|
|
|
@ -9,12 +9,7 @@ const defaultInputDefine = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function GetList(query: any) {
|
function initPlugins(plugins: any) {
|
||||||
const plugins = await request({
|
|
||||||
url: apiPrefix + "/list",
|
|
||||||
method: "post",
|
|
||||||
params: query
|
|
||||||
});
|
|
||||||
for (const plugin of plugins) {
|
for (const plugin of plugins) {
|
||||||
for (const key in plugin.input) {
|
for (const key in plugin.input) {
|
||||||
const field = _.merge({}, defaultInputDefine, plugin.input[key]);
|
const field = _.merge({}, defaultInputDefine, plugin.input[key]);
|
||||||
|
@ -24,7 +19,7 @@ export async function GetList(query: any) {
|
||||||
//嵌套对象
|
//嵌套对象
|
||||||
field.key = ["input", key];
|
field.key = ["input", key];
|
||||||
if (field.required) {
|
if (field.required) {
|
||||||
delete field.required;
|
// delete field.required;
|
||||||
if (field.rules == null) {
|
if (field.rules == null) {
|
||||||
field.rules = [];
|
field.rules = [];
|
||||||
}
|
}
|
||||||
|
@ -34,5 +29,28 @@ export async function GetList(query: any) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log("plugins", plugins);
|
console.log("plugins", plugins);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function GetList(query: any) {
|
||||||
|
const plugins = await request({
|
||||||
|
url: apiPrefix + "/list",
|
||||||
|
method: "post",
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
initPlugins(plugins);
|
||||||
return plugins;
|
return plugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function GetGroups(query: any) {
|
||||||
|
const groups = await request({
|
||||||
|
url: apiPrefix + "/groups",
|
||||||
|
method: "post",
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
const plugins: any = [];
|
||||||
|
for (const groupKey in groups) {
|
||||||
|
plugins.push(...groups[groupKey].plugins);
|
||||||
|
}
|
||||||
|
initPlugins(plugins);
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,39 @@
|
||||||
import { compute, CreateCrudOptionsProps, CreateCrudOptionsRet } from "@fast-crud/fast-crud";
|
import { compute, CreateCrudOptionsRet, dict } from "@fast-crud/fast-crud";
|
||||||
import { Dicts } from "./dicts";
|
import { PluginGroup } from "@certd/pipeline";
|
||||||
|
|
||||||
|
export default function (certPluginGroup: PluginGroup, formWrapperRef: any): CreateCrudOptionsRet {
|
||||||
|
const inputs: any = {};
|
||||||
|
|
||||||
|
for (const plugin of certPluginGroup.plugins) {
|
||||||
|
for (const inputKey in plugin.input) {
|
||||||
|
if (inputs[inputKey]) {
|
||||||
|
inputs[inputKey].form.show = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const inputDefine = plugin.input[inputKey];
|
||||||
|
if (!inputDefine.required && !inputDefine.maybeNeed) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
inputs[inputKey] = {
|
||||||
|
title: inputDefine.title,
|
||||||
|
form: {
|
||||||
|
...inputDefine,
|
||||||
|
show: compute((ctx) => {
|
||||||
|
console.log(formWrapperRef);
|
||||||
|
const form = formWrapperRef.value.getFormData();
|
||||||
|
if (!form) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return form?.certApplyPlugin === plugin.name;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(inputs);
|
||||||
|
debugger;
|
||||||
|
|
||||||
export default function (): CreateCrudOptionsRet {
|
|
||||||
return {
|
return {
|
||||||
crudOptions: {
|
crudOptions: {
|
||||||
form: {
|
form: {
|
||||||
|
@ -10,143 +42,31 @@ export default function (): CreateCrudOptionsRet {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
columns: {
|
columns: {
|
||||||
domains: {
|
certApplyPlugin: {
|
||||||
title: "域名",
|
title: "证书申请插件",
|
||||||
type: "dict-select",
|
type: "dict-select",
|
||||||
search: {
|
dict: dict({
|
||||||
show: true,
|
data: [
|
||||||
component: {
|
{ value: "CertApply", label: "JS-ACME" },
|
||||||
name: "a-input"
|
{ value: "CertApplyLego", label: "Lego-ACME" }
|
||||||
}
|
]
|
||||||
},
|
}),
|
||||||
form: {
|
form: {
|
||||||
col: {
|
order: 0,
|
||||||
span: 24
|
value: "CertApply",
|
||||||
},
|
|
||||||
wrapperCol: {
|
|
||||||
span: null
|
|
||||||
},
|
|
||||||
component: {
|
|
||||||
mode: "tags",
|
|
||||||
open: false
|
|
||||||
},
|
|
||||||
helper: {
|
helper: {
|
||||||
render: () => {
|
render: () => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<ul>
|
||||||
<div>支持通配符域名,例如: *.foo.com 、 *.test.handsfree.work</div>
|
<li>Lego-ACME:基于Lego实现,支持海量DNS提供商</li>
|
||||||
<div>支持多个域名、多个子域名、多个通配符域名打到一个证书上(域名必须是在同一个DNS提供商解析)</div>
|
<li>JS-ACME:如果你的域名DNS属于阿里云、腾讯云、Cloudflare可以选择用它来申请</li>
|
||||||
<div>多级子域名要分成多个域名输入(*.foo.com的证书不能用于xxx.yyy.foo.com)</div>
|
</ul>
|
||||||
<div>输入一个回车之后,再输入下一个</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
valueResolve({ form }) {
|
|
||||||
if (form.domains instanceof String) {
|
|
||||||
form.domains = form.domains?.join(",");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
rules: [{ required: true, message: "请填写域名" }]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
email: {
|
|
||||||
title: "邮箱",
|
|
||||||
type: "text",
|
|
||||||
search: { show: false },
|
|
||||||
form: {
|
|
||||||
rules: [{ required: true, type: "email", message: "请填写邮箱" }]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
blank: {
|
|
||||||
title: "占位",
|
|
||||||
type: "text",
|
|
||||||
form: {
|
|
||||||
blank: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
sslProvider: {
|
|
||||||
title: "证书提供商",
|
|
||||||
type: "dict-select",
|
|
||||||
dict: Dicts.sslProviderDict
|
|
||||||
},
|
|
||||||
eabAccess: {
|
|
||||||
title: "EAB授权",
|
|
||||||
type: "dict-select",
|
|
||||||
form: {
|
|
||||||
component: {
|
|
||||||
name: "PiAccessSelector",
|
|
||||||
type: "eab",
|
|
||||||
vModel: "modelValue"
|
|
||||||
},
|
|
||||||
helper: "如果是ZeroSSL,需要配置EAB授权,https://app.zerossl.com/developer 生成 'EAB' "
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dnsProviderType: {
|
|
||||||
title: "DNS提供商",
|
|
||||||
type: "dict-select",
|
|
||||||
dict: Dicts.dnsProviderTypeDict,
|
|
||||||
form: {
|
|
||||||
value: "aliyun",
|
|
||||||
rules: [{ required: true, message: "请选择DNS提供商" }],
|
|
||||||
valueChange({ form }) {
|
|
||||||
form.dnsProviderAccess = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dnsProviderAccess: {
|
...inputs
|
||||||
title: "DNS授权",
|
|
||||||
type: "text",
|
|
||||||
form: {
|
|
||||||
component: {
|
|
||||||
name: "PiAccessSelector",
|
|
||||||
type: compute(({ form }) => {
|
|
||||||
return form.dnsProviderType;
|
|
||||||
}),
|
|
||||||
vModel: "modelValue"
|
|
||||||
},
|
|
||||||
rules: [{ required: true, message: "请选择DNS授权" }]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// country: {
|
|
||||||
// title: "国家",
|
|
||||||
// type: "text",
|
|
||||||
// form: {
|
|
||||||
// value: "China"
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// state: {
|
|
||||||
// title: "省份",
|
|
||||||
// type: "text",
|
|
||||||
// form: {
|
|
||||||
// value: "GuangDong"
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// locality: {
|
|
||||||
// title: "市区",
|
|
||||||
// type: "text",
|
|
||||||
// form: {
|
|
||||||
// value: "NanShan"
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// organization: {
|
|
||||||
// title: "单位",
|
|
||||||
// type: "text",
|
|
||||||
// form: {
|
|
||||||
// value: "CertD"
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// organizationUnit: {
|
|
||||||
// title: "部门",
|
|
||||||
// type: "text",
|
|
||||||
// form: {
|
|
||||||
// value: "IT Dept"
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// remark: {
|
|
||||||
// title: "备注",
|
|
||||||
// type: "text"
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<fs-form-wrapper ref="formWrapperRef" />
|
<fs-form-wrapper v-if="formWrapperOptions" ref="formWrapperRef" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -7,14 +7,23 @@ import { useColumns, useExpose } from "@fast-crud/fast-crud";
|
||||||
import createCrudOptions from "./crud.jsx";
|
import createCrudOptions from "./crud.jsx";
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import _ from "lodash-es";
|
import _ from "lodash-es";
|
||||||
|
import * as api from "../api.plugin";
|
||||||
|
import { PluginGroup, PluginGroups } from "/@/views/certd/pipeline/pipeline/type";
|
||||||
export default {
|
export default {
|
||||||
name: "PiCertdForm",
|
name: "PiCertdForm",
|
||||||
setup(props: any, ctx: any) {
|
setup(props: any, ctx: any) {
|
||||||
|
const formWrapperRef = ref();
|
||||||
|
const formWrapperOptions = ref();
|
||||||
|
const doSubmitRef = ref();
|
||||||
|
async function buildFormOptions() {
|
||||||
|
const pluginGroups: { [key: string]: PluginGroup } = await api.GetGroups({});
|
||||||
|
const certPluginGroup = pluginGroups.cert;
|
||||||
|
|
||||||
// 自定义表单配置
|
// 自定义表单配置
|
||||||
const { buildFormOptions } = useColumns();
|
const { buildFormOptions } = useColumns();
|
||||||
//使用crudOptions结构来构建自定义表单配置
|
//使用crudOptions结构来构建自定义表单配置
|
||||||
let { crudOptions } = createCrudOptions();
|
let { crudOptions } = createCrudOptions(certPluginGroup, formWrapperRef);
|
||||||
const doSubmitRef = ref();
|
|
||||||
const formOptions = buildFormOptions(
|
const formOptions = buildFormOptions(
|
||||||
_.merge(crudOptions, {
|
_.merge(crudOptions, {
|
||||||
form: {
|
form: {
|
||||||
|
@ -26,9 +35,9 @@ export default {
|
||||||
}) as any
|
}) as any
|
||||||
);
|
);
|
||||||
|
|
||||||
const formWrapperRef = ref();
|
|
||||||
const formWrapperOptions = ref();
|
|
||||||
formWrapperOptions.value = formOptions;
|
formWrapperOptions.value = formOptions;
|
||||||
|
}
|
||||||
|
buildFormOptions();
|
||||||
function open(doSubmit: any) {
|
function open(doSubmit: any) {
|
||||||
doSubmitRef.value = doSubmit;
|
doSubmitRef.value = doSubmit;
|
||||||
formWrapperRef.value.open(formWrapperOptions.value);
|
formWrapperRef.value.open(formWrapperOptions.value);
|
||||||
|
|
|
@ -58,7 +58,7 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
||||||
strategy: {
|
strategy: {
|
||||||
runStrategy: 0 // 正常执行
|
runStrategy: 0 // 正常执行
|
||||||
},
|
},
|
||||||
type: "CertApply"
|
type: form.certApplyPlugin
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import * as pluginApi from "./api.plugin";
|
||||||
import * as historyApi from "./api.history";
|
import * as historyApi from "./api.history";
|
||||||
import * as api from "./api";
|
import * as api from "./api";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import { PipelineDetail, PipelineOptions, RunHistory } from "./pipeline/type";
|
import { PipelineDetail, PipelineOptions, PluginGroups, RunHistory } from "./pipeline/type";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "PipelineDetail",
|
name: "PipelineDetail",
|
||||||
|
@ -43,9 +43,9 @@ export default defineComponent({
|
||||||
return detail;
|
return detail;
|
||||||
},
|
},
|
||||||
|
|
||||||
async getPlugins() {
|
async getPluginGroups() {
|
||||||
const plugins = await pluginApi.GetList({});
|
const groups = await pluginApi.GetGroups({});
|
||||||
return plugins as any[];
|
return new PluginGroups(groups);
|
||||||
},
|
},
|
||||||
|
|
||||||
async doSave(pipelineConfig: any) {
|
async doSave(pipelineConfig: any) {
|
||||||
|
|
|
@ -4,13 +4,9 @@
|
||||||
<div class="title">我的流水线</div>
|
<div class="title">我的流水线</div>
|
||||||
</template>
|
</template>
|
||||||
<fs-crud ref="crudRef" v-bind="crudBinding">
|
<fs-crud ref="crudRef" v-bind="crudBinding">
|
||||||
<template #actionbar-right>
|
<template #actionbar-right> </template>
|
||||||
<!-- <span style="margin-left: 10px">出现<a-tag>Promise rejected attempt #18,retrying in 10000ms:No TXT recordsfound for name</a-tag>属于正常现象,多重试几次</span>-->
|
|
||||||
</template>
|
|
||||||
<template #form-bottom>
|
<template #form-bottom>
|
||||||
<div>
|
<div>申请证书</div>
|
||||||
申请证书
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
<pi-certd-form ref="certdFormRef"></pi-certd-form>
|
<pi-certd-form ref="certdFormRef"></pi-certd-form>
|
||||||
</fs-crud>
|
</fs-crud>
|
||||||
|
|
|
@ -23,8 +23,10 @@ export default {
|
||||||
const currentStepIndex = inject("currentStepIndex") as Ref<number>;
|
const currentStepIndex = inject("currentStepIndex") as Ref<number>;
|
||||||
const currentTask = inject("currentTask") as Ref<any>;
|
const currentTask = inject("currentTask") as Ref<any>;
|
||||||
|
|
||||||
|
const getPluginGroups = inject("getPluginGroups") as Ref<any>;
|
||||||
|
const pluginGroups = getPluginGroups();
|
||||||
function onCreate() {
|
function onCreate() {
|
||||||
options.value = pluginManager.getPreStepOutputOptions({
|
options.value = pluginGroups.getPreStepOutputOptions({
|
||||||
pipeline: pipeline.value,
|
pipeline: pipeline.value,
|
||||||
currentStageIndex: currentStageIndex.value,
|
currentStageIndex: currentStageIndex.value,
|
||||||
currentStepIndex: currentStepIndex.value,
|
currentStepIndex: currentStepIndex.value,
|
||||||
|
@ -40,7 +42,7 @@ export default {
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => {
|
() => {
|
||||||
return pluginManager.map;
|
return pluginGroups.value.map;
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
onCreate();
|
onCreate();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<a-drawer v-model:open="stepDrawerVisible" placement="right" :closable="true" width="600px" @after-open-change="stepDrawerOnAfterVisibleChange">
|
<a-drawer v-model:open="stepDrawerVisible" placement="right" :closable="true" width="700px" @after-open-change="stepDrawerOnAfterVisibleChange">
|
||||||
<template #title>
|
<template #title>
|
||||||
编辑步骤
|
编辑步骤
|
||||||
<a-button v-if="editMode" @click="stepDelete()">
|
<a-button v-if="editMode" @click="stepDelete()">
|
||||||
|
@ -8,8 +8,10 @@
|
||||||
</template>
|
</template>
|
||||||
<template v-if="currentStep">
|
<template v-if="currentStep">
|
||||||
<pi-container v-if="currentStep._isAdd" class="pi-step-form">
|
<pi-container v-if="currentStep._isAdd" class="pi-step-form">
|
||||||
|
<a-tabs tab-position="left">
|
||||||
|
<a-tab-pane v-for="group of pluginGroups.groups" :key="group.key" :tab="group.title">
|
||||||
<a-row :gutter="10">
|
<a-row :gutter="10">
|
||||||
<a-col v-for="(item, index) of stepPluginDefineList" :key="index" class="step-plugin" :span="12">
|
<a-col v-for="item of group.plugins" :key="item.key" class="step-plugin" :span="12">
|
||||||
<a-card
|
<a-card
|
||||||
hoverable
|
hoverable
|
||||||
:class="{ current: item.name === currentStep.type }"
|
:class="{ current: item.name === currentStep.type }"
|
||||||
|
@ -31,7 +33,11 @@
|
||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
|
</a-tab-pane>
|
||||||
|
</a-tabs>
|
||||||
|
<div style="padding: 20px; margin-left: 100px">
|
||||||
<a-button v-if="editMode" type="primary" @click="stepTypeSave"> 确定 </a-button>
|
<a-button v-if="editMode" type="primary" @click="stepTypeSave"> 确定 </a-button>
|
||||||
|
</div>
|
||||||
</pi-container>
|
</pi-container>
|
||||||
<pi-container v-else class="pi-step-form">
|
<pi-container v-else class="pi-step-form">
|
||||||
<a-form ref="stepFormRef" class="step-form" :model="currentStep" :label-col="labelCol" :wrapper-col="wrapperCol">
|
<a-form ref="stepFormRef" class="step-form" :model="currentStep" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||||
|
@ -91,6 +97,8 @@ import { computed, inject, Ref, ref } from "vue";
|
||||||
import _ from "lodash-es";
|
import _ from "lodash-es";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import { CopyOutlined } from "@ant-design/icons-vue";
|
import { CopyOutlined } from "@ant-design/icons-vue";
|
||||||
|
import { PluginGroups } from "/@/views/certd/pipeline/pipeline/type";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "PiStepForm",
|
name: "PiStepForm",
|
||||||
components: { CopyOutlined },
|
components: { CopyOutlined },
|
||||||
|
@ -107,8 +115,8 @@ export default {
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function useStepForm() {
|
function useStepForm() {
|
||||||
const stepPluginDefineList: any = inject("plugins");
|
const getPluginGroups: any = inject("getPluginGroups");
|
||||||
|
const pluginGroups: PluginGroups = getPluginGroups();
|
||||||
const mode: Ref = ref("add");
|
const mode: Ref = ref("add");
|
||||||
const callback: Ref = ref();
|
const callback: Ref = ref();
|
||||||
const currentStep: Ref = ref({ title: undefined, input: {} });
|
const currentStep: Ref = ref({ title: undefined, input: {} });
|
||||||
|
@ -199,9 +207,8 @@ export default {
|
||||||
|
|
||||||
const changeCurrentPlugin = (step: any) => {
|
const changeCurrentPlugin = (step: any) => {
|
||||||
const stepType = step.type;
|
const stepType = step.type;
|
||||||
const pluginDefine = stepPluginDefineList.value.find((p: any) => {
|
const pluginDefine = pluginGroups.get(stepType);
|
||||||
return p.name === stepType;
|
debugger;
|
||||||
});
|
|
||||||
if (pluginDefine) {
|
if (pluginDefine) {
|
||||||
step.type = stepType;
|
step.type = stepType;
|
||||||
step._isAdd = false;
|
step._isAdd = false;
|
||||||
|
@ -271,7 +278,7 @@ export default {
|
||||||
return {
|
return {
|
||||||
stepTypeSelected,
|
stepTypeSelected,
|
||||||
stepTypeSave,
|
stepTypeSave,
|
||||||
stepPluginDefineList,
|
pluginGroups,
|
||||||
stepFormRef,
|
stepFormRef,
|
||||||
mode,
|
mode,
|
||||||
stepAdd,
|
stepAdd,
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<a-drawer v-model:open="taskDrawerVisible" placement="right" :closable="true" width="600px" class="pi-task-form" @after-open-change="taskDrawerOnAfterVisibleChange">
|
<a-drawer
|
||||||
|
v-model:open="taskDrawerVisible"
|
||||||
|
placement="right"
|
||||||
|
:closable="true"
|
||||||
|
width="700px"
|
||||||
|
class="pi-task-form"
|
||||||
|
@after-open-change="taskDrawerOnAfterVisibleChange"
|
||||||
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
编辑任务
|
编辑任务
|
||||||
<a-button v-if="editMode" @click="taskDelete()">
|
<a-button v-if="editMode" @click="taskDelete()">
|
||||||
|
@ -24,7 +31,13 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="steps">
|
<div class="steps">
|
||||||
<a-form-item :value="currentTask.steps" name="steps" label="" :wrapper-col="{ span: 24 }" :rules="[{ required: true, message: '至少需要一个步骤,或者你可以点击标题右边删除按钮删除此任务' }]">
|
<a-form-item
|
||||||
|
:value="currentTask.steps"
|
||||||
|
name="steps"
|
||||||
|
label=""
|
||||||
|
:wrapper-col="{ span: 24 }"
|
||||||
|
:rules="[{ required: true, message: '至少需要一个步骤,或者你可以点击标题右边删除按钮删除此任务' }]"
|
||||||
|
>
|
||||||
<a-descriptions title="任务步骤" size="small">
|
<a-descriptions title="任务步骤" size="small">
|
||||||
<template #extra>
|
<template #extra>
|
||||||
<a-button type="primary" @click="stepAdd(currentTask)">添加步骤</a-button>
|
<a-button type="primary" @click="stepAdd(currentTask)">添加步骤</a-button>
|
||||||
|
@ -70,7 +83,7 @@ import { provide, Ref, ref } from "vue";
|
||||||
import _ from "lodash-es";
|
import _ from "lodash-es";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import PiStepForm from "../step-form/index.vue";
|
import PiStepForm from "../step-form/index.vue";
|
||||||
import { message, Modal } from "ant-design-vue";
|
import { Modal } from "ant-design-vue";
|
||||||
import { CopyOutlined } from "@ant-design/icons-vue";
|
import { CopyOutlined } from "@ant-design/icons-vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -88,7 +101,7 @@ export default {
|
||||||
const stepFormRef: Ref<any> = ref(null);
|
const stepFormRef: Ref<any> = ref(null);
|
||||||
const currentStepIndex = ref(0);
|
const currentStepIndex = ref(0);
|
||||||
provide("currentStepIndex", currentStepIndex);
|
provide("currentStepIndex", currentStepIndex);
|
||||||
const stepAdd = (task: any, stepDef: any) => {
|
const stepAdd = (task: any, stepDef?: any) => {
|
||||||
currentStepIndex.value = task.steps.length;
|
currentStepIndex.value = task.steps.length;
|
||||||
stepFormRef.value.stepAdd((type: any, value: any) => {
|
stepFormRef.value.stepAdd((type: any, value: any) => {
|
||||||
if (type === "save") {
|
if (type === "save") {
|
||||||
|
@ -179,7 +192,7 @@ export default {
|
||||||
|
|
||||||
const taskAdd = (emit: any, taskMerge: any) => {
|
const taskAdd = (emit: any, taskMerge: any) => {
|
||||||
mode.value = "add";
|
mode.value = "add";
|
||||||
const blankTask = { id: nanoid(), title: "新任务", steps: [], status: null };
|
const blankTask: any = { id: nanoid(), title: "新任务", steps: [], status: null };
|
||||||
const task: any = _.merge(blankTask, taskMerge);
|
const task: any = _.merge(blankTask, taskMerge);
|
||||||
taskOpen(task, emit);
|
taskOpen(task, emit);
|
||||||
};
|
};
|
||||||
|
|
|
@ -223,7 +223,7 @@ import _ from "lodash-es";
|
||||||
import { message, Modal, notification } from "ant-design-vue";
|
import { message, Modal, notification } from "ant-design-vue";
|
||||||
import { pluginManager } from "/@/views/certd/pipeline/pipeline/plugin";
|
import { pluginManager } from "/@/views/certd/pipeline/pipeline/plugin";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import { PipelineDetail, PipelineOptions, RunHistory } from "./type";
|
import { PipelineDetail, PipelineOptions, PluginGroups, RunHistory } from "./type";
|
||||||
import type { Runnable } from "@certd/pipeline";
|
import type { Runnable } from "@certd/pipeline";
|
||||||
import PiHistoryTimelineItem from "/@/views/certd/pipeline/pipeline/component/history-timeline-item.vue";
|
import PiHistoryTimelineItem from "/@/views/certd/pipeline/pipeline/component/history-timeline-item.vue";
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
@ -348,17 +348,17 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const plugins: Ref<any> = ref([]);
|
const pluginGroupsRef: Ref<PluginGroups> = ref();
|
||||||
|
|
||||||
const fetchPlugins = async () => {
|
const fetchPlugins = async () => {
|
||||||
const list = await props.options.getPlugins();
|
pluginGroupsRef.value = await props.options.getPluginGroups();
|
||||||
plugins.value = list;
|
|
||||||
pluginManager.init(list);
|
|
||||||
};
|
};
|
||||||
fetchPlugins();
|
fetchPlugins();
|
||||||
|
|
||||||
provide("pipeline", pipeline);
|
provide("pipeline", pipeline);
|
||||||
provide("plugins", plugins);
|
provide("getPluginGroups", () => {
|
||||||
|
return pluginGroupsRef.value;
|
||||||
|
});
|
||||||
provide("currentHistory", currentHistory);
|
provide("currentHistory", currentHistory);
|
||||||
|
|
||||||
function useTask() {
|
function useTask() {
|
||||||
|
|
|
@ -17,49 +17,7 @@ export class PluginManager {
|
||||||
this.map = map;
|
this.map = map;
|
||||||
}
|
}
|
||||||
|
|
||||||
get(name: string) {
|
|
||||||
return this.map[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
getPreStepOutputOptions({ pipeline, currentStageIndex, currentStepIndex, currentTask }: any) {
|
|
||||||
const steps = this.collectionPreStepOutputs({
|
|
||||||
pipeline,
|
|
||||||
currentStageIndex,
|
|
||||||
currentStepIndex,
|
|
||||||
currentTask
|
|
||||||
});
|
|
||||||
const options: any[] = [];
|
|
||||||
for (const step of steps) {
|
|
||||||
const stepDefine = this.get(step.type);
|
|
||||||
for (const key in stepDefine?.output) {
|
|
||||||
options.push({
|
|
||||||
value: `step.${step.id}.${key}`,
|
|
||||||
label: `${stepDefine.output[key].title}【from:${step.title}】`,
|
|
||||||
type: step.type
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
collectionPreStepOutputs({ pipeline, currentStageIndex, currentStepIndex, currentTask }: any) {
|
|
||||||
const steps: any[] = [];
|
|
||||||
// 开始放step
|
|
||||||
for (let i = 0; i < currentStageIndex; i++) {
|
|
||||||
const stage = pipeline.stages[i];
|
|
||||||
for (const task of stage.tasks) {
|
|
||||||
for (const step of task.steps) {
|
|
||||||
steps.push(step);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//放当前任务下的step
|
|
||||||
for (let i = 0; i < currentStepIndex; i++) {
|
|
||||||
const step = currentTask.steps[i];
|
|
||||||
steps.push(step);
|
|
||||||
}
|
|
||||||
return steps;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const pluginManager = new PluginManager();
|
export const pluginManager = new PluginManager();
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import type { Pipeline } from "@certd/pipeline";
|
import type { Pipeline } from "@certd/pipeline";
|
||||||
|
import { FormItemProps } from "@fast-crud/fast-crud";
|
||||||
export type PipelineDetail = {
|
export type PipelineDetail = {
|
||||||
pipeline: Pipeline;
|
pipeline: Pipeline;
|
||||||
};
|
};
|
||||||
|
@ -10,6 +11,110 @@ export type RunHistory = {
|
||||||
[id: string]: string[];
|
[id: string]: string[];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
export type PluginGroup = {
|
||||||
|
key: string;
|
||||||
|
title: string;
|
||||||
|
desc?: string;
|
||||||
|
order: number;
|
||||||
|
plugins: any[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PluginDefine = {
|
||||||
|
key: string;
|
||||||
|
title: string;
|
||||||
|
desc?: string;
|
||||||
|
input: {
|
||||||
|
[key: string]: FormItemProps;
|
||||||
|
};
|
||||||
|
output: {
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export class PluginGroups {
|
||||||
|
groups: { [key: string]: PluginGroup };
|
||||||
|
map: { [key: string]: PluginDefine };
|
||||||
|
constructor(groups: { [key: string]: PluginGroup }) {
|
||||||
|
this.groups = groups;
|
||||||
|
this.initGroup(groups);
|
||||||
|
this.initMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
private initGroup(groups: { [p: string]: PluginGroup }) {
|
||||||
|
const all: PluginGroup = {
|
||||||
|
key: "all",
|
||||||
|
title: "全部",
|
||||||
|
order: 0,
|
||||||
|
plugins: []
|
||||||
|
};
|
||||||
|
for (const key in groups) {
|
||||||
|
all.plugins.push(...groups[key].plugins);
|
||||||
|
}
|
||||||
|
this.groups = {
|
||||||
|
all,
|
||||||
|
...groups
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
initMap() {
|
||||||
|
const map: { [key: string]: PluginDefine } = {};
|
||||||
|
for (const key in this.groups) {
|
||||||
|
const group = this.groups[key];
|
||||||
|
for (const plugin of group.plugins) {
|
||||||
|
map[plugin.name] = plugin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.map = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
getGroups() {
|
||||||
|
return this.groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
get(name: string) {
|
||||||
|
return this.map[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
getPreStepOutputOptions({ pipeline, currentStageIndex, currentStepIndex, currentTask }: any) {
|
||||||
|
const steps = this.collectionPreStepOutputs({
|
||||||
|
pipeline,
|
||||||
|
currentStageIndex,
|
||||||
|
currentStepIndex,
|
||||||
|
currentTask
|
||||||
|
});
|
||||||
|
const options: any[] = [];
|
||||||
|
for (const step of steps) {
|
||||||
|
const stepDefine = this.get(step.type);
|
||||||
|
for (const key in stepDefine?.output) {
|
||||||
|
options.push({
|
||||||
|
value: `step.${step.id}.${key}`,
|
||||||
|
label: `${stepDefine.output[key].title}【from:${step.title}】`,
|
||||||
|
type: step.type
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
collectionPreStepOutputs({ pipeline, currentStageIndex, currentStepIndex, currentTask }: any) {
|
||||||
|
const steps: any[] = [];
|
||||||
|
// 开始放step
|
||||||
|
for (let i = 0; i < currentStageIndex; i++) {
|
||||||
|
const stage = pipeline.stages[i];
|
||||||
|
for (const task of stage.tasks) {
|
||||||
|
for (const step of task.steps) {
|
||||||
|
steps.push(step);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//放当前任务下的step
|
||||||
|
for (let i = 0; i < currentStepIndex; i++) {
|
||||||
|
const step = currentTask.steps[i];
|
||||||
|
steps.push(step);
|
||||||
|
}
|
||||||
|
return steps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export type PipelineOptions = {
|
export type PipelineOptions = {
|
||||||
doTrigger(options: { pipelineId: number }): Promise<void>;
|
doTrigger(options: { pipelineId: number }): Promise<void>;
|
||||||
|
@ -17,5 +122,5 @@ export type PipelineOptions = {
|
||||||
getPipelineDetail(query: { pipelineId: number }): Promise<PipelineDetail>;
|
getPipelineDetail(query: { pipelineId: number }): Promise<PipelineDetail>;
|
||||||
getHistoryList(query: { pipelineId: number }): Promise<RunHistory[]>;
|
getHistoryList(query: { pipelineId: number }): Promise<RunHistory[]>;
|
||||||
getHistoryDetail(query: { historyId: number }): Promise<RunHistory>;
|
getHistoryDetail(query: { historyId: number }): Promise<RunHistory>;
|
||||||
getPlugins(): Promise<Pipeline[]>;
|
getPluginGroups(): Promise<PluginGroups>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
koa:
|
koa:
|
||||||
port: 7001
|
port: 7001
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
"lint:fix": "mwts fix",
|
"lint:fix": "mwts fix",
|
||||||
"ci": "npm run cov",
|
"ci": "npm run cov",
|
||||||
"build": "mwtsc --cleanOutDir --skipLibCheck",
|
"build": "mwtsc --cleanOutDir --skipLibCheck",
|
||||||
|
"build-on-docker": "node ./before-build.js && npm run build",
|
||||||
"up-mw-deps": "npx midway-version -u -w"
|
"up-mw-deps": "npx midway-version -u -w"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -37,7 +37,9 @@ const development = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
cron: {},
|
cron: {
|
||||||
|
immediateTriggerOnce: false,
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* 演示环境
|
* 演示环境
|
||||||
*/
|
*/
|
||||||
|
@ -84,6 +86,8 @@ const development = {
|
||||||
resetAdminPasswd: false,
|
resetAdminPasswd: false,
|
||||||
},
|
},
|
||||||
} as MidwayConfig;
|
} as MidwayConfig;
|
||||||
|
mergeConfig(development, 'development');
|
||||||
|
|
||||||
mergeConfig(development, env);
|
mergeConfig(development, env);
|
||||||
|
|
||||||
export default development;
|
export default development;
|
||||||
|
|
|
@ -8,6 +8,9 @@ const production = {
|
||||||
preview: {
|
preview: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
},
|
},
|
||||||
|
cron: {
|
||||||
|
immediateTriggerOnce: true,
|
||||||
|
},
|
||||||
} as MidwayConfig;
|
} as MidwayConfig;
|
||||||
|
|
||||||
mergeConfig(production, 'production');
|
mergeConfig(production, 'production');
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Autoload, Init, Inject, Scope, ScopeEnum } from '@midwayjs/core';
|
import { Autoload, Config, Init, Inject, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
import { PipelineService } from '../service/pipeline-service.js';
|
import { PipelineService } from '../service/pipeline-service.js';
|
||||||
import { logger } from '../../../utils/logger.js';
|
import { logger } from '../../../utils/logger.js';
|
||||||
|
|
||||||
|
@ -10,11 +10,13 @@ export class AutoRegisterCron {
|
||||||
|
|
||||||
// @Inject()
|
// @Inject()
|
||||||
// echoPlugin: EchoPlugin;
|
// echoPlugin: EchoPlugin;
|
||||||
|
@Config('cron.immediateTriggerOnce')
|
||||||
|
private immediateTriggerOnce = false;
|
||||||
|
|
||||||
@Init()
|
@Init()
|
||||||
async init() {
|
async init() {
|
||||||
logger.info('加载定时trigger开始');
|
logger.info('加载定时trigger开始');
|
||||||
await this.pipelineService.onStartup();
|
await this.pipelineService.onStartup(this.immediateTriggerOnce);
|
||||||
// logger.info(this.echoPlugin, this.echoPlugin.test);
|
// logger.info(this.echoPlugin, this.echoPlugin.test);
|
||||||
// logger.info('加载定时trigger完成');
|
// logger.info('加载定时trigger完成');
|
||||||
//
|
//
|
||||||
|
|
|
@ -1,11 +1,4 @@
|
||||||
import {
|
import { ALL, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
|
||||||
ALL,
|
|
||||||
Controller,
|
|
||||||
Inject,
|
|
||||||
Post,
|
|
||||||
Provide,
|
|
||||||
Query,
|
|
||||||
} from '@midwayjs/core';
|
|
||||||
import { BaseController } from '../../../basic/base-controller.js';
|
import { BaseController } from '../../../basic/base-controller.js';
|
||||||
import { PluginService } from '../service/plugin-service.js';
|
import { PluginService } from '../service/plugin-service.js';
|
||||||
import { Constants } from '../../../basic/constants.js';
|
import { Constants } from '../../../basic/constants.js';
|
||||||
|
@ -25,4 +18,11 @@ export class PluginController extends BaseController {
|
||||||
const list = this.service.getList();
|
const list = this.service.getList();
|
||||||
return this.ok(list);
|
return this.ok(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Post('/groups', { summary: Constants.per.authOnly })
|
||||||
|
async groups(@Query(ALL) query) {
|
||||||
|
query.userId = this.ctx.user.id;
|
||||||
|
const group = this.service.getGroups();
|
||||||
|
return this.ok(group);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Config, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
import { Config, Inject, Provide, Scope, ScopeEnum, sleep } from '@midwayjs/core';
|
||||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||||
import { In, Repository } from 'typeorm';
|
import { In, Repository } from 'typeorm';
|
||||||
import { BaseService } from '../../../basic/base-service.js';
|
import { BaseService } from '../../../basic/base-service.js';
|
||||||
|
@ -80,7 +80,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
/**
|
/**
|
||||||
* 应用启动后初始加载记录
|
* 应用启动后初始加载记录
|
||||||
*/
|
*/
|
||||||
async onStartup() {
|
async onStartup(immediateTriggerOnce: boolean) {
|
||||||
logger.info('加载定时trigger开始');
|
logger.info('加载定时trigger开始');
|
||||||
const idEntityList = await this.repository.find({
|
const idEntityList = await this.repository.find({
|
||||||
select: {
|
select: {
|
||||||
|
@ -114,7 +114,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
for (const entity of list) {
|
for (const entity of list) {
|
||||||
const pipeline = JSON.parse(entity.content ?? '{}');
|
const pipeline = JSON.parse(entity.content ?? '{}');
|
||||||
try {
|
try {
|
||||||
this.registerTriggers(pipeline);
|
await this.registerTriggers(pipeline, immediateTriggerOnce);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('加载定时trigger失败:', e);
|
logger.error('加载定时trigger失败:', e);
|
||||||
}
|
}
|
||||||
|
@ -123,13 +123,18 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
logger.info('定时器数量:', this.cron.getListSize());
|
logger.info('定时器数量:', this.cron.getListSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
registerTriggers(pipeline?: Pipeline) {
|
async registerTriggers(pipeline?: Pipeline, immediateTriggerOnce = false) {
|
||||||
if (pipeline?.triggers == null) {
|
if (pipeline?.triggers == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (const trigger of pipeline.triggers) {
|
for (const trigger of pipeline.triggers) {
|
||||||
this.registerCron(pipeline.id, trigger);
|
this.registerCron(pipeline.id, trigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (immediateTriggerOnce) {
|
||||||
|
await this.trigger(pipeline.id);
|
||||||
|
await sleep(1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async trigger(id) {
|
async trigger(id) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
import { pluginRegistry } from '@certd/pipeline';
|
import { pluginGroups, pluginRegistry } from '@certd/pipeline';
|
||||||
@Provide()
|
@Provide()
|
||||||
@Scope(ScopeEnum.Singleton)
|
@Scope(ScopeEnum.Singleton)
|
||||||
export class PluginService {
|
export class PluginService {
|
||||||
|
@ -12,4 +12,8 @@ export class PluginService {
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getGroups() {
|
||||||
|
return pluginGroups;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, utils } from '@certd/pipeline';
|
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, utils } from '@certd/pipeline';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { ROAClient } from '@alicloud/pop-core';
|
import { ROAClient } from '@alicloud/pop-core';
|
||||||
import { AliyunAccess } from '../../access/index.js';
|
import { AliyunAccess } from '../../access/index.js';
|
||||||
|
@ -9,6 +9,7 @@ import { CertInfo } from '@certd/plugin-cert';
|
||||||
@IsTaskPlugin({
|
@IsTaskPlugin({
|
||||||
name: 'DeployCertToAliyunAckIngress',
|
name: 'DeployCertToAliyunAckIngress',
|
||||||
title: '部署到阿里云AckIngress',
|
title: '部署到阿里云AckIngress',
|
||||||
|
group: pluginGroups.aliyun.key,
|
||||||
input: {},
|
input: {},
|
||||||
output: {},
|
output: {},
|
||||||
default: {
|
default: {
|
||||||
|
|
|
@ -2,7 +2,7 @@ import {
|
||||||
AbstractTaskPlugin,
|
AbstractTaskPlugin,
|
||||||
IAccessService,
|
IAccessService,
|
||||||
ILogger,
|
ILogger,
|
||||||
IsTaskPlugin,
|
IsTaskPlugin, pluginGroups,
|
||||||
RunStrategy,
|
RunStrategy,
|
||||||
TaskInput,
|
TaskInput,
|
||||||
} from '@certd/pipeline';
|
} from '@certd/pipeline';
|
||||||
|
@ -14,6 +14,7 @@ import { AliyunAccess } from '../../access/index.js';
|
||||||
@IsTaskPlugin({
|
@IsTaskPlugin({
|
||||||
name: 'DeployCertToAliyunCDN',
|
name: 'DeployCertToAliyunCDN',
|
||||||
title: '部署证书至阿里云CDN',
|
title: '部署证书至阿里云CDN',
|
||||||
|
group: pluginGroups.aliyun.key,
|
||||||
desc: '依赖证书申请前置任务,自动部署域名证书至阿里云CDN',
|
desc: '依赖证书申请前置任务,自动部署域名证书至阿里云CDN',
|
||||||
default: {
|
default: {
|
||||||
strategy: {
|
strategy: {
|
||||||
|
|
|
@ -1,11 +1,4 @@
|
||||||
import {
|
import { AbstractTaskPlugin, IAccessService, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline';
|
||||||
AbstractTaskPlugin,
|
|
||||||
IAccessService,
|
|
||||||
IsTaskPlugin,
|
|
||||||
RunStrategy,
|
|
||||||
TaskInput,
|
|
||||||
TaskOutput,
|
|
||||||
} from '@certd/pipeline';
|
|
||||||
import Core from '@alicloud/pop-core';
|
import Core from '@alicloud/pop-core';
|
||||||
import { AliyunAccess } from '../../access/index.js';
|
import { AliyunAccess } from '../../access/index.js';
|
||||||
import { appendTimeSuffix, checkRet, ZoneOptions } from '../../utils/index.js';
|
import { appendTimeSuffix, checkRet, ZoneOptions } from '../../utils/index.js';
|
||||||
|
@ -14,6 +7,7 @@ import { Logger } from 'log4js';
|
||||||
@IsTaskPlugin({
|
@IsTaskPlugin({
|
||||||
name: 'uploadCertToAliyun',
|
name: 'uploadCertToAliyun',
|
||||||
title: '上传证书到阿里云',
|
title: '上传证书到阿里云',
|
||||||
|
group: pluginGroups.aliyun.key,
|
||||||
desc: '',
|
desc: '',
|
||||||
default: {
|
default: {
|
||||||
strategy: {
|
strategy: {
|
||||||
|
@ -76,9 +70,7 @@ export class UploadCertToAliyun extends AbstractTaskPlugin {
|
||||||
|
|
||||||
async execute(): Promise<void> {
|
async execute(): Promise<void> {
|
||||||
console.log('开始部署证书到阿里云cdn');
|
console.log('开始部署证书到阿里云cdn');
|
||||||
const access = (await this.accessService.getById(
|
const access = (await this.accessService.getById(this.accessId)) as AliyunAccess;
|
||||||
this.accessId
|
|
||||||
)) as AliyunAccess;
|
|
||||||
const client = this.getClient(access);
|
const client = this.getClient(access);
|
||||||
const certName = appendTimeSuffix(this.name);
|
const certName = appendTimeSuffix(this.name);
|
||||||
const params = {
|
const params = {
|
||||||
|
@ -92,11 +84,7 @@ export class UploadCertToAliyun extends AbstractTaskPlugin {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
};
|
};
|
||||||
|
|
||||||
const ret = (await client.request(
|
const ret = (await client.request('CreateUserCertificate', params, requestOption)) as any;
|
||||||
'CreateUserCertificate',
|
|
||||||
params,
|
|
||||||
requestOption
|
|
||||||
)) as any;
|
|
||||||
checkRet(ret);
|
checkRet(ret);
|
||||||
this.logger.info('证书上传成功:aliyunCertId=', ret.CertId);
|
this.logger.info('证书上传成功:aliyunCertId=', ret.CertId);
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,10 @@
|
||||||
import {
|
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||||
AbstractTaskPlugin,
|
|
||||||
IAccessService,
|
|
||||||
ILogger,
|
|
||||||
IsTaskPlugin,
|
|
||||||
RunStrategy,
|
|
||||||
TaskInput,
|
|
||||||
} from '@certd/pipeline';
|
|
||||||
import { CertInfo, CertReader } from '@certd/plugin-cert';
|
import { CertInfo, CertReader } from '@certd/plugin-cert';
|
||||||
|
|
||||||
@IsTaskPlugin({
|
@IsTaskPlugin({
|
||||||
name: 'CloudflareDeployToCDN',
|
name: 'CloudflareDeployToCDN',
|
||||||
title: '部署证书到CF CDN',
|
title: '部署证书到CF CDN',
|
||||||
|
group: pluginGroups.other.key,
|
||||||
desc: '暂未实现,不可用',
|
desc: '暂未实现,不可用',
|
||||||
default: {
|
default: {
|
||||||
strategy: {
|
strategy: {
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput } from '@certd/pipeline';
|
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||||
import { CertInfo, CertReader } from '@certd/plugin-cert';
|
import { CertInfo, CertReader } from '@certd/plugin-cert';
|
||||||
import { K8sClient } from '@certd/lib-k8s';
|
import { K8sClient } from '@certd/lib-k8s';
|
||||||
|
|
||||||
@IsTaskPlugin({
|
@IsTaskPlugin({
|
||||||
name: 'demoTest',
|
name: 'demoTest',
|
||||||
title: 'Demo测试插件',
|
title: 'Demo测试插件',
|
||||||
|
group: pluginGroups.other.key,
|
||||||
default: {
|
default: {
|
||||||
strategy: {
|
strategy: {
|
||||||
runStrategy: RunStrategy.SkipWhenSucceed,
|
runStrategy: RunStrategy.SkipWhenSucceed,
|
||||||
|
|
|
@ -1,16 +1,10 @@
|
||||||
import {
|
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||||
AbstractTaskPlugin,
|
|
||||||
IAccessService,
|
|
||||||
ILogger,
|
|
||||||
IsTaskPlugin,
|
|
||||||
RunStrategy,
|
|
||||||
TaskInput,
|
|
||||||
} from '@certd/pipeline';
|
|
||||||
import { SshClient } from '../../lib/ssh.js';
|
import { SshClient } from '../../lib/ssh.js';
|
||||||
|
|
||||||
@IsTaskPlugin({
|
@IsTaskPlugin({
|
||||||
name: 'hostShellExecute',
|
name: 'hostShellExecute',
|
||||||
title: '执行远程主机脚本命令',
|
title: '执行远程主机脚本命令',
|
||||||
|
group: pluginGroups.host.key,
|
||||||
input: {},
|
input: {},
|
||||||
default: {
|
default: {
|
||||||
strategy: {
|
strategy: {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline';
|
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline';
|
||||||
import { SshClient } from '../../lib/ssh.js';
|
import { SshClient } from '../../lib/ssh.js';
|
||||||
import { CertInfo, CertReader } from '@certd/plugin-cert';
|
import { CertInfo, CertReader } from '@certd/plugin-cert';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
@ -7,6 +7,7 @@ import { SshAccess } from '../../access/index.js';
|
||||||
@IsTaskPlugin({
|
@IsTaskPlugin({
|
||||||
name: 'uploadCertToHost',
|
name: 'uploadCertToHost',
|
||||||
title: '上传证书到主机',
|
title: '上传证书到主机',
|
||||||
|
group: pluginGroups.host.key,
|
||||||
desc: '也支持复制证书到本机',
|
desc: '也支持复制证书到本机',
|
||||||
default: {
|
default: {
|
||||||
strategy: {
|
strategy: {
|
||||||
|
|
|
@ -1,11 +1,4 @@
|
||||||
import {
|
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||||
AbstractTaskPlugin,
|
|
||||||
IAccessService,
|
|
||||||
ILogger,
|
|
||||||
IsTaskPlugin,
|
|
||||||
RunStrategy,
|
|
||||||
TaskInput,
|
|
||||||
} from '@certd/pipeline';
|
|
||||||
import tencentcloud from 'tencentcloud-sdk-nodejs';
|
import tencentcloud from 'tencentcloud-sdk-nodejs';
|
||||||
import { TencentAccess } from '../../access/index.js';
|
import { TencentAccess } from '../../access/index.js';
|
||||||
import { CertInfo } from '@certd/plugin-cert';
|
import { CertInfo } from '@certd/plugin-cert';
|
||||||
|
@ -13,6 +6,7 @@ import { CertInfo } from '@certd/plugin-cert';
|
||||||
@IsTaskPlugin({
|
@IsTaskPlugin({
|
||||||
name: 'DeployCertToTencentCDN',
|
name: 'DeployCertToTencentCDN',
|
||||||
title: '部署到腾讯云CDN',
|
title: '部署到腾讯云CDN',
|
||||||
|
group: pluginGroups.tencent.key,
|
||||||
default: {
|
default: {
|
||||||
strategy: {
|
strategy: {
|
||||||
runStrategy: RunStrategy.SkipWhenSucceed,
|
runStrategy: RunStrategy.SkipWhenSucceed,
|
||||||
|
@ -75,9 +69,7 @@ export class DeployToCdnPlugin extends AbstractTaskPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute(): Promise<void> {
|
async execute(): Promise<void> {
|
||||||
const accessProvider: TencentAccess = (await this.accessService.getById(
|
const accessProvider: TencentAccess = (await this.accessService.getById(this.accessId)) as TencentAccess;
|
||||||
this.accessId
|
|
||||||
)) as TencentAccess;
|
|
||||||
const client = this.getClient(accessProvider);
|
const client = this.getClient(accessProvider);
|
||||||
const params = this.buildParams();
|
const params = this.buildParams();
|
||||||
await this.doRequest(client, params);
|
await this.doRequest(client, params);
|
||||||
|
|
|
@ -1,12 +1,4 @@
|
||||||
import {
|
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, utils } from '@certd/pipeline';
|
||||||
AbstractTaskPlugin,
|
|
||||||
IAccessService,
|
|
||||||
ILogger,
|
|
||||||
IsTaskPlugin,
|
|
||||||
RunStrategy,
|
|
||||||
TaskInput,
|
|
||||||
utils,
|
|
||||||
} from '@certd/pipeline';
|
|
||||||
import tencentcloud from 'tencentcloud-sdk-nodejs';
|
import tencentcloud from 'tencentcloud-sdk-nodejs';
|
||||||
import { TencentAccess } from '../../access/index.js';
|
import { TencentAccess } from '../../access/index.js';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
@ -14,6 +6,7 @@ import dayjs from 'dayjs';
|
||||||
@IsTaskPlugin({
|
@IsTaskPlugin({
|
||||||
name: 'DeployCertToTencentCLB',
|
name: 'DeployCertToTencentCLB',
|
||||||
title: '部署到腾讯云CLB',
|
title: '部署到腾讯云CLB',
|
||||||
|
group: pluginGroups.tencent.key,
|
||||||
desc: '暂时只支持单向认证证书,暂时只支持通用负载均衡',
|
desc: '暂时只支持单向认证证书,暂时只支持通用负载均衡',
|
||||||
default: {
|
default: {
|
||||||
strategy: {
|
strategy: {
|
||||||
|
@ -40,8 +33,7 @@ export class DeployToClbPlugin extends AbstractTaskPlugin {
|
||||||
|
|
||||||
@TaskInput({
|
@TaskInput({
|
||||||
title: '负载均衡ID',
|
title: '负载均衡ID',
|
||||||
helper:
|
helper: '如果没有配置,则根据域名匹配负载均衡下的监听器(根据域名匹配时暂时只支持前100个)',
|
||||||
'如果没有配置,则根据域名匹配负载均衡下的监听器(根据域名匹配时暂时只支持前100个)',
|
|
||||||
required: true,
|
required: true,
|
||||||
})
|
})
|
||||||
loadBalancerId!: string;
|
loadBalancerId!: string;
|
||||||
|
@ -88,9 +80,7 @@ export class DeployToClbPlugin extends AbstractTaskPlugin {
|
||||||
this.logger = this.ctx.logger;
|
this.logger = this.ctx.logger;
|
||||||
}
|
}
|
||||||
async execute(): Promise<void> {
|
async execute(): Promise<void> {
|
||||||
const accessProvider = (await this.accessService.getById(
|
const accessProvider = (await this.accessService.getById(this.accessId)) as TencentAccess;
|
||||||
this.accessId
|
|
||||||
)) as TencentAccess;
|
|
||||||
const client = this.getClient(accessProvider, this.region);
|
const client = this.getClient(accessProvider, this.region);
|
||||||
|
|
||||||
const lastCertId = await this.getCertIdFromProps(client);
|
const lastCertId = await this.getCertIdFromProps(client);
|
||||||
|
@ -103,10 +93,7 @@ export class DeployToClbPlugin extends AbstractTaskPlugin {
|
||||||
try {
|
try {
|
||||||
await utils.sleep(2000);
|
await utils.sleep(2000);
|
||||||
let newCertId = await this.getCertIdFromProps(client);
|
let newCertId = await this.getCertIdFromProps(client);
|
||||||
if (
|
if ((lastCertId && newCertId === lastCertId) || (!lastCertId && !newCertId)) {
|
||||||
(lastCertId && newCertId === lastCertId) ||
|
|
||||||
(!lastCertId && !newCertId)
|
|
||||||
) {
|
|
||||||
await utils.sleep(2000);
|
await utils.sleep(2000);
|
||||||
newCertId = await this.getCertIdFromProps(client);
|
newCertId = await this.getCertIdFromProps(client);
|
||||||
}
|
}
|
||||||
|
@ -121,11 +108,7 @@ export class DeployToClbPlugin extends AbstractTaskPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCertIdFromProps(client: any) {
|
async getCertIdFromProps(client: any) {
|
||||||
const listenerRet = await this.getListenerList(
|
const listenerRet = await this.getListenerList(client, this.loadBalancerId, [this.listenerId]);
|
||||||
client,
|
|
||||||
this.loadBalancerId,
|
|
||||||
[this.listenerId]
|
|
||||||
);
|
|
||||||
return this.getCertIdFromListener(listenerRet[0], this.domain);
|
return this.getCertIdFromListener(listenerRet[0], this.domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,14 +135,7 @@ export class DeployToClbPlugin extends AbstractTaskPlugin {
|
||||||
const params = this.buildProps();
|
const params = this.buildProps();
|
||||||
const ret = await client.ModifyListener(params);
|
const ret = await client.ModifyListener(params);
|
||||||
this.checkRet(ret);
|
this.checkRet(ret);
|
||||||
this.logger.info(
|
this.logger.info('设置腾讯云CLB证书成功:', ret.RequestId, '->loadBalancerId:', this.loadBalancerId, 'listenerId', this.listenerId);
|
||||||
'设置腾讯云CLB证书成功:',
|
|
||||||
ret.RequestId,
|
|
||||||
'->loadBalancerId:',
|
|
||||||
this.loadBalancerId,
|
|
||||||
'listenerId',
|
|
||||||
this.listenerId
|
|
||||||
);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,4 @@
|
||||||
import {
|
import { AbstractTaskPlugin, IAccessService, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, utils } from '@certd/pipeline';
|
||||||
AbstractTaskPlugin,
|
|
||||||
IAccessService,
|
|
||||||
IsTaskPlugin,
|
|
||||||
RunStrategy,
|
|
||||||
TaskInput,
|
|
||||||
utils,
|
|
||||||
} from '@certd/pipeline';
|
|
||||||
import tencentcloud from 'tencentcloud-sdk-nodejs';
|
import tencentcloud from 'tencentcloud-sdk-nodejs';
|
||||||
import { K8sClient } from '@certd/lib-k8s';
|
import { K8sClient } from '@certd/lib-k8s';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
@ -14,6 +7,7 @@ import { Logger } from 'log4js';
|
||||||
@IsTaskPlugin({
|
@IsTaskPlugin({
|
||||||
name: 'DeployCertToTencentTKEIngress',
|
name: 'DeployCertToTencentTKEIngress',
|
||||||
title: '部署到腾讯云TKE-ingress',
|
title: '部署到腾讯云TKE-ingress',
|
||||||
|
group: pluginGroups.tencent.key,
|
||||||
desc: '需要【上传到腾讯云】作为前置任务',
|
desc: '需要【上传到腾讯云】作为前置任务',
|
||||||
default: {
|
default: {
|
||||||
strategy: {
|
strategy: {
|
||||||
|
@ -104,10 +98,7 @@ export class DeployCertToTencentTKEIngressPlugin extends AbstractTaskPlugin {
|
||||||
async execute(): Promise<void> {
|
async execute(): Promise<void> {
|
||||||
const accessProvider = await this.accessService.getById(this.accessId);
|
const accessProvider = await this.accessService.getById(this.accessId);
|
||||||
const tkeClient = this.getTkeClient(accessProvider, this.region);
|
const tkeClient = this.getTkeClient(accessProvider, this.region);
|
||||||
const kubeConfigStr = await this.getTkeKubeConfig(
|
const kubeConfigStr = await this.getTkeKubeConfig(tkeClient, this.clusterId);
|
||||||
tkeClient,
|
|
||||||
this.clusterId
|
|
||||||
);
|
|
||||||
|
|
||||||
this.logger.info('kubeconfig已成功获取');
|
this.logger.info('kubeconfig已成功获取');
|
||||||
const k8sClient = new K8sClient(kubeConfigStr);
|
const k8sClient = new K8sClient(kubeConfigStr);
|
||||||
|
@ -154,9 +145,7 @@ export class DeployCertToTencentTKEIngressPlugin extends AbstractTaskPlugin {
|
||||||
};
|
};
|
||||||
const ret = await client.DescribeClusterKubeconfig(params);
|
const ret = await client.DescribeClusterKubeconfig(params);
|
||||||
this.checkRet(ret);
|
this.checkRet(ret);
|
||||||
this.logger.info(
|
this.logger.info('注意:后续操作需要在【集群->基本信息】中开启外网或内网访问,https://console.cloud.tencent.com/tke2/cluster');
|
||||||
'注意:后续操作需要在【集群->基本信息】中开启外网或内网访问,https://console.cloud.tencent.com/tke2/cluster'
|
|
||||||
);
|
|
||||||
return ret.Kubeconfig;
|
return ret.Kubeconfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline';
|
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline';
|
||||||
import tencentcloud from 'tencentcloud-sdk-nodejs';
|
import tencentcloud from 'tencentcloud-sdk-nodejs';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import dayjs from 'dayjs';
|
||||||
name: 'UploadCertToTencent',
|
name: 'UploadCertToTencent',
|
||||||
title: '上传证书到腾讯云',
|
title: '上传证书到腾讯云',
|
||||||
desc: '上传成功后输出:tencentCertId',
|
desc: '上传成功后输出:tencentCertId',
|
||||||
|
group: pluginGroups.tencent.key,
|
||||||
default: {
|
default: {
|
||||||
strategy: {
|
strategy: {
|
||||||
runStrategy: RunStrategy.SkipWhenSucceed,
|
runStrategy: RunStrategy.SkipWhenSucceed,
|
||||||
|
|
Loading…
Reference in New Issue