mirror of https://github.com/certd/certd
perf: 支持k8s ingress secret
parent
60ea9106f1
commit
e5a5d0a607
|
@ -8,6 +8,7 @@ import { IContext } from "../core/index.js";
|
|||
import { ILogger, logger } from "../utils/index.js";
|
||||
import { HttpClient } from "../utils/util.request";
|
||||
import { utils } from "../utils/index.js";
|
||||
import dayjs from "dayjs";
|
||||
export enum ContextScope {
|
||||
global,
|
||||
pipeline,
|
||||
|
@ -138,6 +139,13 @@ export abstract class AbstractTaskPlugin implements ITaskPlugin {
|
|||
}
|
||||
|
||||
abstract execute(): Promise<void>;
|
||||
|
||||
appendTimeSuffix(name?: string) {
|
||||
if (name == null) {
|
||||
name = "certd";
|
||||
}
|
||||
return name + "_" + dayjs().format("YYYYMMDDHHmmss");
|
||||
}
|
||||
}
|
||||
|
||||
export type OutputVO = {
|
||||
|
|
|
@ -33,9 +33,11 @@ export class HttpError extends Error {
|
|||
delete error.response;
|
||||
delete error.config;
|
||||
delete error.request;
|
||||
logger.error(error);
|
||||
// logger.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
export const HttpCommonError = HttpError;
|
||||
/**
|
||||
* @description 创建请求实例
|
||||
*/
|
||||
|
@ -118,7 +120,7 @@ export function createAxiosService({ logger }: { logger: Logger }) {
|
|||
logger.error("返回数据:", JSON.stringify(error.response?.data));
|
||||
|
||||
if (error instanceof AggregateError) {
|
||||
logger.error(error);
|
||||
logger.error("AggregateError", error);
|
||||
}
|
||||
const err = new HttpError(error);
|
||||
return Promise.reject(err);
|
||||
|
|
|
@ -1 +1 @@
|
|||
export * from "./lib/k8s.client.js";
|
||||
export * from './lib/k8s.client.js';
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { KubeConfig, CoreV1Api, V1Secret, NetworkingV1Api, V1Ingress } from '@kubernetes/client-node';
|
||||
import { CoreV1Api, KubeConfig, NetworkingV1Api, V1Ingress, V1Secret } from '@kubernetes/client-node';
|
||||
import dns from 'dns';
|
||||
import { ILogger } from '@certd/pipeline';
|
||||
import _ from 'lodash-es';
|
||||
|
||||
export type K8sClientOpts = {
|
||||
kubeConfigStr: string;
|
||||
|
@ -74,7 +75,7 @@ export class K8sClient {
|
|||
async createSecret(opts: { namespace: string; body: V1Secret }) {
|
||||
const namespace = opts.namespace || 'default';
|
||||
const created = await this.client.createNamespacedSecret(namespace, opts.body);
|
||||
this.logger.info('new secrets:', created.body);
|
||||
this.logger.info('new secrets:', opts.body);
|
||||
return created.body;
|
||||
}
|
||||
|
||||
|
@ -93,8 +94,11 @@ export class K8sClient {
|
|||
if (secretName == null) {
|
||||
throw new Error('secretName 不能为空');
|
||||
}
|
||||
const res = await this.client.patchNamespacedSecret(secretName, namespace, opts.body);
|
||||
this.logger.info('secret patched:', res.body);
|
||||
this.logger.info('patch secret:', secretName, namespace);
|
||||
const oldSecret = await this.client.readNamespacedSecret(secretName, namespace);
|
||||
const newSecret = _.merge(oldSecret.body, opts.body);
|
||||
const res = await this.client.replaceNamespacedSecret(secretName, namespace, newSecret);
|
||||
this.logger.info('secret updated');
|
||||
return res.body;
|
||||
}
|
||||
|
||||
|
@ -123,9 +127,12 @@ export class K8sClient {
|
|||
if (!ingressName) {
|
||||
throw new Error('ingressName 不能为空');
|
||||
}
|
||||
this.logger.info('patch ingress:', ingressName, namespace);
|
||||
const client = this.kubeconfig.makeApiClient(NetworkingV1Api);
|
||||
const res = await client.patchNamespacedIngress(ingressName, namespace, opts.body);
|
||||
this.logger.info('ingress patched:', res.body);
|
||||
const oldIngress = await client.readNamespacedIngress(ingressName, namespace);
|
||||
const newIngress = _.merge(oldIngress.body, opts.body);
|
||||
const res = await client.replaceNamespacedIngress(ingressName, namespace, newIngress);
|
||||
this.logger.info('ingress patched', opts.body);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
export * from './k8s-access.js';
|
|
@ -1,22 +0,0 @@
|
|||
import { IsAccess, AccessInput } from '@certd/pipeline';
|
||||
|
||||
@IsAccess({
|
||||
name: 'k8s',
|
||||
title: 'k8s授权',
|
||||
desc: '',
|
||||
})
|
||||
export class K8sAccess {
|
||||
@AccessInput({
|
||||
title: 'kubeconfig',
|
||||
component: {
|
||||
name: 'a-textarea',
|
||||
vModel: 'value',
|
||||
placeholder: 'kubeconfig',
|
||||
},
|
||||
required: true,
|
||||
encrypt: true,
|
||||
})
|
||||
kubeconfig = '';
|
||||
}
|
||||
|
||||
new K8sAccess();
|
|
@ -1,3 +1,2 @@
|
|||
export * from './plugin-k8s.js';
|
||||
export * from './plugin-restart.js';
|
||||
export * from './plugin-script.js';
|
||||
|
|
|
@ -1,114 +0,0 @@
|
|||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, utils } from '@certd/pipeline';
|
||||
import { CertInfo } from '@certd/plugin-cert';
|
||||
import { K8sAccess } from '../access/index.js';
|
||||
import { appendTimeSuffix } from '../../plugin-aliyun/utils/index.js';
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: 'DeployToK8SIngress',
|
||||
title: 'K8S Ingress证书部署',
|
||||
desc: '暂不可用',
|
||||
group: pluginGroups.other.key,
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.SkipWhenSucceed,
|
||||
},
|
||||
},
|
||||
})
|
||||
export class K8STestPlugin extends AbstractTaskPlugin {
|
||||
@TaskInput({
|
||||
title: '命名空间',
|
||||
value: 'default',
|
||||
component: {
|
||||
placeholder: '命名空间',
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
namespace!: string;
|
||||
@TaskInput({
|
||||
title: 'ingress名称',
|
||||
value: '',
|
||||
component: {
|
||||
placeholder: 'ingress名称',
|
||||
},
|
||||
required: true,
|
||||
helper: '可以传入一个数组',
|
||||
})
|
||||
ingressName!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '保密字典Id',
|
||||
component: {
|
||||
placeholder: '保密字典Id',
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
secretName!: string | string[];
|
||||
|
||||
@TaskInput({
|
||||
title: 'k8s授权',
|
||||
helper: 'kubeconfig',
|
||||
component: {
|
||||
name: 'pi-access-selector',
|
||||
type: 'k8s',
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
accessId!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '域名证书',
|
||||
helper: '请选择前置任务输出的域名证书',
|
||||
component: {
|
||||
name: 'pi-output-selector',
|
||||
from: ['CertApply', 'CertApplyLego'],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
cert!: CertInfo;
|
||||
|
||||
K8sClient: any;
|
||||
async onInstance() {
|
||||
const sdk = await import('@certd/lib-k8s');
|
||||
this.K8sClient = sdk.K8sClient;
|
||||
}
|
||||
async execute(): Promise<void> {
|
||||
const access: K8sAccess = await this.accessService.getById(this.accessId);
|
||||
const k8sClient = new this.K8sClient({
|
||||
kubeConfigStr: access.kubeconfig,
|
||||
logger: this.logger,
|
||||
});
|
||||
await this.patchNginxCertSecret({ cert: this.cert, k8sClient });
|
||||
await utils.sleep(3000); // 停留2秒,等待secret部署完成
|
||||
}
|
||||
|
||||
async patchNginxCertSecret(options: { cert: CertInfo; 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 } = this;
|
||||
|
||||
const body: any = {
|
||||
data: {
|
||||
'tls.crt': crtBase64,
|
||||
'tls.key': keyBase64,
|
||||
},
|
||||
metadata: {
|
||||
labels: {
|
||||
certd: appendTimeSuffix('certd'),
|
||||
},
|
||||
},
|
||||
};
|
||||
let secretNames: any = secretName;
|
||||
if (typeof secretName === 'string') {
|
||||
secretNames = [secretName];
|
||||
}
|
||||
for (const secret of secretNames) {
|
||||
await k8sClient.patchSecret({ namespace, secretName: secret, body });
|
||||
this.logger.info(`ingress cert Secret已更新:${secret}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
new K8STestPlugin();
|
Loading…
Reference in New Issue