mirror of
https://github.com/certd/certd.git
synced 2026-07-28 15:47:40 +08:00
perf(tencent-clb): 为腾讯云CLB部署插件支持远程选择输入
- 重构插件输入配置,使用createRemoteSelectInputDefine统一封装远程选择组件 - 新增onGetCLBList、onGetListenerList、onGetDomainList方法实现数据拉取和格式转换 - 补全完整的单元测试用例,覆盖输入配置校验和数据映射逻辑
This commit is contained in:
+111
@@ -0,0 +1,111 @@
|
||||
/// <reference types="mocha" />
|
||||
|
||||
import assert from "node:assert/strict";
|
||||
import { DeployCertToTencentCLB } from "./index.js";
|
||||
|
||||
describe("DeployCertToTencentCLB", () => {
|
||||
it("uses remote single-select inputs for CLB and HTTPS listener", () => {
|
||||
const input = (DeployCertToTencentCLB as any).define.input;
|
||||
|
||||
assert.equal(input.loadBalancerId.component.name, "remote-select");
|
||||
assert.equal(input.loadBalancerId.component.single, true);
|
||||
assert.equal(input.loadBalancerId.component.action, "onGetCLBList");
|
||||
assert.equal(input.loadBalancerId.required, true);
|
||||
|
||||
assert.equal(input.listenerId.component.name, "remote-select");
|
||||
assert.equal(input.listenerId.component.single, true);
|
||||
assert.equal(input.listenerId.component.action, "onGetListenerList");
|
||||
assert.deepEqual(input.listenerId.component.watches, ["certDomains", "accessId", "region", "loadBalancerId"]);
|
||||
assert.equal(input.listenerId.required, true);
|
||||
|
||||
assert.equal(input.domain.component.name, "remote-select");
|
||||
assert.equal(input.domain.component.single, false);
|
||||
assert.equal(input.domain.component.action, "onGetDomainList");
|
||||
assert.deepEqual(input.domain.component.watches, ["certDomains", "accessId", "region", "loadBalancerId", "listenerId"]);
|
||||
assert.equal(input.domain.required, false);
|
||||
});
|
||||
|
||||
it("maps CLB API results to remote-select options", async () => {
|
||||
const plugin = new DeployCertToTencentCLB();
|
||||
plugin.accessId = "access-1";
|
||||
plugin.logger = { info: () => undefined } as any;
|
||||
(plugin as any).getClient = async () => ({});
|
||||
(plugin as any).getCLBList = async () => [
|
||||
{
|
||||
LoadBalancerId: "lb-1",
|
||||
LoadBalancerName: "业务负载均衡",
|
||||
},
|
||||
];
|
||||
|
||||
const options = await plugin.onGetCLBList({});
|
||||
|
||||
assert.deepEqual(options, [
|
||||
{
|
||||
value: "lb-1",
|
||||
label: "业务负载均衡<lb-1>",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("maps HTTPS listener API results after selecting a CLB", async () => {
|
||||
const plugin = new DeployCertToTencentCLB();
|
||||
plugin.accessId = "access-1";
|
||||
plugin.loadBalancerId = "lb-1";
|
||||
plugin.logger = { info: () => undefined } as any;
|
||||
(plugin as any).getClient = async () => ({});
|
||||
(plugin as any).getListenerList = async (_client: any, loadBalancerId: string, listenerIds: any) => {
|
||||
assert.equal(loadBalancerId, "lb-1");
|
||||
assert.equal(listenerIds, null);
|
||||
return [
|
||||
{
|
||||
ListenerId: "listener-1",
|
||||
ListenerName: "HTTPS监听器",
|
||||
Port: 443,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
const options = await plugin.onGetListenerList({});
|
||||
|
||||
assert.deepEqual(options, [
|
||||
{
|
||||
value: "listener-1",
|
||||
label: "HTTPS监听器:443<listener-1>",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("maps SNI domains from the selected listener rules", async () => {
|
||||
const plugin = new DeployCertToTencentCLB();
|
||||
plugin.accessId = "access-1";
|
||||
plugin.loadBalancerId = "lb-1";
|
||||
plugin.listenerId = "listener-1";
|
||||
plugin.logger = { info: () => undefined } as any;
|
||||
(plugin as any).getClient = async () => ({});
|
||||
(plugin as any).getListenerList = async (_client: any, loadBalancerId: string, listenerIds: string[]) => {
|
||||
assert.equal(loadBalancerId, "lb-1");
|
||||
assert.deepEqual(listenerIds, ["listener-1"]);
|
||||
return [
|
||||
{
|
||||
ListenerId: "listener-1",
|
||||
Rules: [{ Domain: "www.example.com" }, { Domain: "api.example.com" }],
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
const options = await plugin.onGetDomainList({});
|
||||
|
||||
assert.deepEqual(options, [
|
||||
{
|
||||
value: "www.example.com",
|
||||
label: "www.example.com",
|
||||
domain: "www.example.com",
|
||||
},
|
||||
{
|
||||
value: "api.example.com",
|
||||
label: "api.example.com",
|
||||
domain: "api.example.com",
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
+108
-20
@@ -1,7 +1,8 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, PageSearch, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
||||
import dayjs from "dayjs";
|
||||
import { TencentAccess } from "../../../plugin-lib/tencent/index.js";
|
||||
import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert";
|
||||
import { createRemoteSelectInputDefine } from "@certd/plugin-lib";
|
||||
@IsTaskPlugin({
|
||||
name: "DeployCertToTencentCLB",
|
||||
title: "腾讯云-部署到CLB",
|
||||
@@ -73,29 +74,44 @@ export class DeployCertToTencentCLB extends AbstractTaskPlugin {
|
||||
})
|
||||
region!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "负载均衡ID",
|
||||
required: true,
|
||||
})
|
||||
@TaskInput(
|
||||
createRemoteSelectInputDefine({
|
||||
title: "负载均衡ID",
|
||||
helper: "请选择要部署证书的负载均衡",
|
||||
action: DeployCertToTencentCLB.prototype.onGetCLBList.name,
|
||||
watches: ["region"],
|
||||
single: true,
|
||||
pager: false,
|
||||
search: false,
|
||||
})
|
||||
)
|
||||
loadBalancerId!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "监听器ID",
|
||||
required: true,
|
||||
})
|
||||
@TaskInput(
|
||||
createRemoteSelectInputDefine({
|
||||
title: "监听器ID",
|
||||
helper: "请选择要部署证书的HTTPS监听器",
|
||||
action: DeployCertToTencentCLB.prototype.onGetListenerList.name,
|
||||
watches: ["region", "loadBalancerId"],
|
||||
single: true,
|
||||
pager: false,
|
||||
search: false,
|
||||
})
|
||||
)
|
||||
listenerId!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "域名",
|
||||
required: false,
|
||||
component: {
|
||||
name: "a-select",
|
||||
vModel: "value",
|
||||
open: false,
|
||||
mode: "tags",
|
||||
},
|
||||
helper: "如果开启了sni,则此项必须填写,未开启,则不要填写",
|
||||
})
|
||||
@TaskInput(
|
||||
createRemoteSelectInputDefine({
|
||||
title: "域名",
|
||||
helper: "如果开启了SNI,请选择要部署证书的域名;未开启SNI时可以留空",
|
||||
action: DeployCertToTencentCLB.prototype.onGetDomainList.name,
|
||||
watches: ["region", "loadBalancerId", "listenerId"],
|
||||
required: false,
|
||||
single: false,
|
||||
pager: false,
|
||||
search: false,
|
||||
})
|
||||
)
|
||||
domain!: string | string[];
|
||||
|
||||
@TaskInput({
|
||||
@@ -272,6 +288,27 @@ export class DeployCertToTencentCLB extends AbstractTaskPlugin {
|
||||
return ret.LoadBalancerSet;
|
||||
}
|
||||
|
||||
async onGetCLBList(data: PageSearch) {
|
||||
if (!this.accessId) {
|
||||
throw new Error("请选择Access提供者");
|
||||
}
|
||||
|
||||
const client = await this.getClient();
|
||||
const list = await this.getCLBList(client);
|
||||
if (!list || list.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return list.map((item: any) => {
|
||||
const loadBalancerId = item.LoadBalancerId;
|
||||
const loadBalancerName = item.LoadBalancerName || loadBalancerId;
|
||||
return {
|
||||
value: loadBalancerId,
|
||||
label: `${loadBalancerName}<${loadBalancerId}>`,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async getListenerList(client: any, balancerId: any, listenerIds: any) {
|
||||
// HTTPS
|
||||
const params = {
|
||||
@@ -284,6 +321,57 @@ export class DeployCertToTencentCLB extends AbstractTaskPlugin {
|
||||
return ret.Listeners;
|
||||
}
|
||||
|
||||
async onGetListenerList(data: PageSearch) {
|
||||
if (!this.accessId) {
|
||||
throw new Error("请选择Access提供者");
|
||||
}
|
||||
if (!this.loadBalancerId) {
|
||||
throw new Error("请先选择负载均衡");
|
||||
}
|
||||
|
||||
const client = await this.getClient();
|
||||
const list = await this.getListenerList(client, this.loadBalancerId, null);
|
||||
if (!list || list.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return list.map((item: any) => {
|
||||
const listenerId = item.ListenerId;
|
||||
const listenerName = item.ListenerName || "HTTPS监听器";
|
||||
const port = item.Port ? `:${item.Port}` : "";
|
||||
return {
|
||||
value: listenerId,
|
||||
label: `${listenerName}${port}<${listenerId}>`,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async onGetDomainList(data: PageSearch) {
|
||||
if (!this.accessId) {
|
||||
throw new Error("请选择Access提供者");
|
||||
}
|
||||
if (!this.loadBalancerId) {
|
||||
throw new Error("请先选择负载均衡");
|
||||
}
|
||||
if (!this.listenerId) {
|
||||
throw new Error("请先选择监听器");
|
||||
}
|
||||
|
||||
const client = await this.getClient();
|
||||
const listeners = await this.getListenerList(client, this.loadBalancerId, [this.listenerId]);
|
||||
const listener = listeners?.[0];
|
||||
const domains = listener?.Rules?.map((rule: any) => rule.Domain).filter(Boolean) || [];
|
||||
const uniqueDomains = [...new Set(domains)];
|
||||
|
||||
return uniqueDomains.map(domain => {
|
||||
return {
|
||||
value: domain,
|
||||
label: domain,
|
||||
domain,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
checkRet(ret: any) {
|
||||
if (!ret || ret.Error) {
|
||||
throw new Error("执行失败:" + ret.Error.Code + "," + ret.Error.Message);
|
||||
|
||||
Reference in New Issue
Block a user