mirror of
https://github.com/certimate-go/certimate.git
synced 2026-09-24 23:10:13 +08:00
feat: custom k8s secret annotations and labels
This commit is contained in:
@@ -2,6 +2,7 @@ package deployers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/certimate-go/certimate/internal/domain"
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
@@ -16,6 +17,50 @@ func init() {
|
||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||
}
|
||||
|
||||
parseKeyValueMap := func(s string) (map[string]string, error) {
|
||||
result := make(map[string]string)
|
||||
|
||||
lines := strings.Split(s, "\n")
|
||||
for i, line := range lines {
|
||||
if strings.TrimSpace(line) == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
pos := strings.Index(line, ":")
|
||||
if pos == -1 {
|
||||
return nil, fmt.Errorf("invalid line format at line %d", i+1)
|
||||
}
|
||||
|
||||
key := strings.TrimSpace(line[:pos])
|
||||
value := strings.TrimSpace(line[pos+1:])
|
||||
if key == "" {
|
||||
return nil, fmt.Errorf("invalid key at line %d", i+1)
|
||||
}
|
||||
|
||||
result[key] = value
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
secretAnnotations := make(map[string]string)
|
||||
if secretAnnotationsString := xmaps.GetString(options.ProviderExtendedConfig, "secretAnnotations"); secretAnnotationsString != "" {
|
||||
temp, err := parseKeyValueMap(secretAnnotationsString)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse kubernetes secret annotations: %w", err)
|
||||
}
|
||||
secretAnnotations = temp
|
||||
}
|
||||
|
||||
secretLabels := make(map[string]string)
|
||||
if secretLabelsString := xmaps.GetString(options.ProviderExtendedConfig, "secretLabels"); secretLabelsString != "" {
|
||||
temp, err := parseKeyValueMap(secretLabelsString)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse kubernetes secret labels: %w", err)
|
||||
}
|
||||
secretLabels = temp
|
||||
}
|
||||
|
||||
provider, err := k8ssecret.NewSSLDeployerProvider(&k8ssecret.SSLDeployerProviderConfig{
|
||||
KubeConfig: credentials.KubeConfig,
|
||||
Namespace: xmaps.GetOrDefaultString(options.ProviderExtendedConfig, "namespace", "default"),
|
||||
@@ -23,6 +68,8 @@ func init() {
|
||||
SecretType: xmaps.GetOrDefaultString(options.ProviderExtendedConfig, "secretType", "kubernetes.io/tls"),
|
||||
SecretDataKeyForCrt: xmaps.GetOrDefaultString(options.ProviderExtendedConfig, "secretDataKeyForCrt", "tls.crt"),
|
||||
SecretDataKeyForKey: xmaps.GetOrDefaultString(options.ProviderExtendedConfig, "secretDataKeyForKey", "tls.key"),
|
||||
SecretAnnotations: secretAnnotations,
|
||||
SecretLabels: secretLabels,
|
||||
})
|
||||
return provider, err
|
||||
}); err != nil {
|
||||
|
||||
@@ -30,6 +30,10 @@ type SSLDeployerProviderConfig struct {
|
||||
SecretDataKeyForCrt string `json:"secretDataKeyForCrt,omitempty"`
|
||||
// Kubernetes Secret 中用于存放私钥的 Key。
|
||||
SecretDataKeyForKey string `json:"secretDataKeyForKey,omitempty"`
|
||||
// Kubernetes Secret 注解。
|
||||
SecretAnnotations map[string]string `json:"secretAnnotations,omitempty"`
|
||||
// Kubernetes Secret 标签。
|
||||
SecretLabels map[string]string `json:"secretLabels,omitempty"`
|
||||
}
|
||||
|
||||
type SSLDeployerProvider struct {
|
||||
@@ -94,6 +98,17 @@ func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privke
|
||||
"certimate/issuer-sn": certX509.Issuer.SerialNumber,
|
||||
"certimate/issuer-org": strings.Join(certX509.Issuer.Organization, ","),
|
||||
}
|
||||
secretLabels := map[string]string{}
|
||||
if d.config.SecretAnnotations != nil {
|
||||
for k, v := range d.config.SecretAnnotations {
|
||||
secretAnnotations[k] = v
|
||||
}
|
||||
}
|
||||
if d.config.SecretLabels != nil {
|
||||
for k, v := range d.config.SecretLabels {
|
||||
secretLabels[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// 获取 Secret 实例,如果不存在则创建
|
||||
secretPayload, err = client.CoreV1().Secrets(d.config.Namespace).Get(context.TODO(), d.config.SecretName, k8smeta.GetOptions{})
|
||||
@@ -106,6 +121,7 @@ func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privke
|
||||
ObjectMeta: k8smeta.ObjectMeta{
|
||||
Name: d.config.SecretName,
|
||||
Annotations: secretAnnotations,
|
||||
Labels: secretLabels,
|
||||
},
|
||||
Type: k8score.SecretType(d.config.SecretType),
|
||||
}
|
||||
@@ -131,6 +147,13 @@ func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privke
|
||||
secretPayload.ObjectMeta.Annotations[k] = v
|
||||
}
|
||||
}
|
||||
if secretPayload.ObjectMeta.Labels == nil {
|
||||
secretPayload.ObjectMeta.Labels = secretLabels
|
||||
} else {
|
||||
for k, v := range secretLabels {
|
||||
secretPayload.ObjectMeta.Labels[k] = v
|
||||
}
|
||||
}
|
||||
if secretPayload.Data == nil {
|
||||
secretPayload.Data = make(map[string][]byte)
|
||||
}
|
||||
|
||||
+79
@@ -3,6 +3,8 @@ import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import CodeInput from "@/components/CodeInput";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFieldsProviderKubernetesSecret = () => {
|
||||
@@ -13,8 +15,23 @@ const BizDeployNodeConfigFieldsProviderKubernetesSecret = () => {
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const formInst = Form.useFormInstance();
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
const handleSecretAnnotationsBlur = () => {
|
||||
let value = formInst.getFieldValue([parentNamePath, "secretAnnotations"]);
|
||||
value = value.trim();
|
||||
value = value.replace(/(?<!\r)\n/g, "\r\n");
|
||||
formInst.setFieldValue([parentNamePath, "secretAnnotations"], value);
|
||||
};
|
||||
|
||||
const handleSecretLabelsBlur = () => {
|
||||
let value = formInst.getFieldValue([parentNamePath, "secretLabels"]);
|
||||
value = value.trim();
|
||||
value = value.replace(/(?<!\r)\n/g, "\r\n");
|
||||
formInst.setFieldValue([parentNamePath, "secretLabels"], value);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
@@ -66,6 +83,40 @@ const BizDeployNodeConfigFieldsProviderKubernetesSecret = () => {
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.k8s_secret_data_key_for_key.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "secretAnnotations"]}
|
||||
initialValue={initialValues.secretAnnotations}
|
||||
label={t("workflow_node.deploy.form.k8s_secret_annotations.label")}
|
||||
extra={t("workflow_node.deploy.form.k8s_secret_annotations.help")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.k8s_secret_annotations.tooltip") }}></span>}
|
||||
>
|
||||
<CodeInput
|
||||
height="auto"
|
||||
minHeight="64px"
|
||||
maxHeight="256px"
|
||||
placeholder={t("workflow_node.deploy.form.k8s_secret_annotations.placeholder")}
|
||||
onBlur={handleSecretAnnotationsBlur}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "secretLabels"]}
|
||||
initialValue={initialValues.secretLabels}
|
||||
label={t("workflow_node.deploy.form.k8s_secret_labels.label")}
|
||||
extra={t("workflow_node.deploy.form.k8s_secret_labels.help")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.k8s_secret_labels.tooltip") }}></span>}
|
||||
>
|
||||
<CodeInput
|
||||
height="auto"
|
||||
minHeight="64px"
|
||||
maxHeight="256px"
|
||||
placeholder={t("workflow_node.deploy.form.k8s_secret_labels.placeholder")}
|
||||
onBlur={handleSecretLabelsBlur}
|
||||
/>
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -88,6 +139,34 @@ const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> })
|
||||
secretType: z.string().nonempty(t("workflow_node.deploy.form.k8s_secret_type.placeholder")),
|
||||
secretDataKeyForCrt: z.string().nonempty(t("workflow_node.deploy.form.k8s_secret_data_key_for_crt.placeholder")),
|
||||
secretDataKeyForKey: z.string().nonempty(t("workflow_node.deploy.form.k8s_secret_data_key_for_key.placeholder")),
|
||||
secretAnnotations: z
|
||||
.string()
|
||||
.nullish()
|
||||
.refine((v) => {
|
||||
if (!v) return true;
|
||||
|
||||
const lines = v.split(/\r?\n/);
|
||||
for (const line of lines) {
|
||||
if (line.split(":").length < 2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}, t("workflow_node.deploy.form.k8s_secret_annotations.errmsg.invalid")),
|
||||
secretLabels: z
|
||||
.string()
|
||||
.nullish()
|
||||
.refine((v) => {
|
||||
if (!v) return true;
|
||||
|
||||
const lines = v.split(/\r?\n/);
|
||||
for (const line of lines) {
|
||||
if (line.split(":").length < 2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}, t("workflow_node.deploy.form.k8s_secret_labels.errmsg.invalid")),
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -594,6 +594,16 @@
|
||||
"workflow_node.deploy.form.k8s_secret_data_key_for_key.label": "Kubernetes Secret data key for private key",
|
||||
"workflow_node.deploy.form.k8s_secret_data_key_for_key.placeholder": "Please enter Kubernetes Secret data key for private key",
|
||||
"workflow_node.deploy.form.k8s_secret_data_key_for_key.tooltip": "For more information, see <a href=\"https://kubernetes.io/docs/concepts/configuration/secret/\" target=\"_blank\">https://kubernetes.io/docs/concepts/configuration/secret/</a>",
|
||||
"workflow_node.deploy.form.k8s_secret_annotations.label": "Kubernetes Secret annotations (Optional)",
|
||||
"workflow_node.deploy.form.k8s_secret_annotations.placeholder": "Please enter Kubernetes Secret annotations",
|
||||
"workflow_node.deploy.form.k8s_secret_annotations.help": "Notes: One key value pair per line, separated by colon.",
|
||||
"workflow_node.deploy.form.k8s_secret_annotations.errmsg.invalid": "Please enter a valid annotations",
|
||||
"workflow_node.deploy.form.k8s_secret_annotations.tooltip": "Example: <br><i>environment: production<br>app: nginx</i>",
|
||||
"workflow_node.deploy.form.k8s_secret_labels.label": "Kubernetes Secret labels (Optional)",
|
||||
"workflow_node.deploy.form.k8s_secret_labels.placeholder": "Please enter Kubernetes Secret labels",
|
||||
"workflow_node.deploy.form.k8s_secret_labels.help": "Notes: One key value pair per line, separated by colon.",
|
||||
"workflow_node.deploy.form.k8s_secret_labels.errmsg.invalid": "Please enter a valid labels",
|
||||
"workflow_node.deploy.form.k8s_secret_labels.tooltip": "Example: <br><i>environment: production<br>app: nginx</i>",
|
||||
"workflow_node.deploy.form.kong_resource_type.label": "Resource type",
|
||||
"workflow_node.deploy.form.kong_resource_type.placeholder": "Please select resource type",
|
||||
"workflow_node.deploy.form.kong_resource_type.option.certificate.label": "SSL certificate",
|
||||
|
||||
@@ -592,6 +592,16 @@
|
||||
"workflow_node.deploy.form.k8s_secret_data_key_for_key.label": "Kubernetes Secret 数据键(用于存放私钥的字段)",
|
||||
"workflow_node.deploy.form.k8s_secret_data_key_for_key.placeholder": "请输入 Kubernetes Secret 中用于存放私钥的数据键",
|
||||
"workflow_node.deploy.form.k8s_secret_data_key_for_key.tooltip": "这是什么?请参阅 <a href=\"https://kubernetes.io/zh-cn/docs/concepts/configuration/secret/\" target=\"_blank\">https://kubernetes.io/zh-cn/docs/concepts/configuration/secret/</a>",
|
||||
"workflow_node.deploy.form.k8s_secret_annotations.label": "Kubernetes Secret 注解(可选)",
|
||||
"workflow_node.deploy.form.k8s_secret_annotations.placeholder": "请输入 Kubernetes Secret 注解",
|
||||
"workflow_node.deploy.form.k8s_secret_annotations.help": "提示:每行一个键值对,以分号分隔。",
|
||||
"workflow_node.deploy.form.k8s_secret_annotations.errmsg.invalid": "请输入有效的注解键值对",
|
||||
"workflow_node.deploy.form.k8s_secret_annotations.tooltip": "示例:<br><i>environment: production<br>app: nginx</i>",
|
||||
"workflow_node.deploy.form.k8s_secret_labels.label": "Kubernetes Secret 标签(可选)",
|
||||
"workflow_node.deploy.form.k8s_secret_labels.placeholder": "请输入 Kubernetes Secret 标签",
|
||||
"workflow_node.deploy.form.k8s_secret_labels.help": "提示:每行一个键值对,以分号分隔。",
|
||||
"workflow_node.deploy.form.k8s_secret_labels.errmsg.invalid": "请输入有效的标签键值对",
|
||||
"workflow_node.deploy.form.k8s_secret_labels.tooltip": "示例:<br><i>environment: production<br>app: nginx</i>",
|
||||
"workflow_node.deploy.form.kong_resource_type.label": "证书部署方式",
|
||||
"workflow_node.deploy.form.kong_resource_type.placeholder": "请选择证书部署方式",
|
||||
"workflow_node.deploy.form.kong_resource_type.option.certificate.label": "替换指定证书",
|
||||
|
||||
Reference in New Issue
Block a user