Files
certd/packages/libs/lib-k8s/src/lib/k8s.client.ts
T

168 lines
5.5 KiB
TypeScript
Raw Normal View History

import { CoreV1Api, KubeConfig, NetworkingV1Api, V1Ingress, V1Secret } from "@kubernetes/client-node";
import dns from "dns";
import { ILogger } from "@certd/basic";
import _ from "lodash-es";
2022-11-07 23:31:20 +08:00
2024-08-14 15:10:55 +08:00
export type K8sClientOpts = {
kubeConfigStr: string;
logger: ILogger;
//{ [domain]:{ip:'xxx.xx.xxx'} }
//暂时没用
lookup?: any;
skipTLSVerify?: boolean;
2024-08-14 15:10:55 +08:00
};
2022-11-07 23:31:20 +08:00
export class K8sClient {
2024-08-14 15:10:55 +08:00
kubeconfig!: KubeConfig;
2022-11-07 23:31:20 +08:00
kubeConfigStr: string;
2024-08-14 15:10:55 +08:00
lookup!: (hostnameReq: any, options: any, callback: any) => void;
client!: CoreV1Api;
2024-08-06 10:22:28 +08:00
logger: ILogger;
skipTLSVerify?: boolean;
2024-08-14 15:10:55 +08:00
constructor(opts: K8sClientOpts) {
this.kubeConfigStr = opts.kubeConfigStr;
this.logger = opts.logger;
this.setLookup(opts.lookup);
this.skipTLSVerify = opts.skipTLSVerify;
2022-11-07 23:31:20 +08:00
this.init();
}
init() {
const kubeconfig = new KubeConfig();
kubeconfig.loadFromString(this.kubeConfigStr);
2024-08-14 15:10:55 +08:00
this.kubeconfig = kubeconfig;
try {
if (this.skipTLSVerify == true) {
for (const cluster of kubeconfig.getClusters()) {
// @ts-ignore
cluster["skipTLSVerify"] = this.skipTLSVerify;
}
}
} catch (e) {
this.logger.warn("skipTLSVerify error", e);
}
2024-08-14 15:10:55 +08:00
this.client = kubeconfig.makeApiClient(CoreV1Api);
2022-11-07 23:31:20 +08:00
2024-08-14 15:10:55 +08:00
// const reqOpts = { kubeconfig, request: {} } as any;
// if (this.lookup) {
// reqOpts.request.lookup = this.lookup;
// }
//
// const backend = new Request(reqOpts);
// this.client = new Client({ backend, version: '1.13' });
2022-11-07 23:31:20 +08:00
}
/**
*
* @param localRecords { [domain]:{ip:'xxx.xx.xxx'} }
*/
setLookup(localRecords: { [key: string]: { ip: string } }) {
2024-08-14 15:10:55 +08:00
if (localRecords == null) {
return;
}
2022-11-07 23:31:20 +08:00
this.lookup = (hostnameReq: any, options: any, callback: any) => {
this.logger.info("custom lookup", hostnameReq, localRecords);
2022-11-07 23:31:20 +08:00
if (localRecords[hostnameReq]) {
this.logger.info("local record", hostnameReq, localRecords[hostnameReq]);
2022-11-07 23:31:20 +08:00
callback(null, localRecords[hostnameReq].ip, 4);
} else {
dns.lookup(hostnameReq, options, callback);
}
};
}
/**
* 查询 secret列表
* @param opts = {namespace:default}
* @returns secretsList
*/
2024-08-14 15:10:55 +08:00
async getSecrets(opts: { namespace: string }) {
const namespace = opts.namespace || "default";
2024-08-14 15:10:55 +08:00
return await this.client.listNamespacedSecret(namespace);
2022-11-07 23:31:20 +08:00
}
/**
* 创建Secret
* @param opts {namespace:default, body:yamlStr}
* @returns {Promise<*>}
*/
2024-08-14 15:10:55 +08:00
async createSecret(opts: { namespace: string; body: V1Secret }) {
const namespace = opts.namespace || "default";
2024-08-14 15:10:55 +08:00
const created = await this.client.createNamespacedSecret(namespace, opts.body);
this.logger.info("new secrets:", opts.body);
2024-08-14 15:10:55 +08:00
return created.body;
2022-11-07 23:31:20 +08:00
}
2024-08-14 15:10:55 +08:00
// async updateSecret(opts: any) {
// const namespace = opts.namespace || 'default';
// const secretName = opts.secretName;
// if (secretName == null) {
// throw new Error('secretName 不能为空');
// }
// return await this.client.replaceNamespacedSecret(secretName, namespace, opts.body);
// }
2022-11-07 23:31:20 +08:00
2024-08-14 15:10:55 +08:00
async patchSecret(opts: { namespace: string; secretName: string; body: V1Secret }) {
const namespace = opts.namespace || "default";
2022-11-07 23:31:20 +08:00
const secretName = opts.secretName;
if (secretName == null) {
throw new Error("secretName 不能为空");
2022-11-07 23:31:20 +08:00
}
this.logger.info("patch secret:", secretName, namespace);
2024-09-19 14:23:15 +08:00
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");
2024-08-14 15:10:55 +08:00
return res.body;
2022-11-07 23:31:20 +08:00
}
2024-08-14 15:10:55 +08:00
async getIngressList(opts: { namespace: string }) {
const namespace = opts.namespace || "default";
2024-08-14 15:10:55 +08:00
const client = this.kubeconfig.makeApiClient(NetworkingV1Api);
const res = await client.listNamespacedIngress(namespace);
this.logger.info("ingress list get:", res.body);
2024-08-14 15:10:55 +08:00
return res.body;
2022-11-07 23:31:20 +08:00
}
2024-08-14 15:10:55 +08:00
// async getIngress(opts: { namespace: string; ingressName: string }) {
// const namespace = opts.namespace || 'default';
// const ingressName = opts.ingressName;
// if (!ingressName) {
// throw new Error('ingressName 不能为空');
// }
// const client = this.kubeconfig.makeApiClient(NetworkingV1Api);
// const res = await client.listNamespacedIngress();
// return await this.client.apis.extensions.v1beta1.namespaces(namespace).ingresses(ingressName).get();
// }
2022-11-07 23:31:20 +08:00
2024-08-14 15:10:55 +08:00
async patchIngress(opts: { namespace: string; ingressName: string; body: V1Ingress }) {
const namespace = opts.namespace || "default";
2022-11-07 23:31:20 +08:00
const ingressName = opts.ingressName;
if (!ingressName) {
throw new Error("ingressName 不能为空");
2022-11-07 23:31:20 +08:00
}
this.logger.info("patch ingress:", ingressName, namespace);
2024-08-14 15:10:55 +08:00
const client = this.kubeconfig.makeApiClient(NetworkingV1Api);
2024-09-19 14:23:15 +08:00
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);
2024-08-14 15:10:55 +08:00
return res;
2022-11-07 23:31:20 +08:00
}
2025-07-24 16:22:07 +08:00
async restartIngress(namespace: string, ingressNames: string[], labels: any) {
const body = {
metadata: {
labels: {
...labels,
},
},
};
for (const ingress of ingressNames) {
await this.patchIngress({ namespace, ingressName: ingress, body });
this.logger.info(`ingress已重启:${ingress}`);
}
}
2022-11-07 23:31:20 +08:00
}