feat: custom k8s secret annotations and labels

This commit is contained in:
Fu Diwei
2025-09-06 00:16:32 +08:00
parent 145eadad2f
commit ed03acd5a2
5 changed files with 169 additions and 0 deletions
@@ -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)
}
@@ -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": "替换指定证书",