diff --git a/packages/ui/certd-server/package.json b/packages/ui/certd-server/package.json index 3fb26ba5e..4653692cb 100644 --- a/packages/ui/certd-server/package.json +++ b/packages/ui/certd-server/package.json @@ -46,6 +46,7 @@ "@certd/plugin-lib": "^1.29.5", "@certd/plugin-plus": "^1.29.5", "@certd/plus-core": "^1.29.5", + "@corsinvest/cv4pve-api-javascript": "^8.3.0", "@huaweicloud/huaweicloud-sdk-cdn": "^3.1.120", "@huaweicloud/huaweicloud-sdk-core": "^3.1.120", "@koa/cors": "^5.0.0", diff --git a/packages/ui/certd-server/src/plugins/plugin-proxmox/access.ts b/packages/ui/certd-server/src/plugins/plugin-proxmox/access.ts new file mode 100644 index 000000000..494a46633 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-proxmox/access.ts @@ -0,0 +1,63 @@ +import { IsAccess, AccessInput, BaseAccess } from '@certd/pipeline'; + +/** + * 这个注解将注册一个授权配置 + * 在certd的后台管理系统中,用户可以选择添加此类型的授权 + */ +@IsAccess({ + name: 'proxmox', + title: 'proxmox', + desc: '', + icon: 'svg:icon-dogecloud', +}) +export class ProxmoxAccess extends BaseAccess { + /** + * 授权属性配置 + */ + @AccessInput({ + title: 'host', + component: { + placeholder: 'IP或域名', + }, + required: true, + encrypt: false, + }) + host = ''; + + @AccessInput({ + title: '端口', + component: { + placeholder: '端口', + component: { + name: 'a-input-number', + }, + }, + required: true, + encrypt: false, + }) + port: number; + /** + * 授权属性配置 + */ + @AccessInput({ + title: '用户名', + component: { + placeholder: 'username', + }, + required: true, + encrypt: false, + }) + username = ''; + + @AccessInput({ + title: '密码', + component: { + placeholder: 'password', + }, + required: true, + encrypt: true, + }) + password = ''; +} + +new ProxmoxAccess(); diff --git a/packages/ui/certd-server/src/plugins/plugin-proxmox/index.ts b/packages/ui/certd-server/src/plugins/plugin-proxmox/index.ts new file mode 100644 index 000000000..fdad254fb --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-proxmox/index.ts @@ -0,0 +1,2 @@ +export * from './plugins/index.js'; +export * from './access.js'; diff --git a/packages/ui/certd-server/src/plugins/plugin-proxmox/plugins/index.ts b/packages/ui/certd-server/src/plugins/plugin-proxmox/plugins/index.ts new file mode 100644 index 000000000..672a272e9 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-proxmox/plugins/index.ts @@ -0,0 +1 @@ +export * from './plugin-upload.js'; diff --git a/packages/ui/certd-server/src/plugins/plugin-proxmox/plugins/plugin-upload.ts b/packages/ui/certd-server/src/plugins/plugin-proxmox/plugins/plugin-upload.ts new file mode 100644 index 000000000..65b2ae929 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-proxmox/plugins/plugin-upload.ts @@ -0,0 +1,108 @@ +import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; +import { CertInfo } from '@certd/plugin-cert'; +import { AbstractPlusTaskPlugin } from '@certd/plugin-plus'; +import { ProxmoxAccess } from '../access.js'; +import { createRemoteSelectInputDefine } from '@certd/plugin-lib'; + +@IsTaskPlugin({ + //命名规范,插件名称+功能(就是目录plugin-demo中的demo),大写字母开头,驼峰命名 + name: 'ProxmoxUploadCert', + title: '上传证书到Proxmox', + icon: 'clarity:plugin-line', + //插件分组 + group: pluginGroups.other.key, + needPlus: true, + default: { + //默认值配置照抄即可 + strategy: { + runStrategy: RunStrategy.SkipWhenSucceed, + }, + }, +}) +//类名规范,跟上面插件名称(name)一致 +export class ProxmoxUploadCert extends AbstractPlusTaskPlugin { + //证书选择,此项必须要有 + @TaskInput({ + title: '域名证书', + helper: '请选择前置任务输出的域名证书', + component: { + name: 'output-selector', + from: ['CertApply', 'CertApplyLego'], + }, + // required: true, // 必填 + }) + cert!: CertInfo; + + // @TaskInput(createCertDomainGetterInputDefine({ props: { required: false } })) + // //前端可以展示,当前申请的证书域名列表 + // certDomains!: string[]; + + //授权选择框 + @TaskInput({ + title: 'Proxmox授权', + component: { + name: 'access-selector', + type: 'proxmox', //固定授权类型 + }, + required: true, //必填 + }) + accessId!: string; + // + + @TaskInput( + createRemoteSelectInputDefine({ + title: '节点', + helper: '要部署证书的节点', + typeName: 'ProxmoxUploadCert', + action: ProxmoxUploadCert.prototype.onGetNodeList.name, + watches: ['accessId'], + }) + ) + nodes!: string[]; + + //插件实例化时执行的方法 + async onInstance() {} + + //插件执行方法 + async execute(): Promise { + const { cert } = this; + + const client = await this.getClient(); + + for (const node of this.nodes) { + this.logger.info(`开始上传证书到节点:${node}`); + const res = await client.nodes.get(node).certificates.custom.uploadCustomCert(cert.crt, false, cert.key, true); + this.logger.info(`上传结果:${JSON.stringify(res.response)}`); + } + + this.logger.info('部署成功'); + } + + async onGetNodeList() { + const client = await this.getClient(); + + const nodesRes = await client.nodes.index(); + // this.logger.info('nodes:', nodesRes.response); + return nodesRes.response.data.map((node: any) => { + return { + value: node.node, + label: node.node, + }; + }); + } + + async getClient() { + const access: ProxmoxAccess = await this.accessService.getById(this.accessId); + const pve = await import('@corsinvest/cv4pve-api-javascript'); + const client = new pve.PveClient(access.host, access.port); + const login = await client.login(access.username, access.password, 'pam'); + if (!login) { + throw new Error(`Login failed:${JSON.stringify(login)}`); + } + const versionRes = await client.version.version(); + this.logger.info('Proxmox version:', versionRes.response); + return client; + } +} +//实例化一下,注册插件 +new ProxmoxUploadCert();