feat: support configuring renewal interval in application

This commit is contained in:
Fu Diwei 2025-01-19 05:37:28 +08:00
parent 60a13aaf17
commit c71d14cafa
6 changed files with 78 additions and 17 deletions

View File

@ -68,7 +68,7 @@ type WorkflowNodeConfigForApply struct {
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout"` // DNS 传播超时时间(默认取决于提供商)
DnsTTL int32 `json:"dnsTTL"` // DNS TTL默认取决于提供商
DisableFollowCNAME bool `json:"disableFollowCNAME"` // 是否禁用 CNAME 跟随
SkipBeforeExpiryDays int32 `json:"skipBeforeExpiryDays"` // TODO: 证书到期前多少天前跳过续期默认值30
SkipBeforeExpiryDays int32 `json:"skipBeforeExpiryDays"` // 证书到期前多少天前跳过续期默认值30
}
type WorkflowNodeConfigForDeploy struct {

View File

@ -109,9 +109,6 @@ func (a *applyNode) Run(ctx context.Context) error {
}
func (a *applyNode) checkCanSkip(ctx context.Context, lastOutput *domain.WorkflowOutput) (skip bool, reason string) {
const validityDuration = time.Hour * 24 * 10
// TODO: 可控制是否强制申请
if lastOutput != nil && lastOutput.Succeeded {
// 比较和上次申请时的关键配置(即影响证书签发的)参数是否一致
currentNodeConfig := a.node.GetConfigForApply()
@ -133,7 +130,8 @@ func (a *applyNode) checkCanSkip(ctx context.Context, lastOutput *domain.Workflo
}
lastCertificate, _ := a.certRepo.GetByWorkflowNodeId(ctx, a.node.Id)
if lastCertificate != nil && time.Until(lastCertificate.ExpireAt) > validityDuration {
renewalInterval := time.Duration(currentNodeConfig.SkipBeforeExpiryDays) * time.Hour * 24
if lastCertificate != nil && time.Until(lastCertificate.ExpireAt) > renewalInterval {
return true, "已申请过证书,且证书尚未临近过期"
}
}

View File

@ -2,7 +2,22 @@ import { forwardRef, memo, useEffect, useImperativeHandle, useMemo, useState } f
import { useTranslation } from "react-i18next";
import { FormOutlined as FormOutlinedIcon, PlusOutlined as PlusOutlinedIcon, QuestionCircleOutlined as QuestionCircleOutlinedIcon } from "@ant-design/icons";
import { useControllableValue } from "ahooks";
import { AutoComplete, type AutoCompleteProps, Button, Divider, Form, type FormInstance, Input, Select, Space, Switch, Tooltip, Typography } from "antd";
import {
AutoComplete,
type AutoCompleteProps,
Button,
Divider,
Flex,
Form,
type FormInstance,
Input,
InputNumber,
Select,
Space,
Switch,
Tooltip,
Typography,
} from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
@ -43,6 +58,7 @@ const initFormModel = (): ApplyNodeConfigFormFieldValues => {
return {
keyAlgorithm: "RSA2048",
disableFollowCNAME: true,
skipBeforeExpiryDays: 20,
};
};
@ -89,6 +105,11 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
])
.nullish(),
disableFollowCNAME: z.boolean().nullish(),
skipBeforeExpiryDays: z
.number({ message: t("workflow_node.apply.form.skip_before_expiry_days.placeholder") })
.int(t("workflow_node.apply.form.skip_before_expiry_days.placeholder"))
.gte(1, t("workflow_node.apply.form.skip_before_expiry_days.placeholder"))
.lte(60, t("workflow_node.apply.form.skip_before_expiry_days.placeholder")),
});
const formRule = createSchemaFieldRule(formSchema);
const { form: formInst, formProps } = useAntdForm({
@ -329,7 +350,7 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
min={0}
max={3600}
placeholder={t("workflow_node.apply.form.dns_propagation_timeout.placeholder")}
addonAfter={t("workflow_node.apply.form.dns_propagation_timeout.suffix")}
addonAfter={t("workflow_node.apply.form.dns_propagation_timeout.unit")}
/>
</Form.Item>
@ -345,7 +366,7 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
min={0}
max={86400}
placeholder={t("workflow_node.apply.form.dns_ttl.placeholder")}
addonAfter={t("workflow_node.apply.form.dns_ttl.suffix")}
addonAfter={t("workflow_node.apply.form.dns_ttl.unit")}
/>
</Form.Item>
@ -358,6 +379,33 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
<Switch />
</Form.Item>
</Form>
<Divider className="my-1">
<Typography.Text className="text-xs font-normal" type="secondary">
{t("workflow_node.apply.form.strategy_config.label")}
</Typography.Text>
</Divider>
<Form className={className} style={style} {...formProps} disabled={disabled} layout="vertical" scrollToFirstError onValuesChange={handleFormChange}>
<Form.Item
label={t("workflow_node.apply.form.skip_before_expiry_days.label")}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.skip_before_expiry_days.tooltip") }}></span>}
>
<Flex align="center" gap={8}>
<div>{t("workflow_node.apply.form.skip_before_expiry_days.prefix")}</div>
<Form.Item name="skipBeforeExpiryDays" noStyle rules={[formRule]}>
<InputNumber
className="flex-1"
min={1}
max={60}
placeholder={t("workflow_node.apply.form.skip_before_expiry_days.placeholder")}
addonAfter={t("workflow_node.apply.form.skip_before_expiry_days.unit")}
/>
</Form.Item>
<div>{t("workflow_node.apply.form.skip_before_expiry_days.suffix")}</div>
</Flex>
</Form.Item>
</Form>
</Form.Provider>
);
}

View File

@ -111,6 +111,7 @@ export type WorkflowNodeConfigForApply = {
dnsPropagationTimeout?: number;
dnsTTL?: number;
disableFollowCNAME?: boolean;
skipBeforeExpiryDays: number;
};
export type WorkflowNodeConfigForDeploy = {

View File

@ -51,19 +51,26 @@
"workflow_node.apply.form.key_algorithm.placeholder": "Please select certificate key algorithm",
"workflow_node.apply.form.nameservers.label": "DNS recursive nameservers (Optional)",
"workflow_node.apply.form.nameservers.placeholder": "Please enter DNS recursive nameservers (separated by semicolons)",
"workflow_node.apply.form.nameservers.tooltip": "It determines whether to custom DNS recursive nameservers during ACME DNS-01 authentication. If you don't understand this option, just keep it by default.<br><a href=\"https://go-acme.github.io/lego/usage/cli/options/index.html#dns-resolvers-and-challenge-verification\" target=\"_blank\">Learn more</a>.",
"workflow_node.apply.form.nameservers.tooltip": "It determines whether to custom DNS recursive nameservers during ACME DNS-01 authentication. If you don't understand this option, just keep it by default.<a href=\"https://go-acme.github.io/lego/usage/cli/options/index.html#dns-resolvers-and-challenge-verification\" target=\"_blank\">Learn more</a>.",
"workflow_node.apply.form.nameservers.multiple_input_modal.title": "Change DNS rcursive nameservers",
"workflow_node.apply.form.nameservers.multiple_input_modal.placeholder": "Please enter DNS recursive nameserver",
"workflow_node.apply.form.dns_propagation_timeout.label": "DNS propagation timeout (Optional)",
"workflow_node.apply.form.dns_propagation_timeout.placeholder": "Please enter DNS propagation timeout",
"workflow_node.apply.form.dns_propagation_timeout.suffix": "seconds",
"workflow_node.apply.form.dns_propagation_timeout.unit": "seconds",
"workflow_node.apply.form.dns_propagation_timeout.tooltip": "It determines the maximum waiting time for DNS propagation checks during ACME DNS-01 authentication. If you don't understand this option, just keep it by default.<br><br>Leave blank to use the default value provided by the provider.",
"workflow_node.apply.form.dns_ttl.label": "DNS TTL (Optional)",
"workflow_node.apply.form.dns_ttl.placeholder": "Please enter DNS TTL",
"workflow_node.apply.form.dns_ttl.suffix": "seconds",
"workflow_node.apply.form.dns_ttl.unit": "seconds",
"workflow_node.apply.form.dns_ttl.tooltip": "It determines the time to live for DNS record during ACME DNS-01 authentication. If you don't understand this option, just keep it by default.<br><br>Leave blank to use the default value provided by the provider.",
"workflow_node.apply.form.disable_follow_cname.label": "Disable CNAME following",
"workflow_node.apply.form.disable_follow_cname.tooltip": "It determines whether to disable CNAME following during ACME DNS-01 authentication. If you don't understand this option, just keep it by default.<br><a href=\"https://letsencrypt.org/2019/10/09/onboarding-your-customers-with-lets-encrypt-and-acme/#the-advantages-of-a-cname\" target=\"_blank\">Learn more</a>.",
"workflow_node.apply.form.disable_follow_cname.tooltip": "It determines whether to disable CNAME following during ACME DNS-01 authentication. If you don't understand this option, just keep it by default.<a href=\"https://letsencrypt.org/2019/10/09/onboarding-your-customers-with-lets-encrypt-and-acme/#the-advantages-of-a-cname\" target=\"_blank\">Learn more</a>.",
"workflow_node.apply.form.strategy_config.label": "Strategy settings",
"workflow_node.apply.form.skip_before_expiry_days.label": "Renewal interval",
"workflow_node.apply.form.skip_before_expiry_days.placeholder": "Please enter renewal interval",
"workflow_node.apply.form.skip_before_expiry_days.prefix": "Skip when the certificate expiration time exceeds",
"workflow_node.apply.form.skip_before_expiry_days.suffix": "",
"workflow_node.apply.form.skip_before_expiry_days.unit": "days",
"workflow_node.apply.form.skip_before_expiry_days.tooltip": "Be careful not to exceed the validity period limit of the CA, otherwise the certificate may never be renewed.",
"workflow_node.deploy.label": "Deployment",
"workflow_node.deploy.search.provider.placeholder": "Search deploy target ...",

View File

@ -30,7 +30,7 @@
"workflow_node.apply.form.domains.multiple_input_modal.placeholder": "请输入域名",
"workflow_node.apply.form.contact_email.label": "联系邮箱",
"workflow_node.apply.form.contact_email.placeholder": "请输入联系邮箱",
"workflow_node.apply.form.contact_email.tooltip": "申请签发 SSL 证书时所需的联系方式。请注意 Let's Encrypt 账户注册的速率限制。<br><a href=\"https://letsencrypt.org/zh-cn/docs/rate-limits/\" target=\"_blank\">点此了解更多</a>。",
"workflow_node.apply.form.contact_email.tooltip": "申请签发 SSL 证书时所需的联系方式。请注意 Let's Encrypt 账户注册的速率限制。<a href=\"https://letsencrypt.org/zh-cn/docs/rate-limits/\" target=\"_blank\">点此了解更多</a>。",
"workflow_node.apply.form.provider.label": "DNS 提供商",
"workflow_node.apply.form.provider.placeholder": "请选择 DNS 提供商",
"workflow_node.apply.form.provider_access.label": "DNS 提供商授权",
@ -51,19 +51,26 @@
"workflow_node.apply.form.key_algorithm.placeholder": "请选择数字证书算法",
"workflow_node.apply.form.nameservers.label": "DNS 递归服务器(可选)",
"workflow_node.apply.form.nameservers.placeholder": "请输入 DNS 递归服务器(多个值请用半角分号隔开)",
"workflow_node.apply.form.nameservers.tooltip": "在 ACME DNS-01 认证时使用自定义的 DNS 递归服务器。如果你不了解该选项的用途,保持默认即可。<br><a href=\"https://go-acme.github.io/lego/usage/cli/options/index.html#dns-resolvers-and-challenge-verification\" target=\"_blank\">点此了解更多</a>。",
"workflow_node.apply.form.nameservers.tooltip": "在 ACME DNS-01 认证时使用自定义的 DNS 递归服务器。如果你不了解该选项的用途,保持默认即可。<a href=\"https://go-acme.github.io/lego/usage/cli/options/index.html#dns-resolvers-and-challenge-verification\" target=\"_blank\">点此了解更多</a>。",
"workflow_node.apply.form.nameservers.multiple_input_modal.title": "修改 DNS 递归服务器",
"workflow_node.apply.form.nameservers.multiple_input_modal.placeholder": "请输入 DNS 递归服务器",
"workflow_node.apply.form.dns_propagation_timeout.label": "DNS 传播检查超时时间(可选)",
"workflow_node.apply.form.dns_propagation_timeout.placeholder": "请输入 DNS 传播检查超时时间",
"workflow_node.apply.form.dns_propagation_timeout.suffix": "秒",
"workflow_node.apply.form.dns_propagation_timeout.unit": "秒",
"workflow_node.apply.form.dns_propagation_timeout.tooltip": "在 ACME DNS-01 认证时等待 DNS 传播检查的最长时间。如果你不了解此选项的用途,保持默认即可。<br><br>为空时,将使用提供商提供的默认值。",
"workflow_node.apply.form.dns_ttl.label": "DNS 解析 TTL可选",
"workflow_node.apply.form.dns_ttl.placeholder": "请输入 DNS 解析 TTL",
"workflow_node.apply.form.dns_ttl.suffix": "秒",
"workflow_node.apply.form.dns_ttl.unit": "秒",
"workflow_node.apply.form.dns_ttl.tooltip": "在 ACME DNS-01 认证时 DNS 解析记录的 TTL。如果你不了解此选项的用途保持默认即可。<br><br>为空时,将使用提供商提供的默认值。",
"workflow_node.apply.form.disable_follow_cname.label": "禁止 CNAME 跟随",
"workflow_node.apply.form.disable_follow_cname.tooltip": "在 ACME DNS-01 认证时是否禁止 CNAME 跟随。如果你不了解该选项的用途,保持默认即可。<br><a href=\"https://letsencrypt.org/2019/10/09/onboarding-your-customers-with-lets-encrypt-and-acme/#the-advantages-of-a-cname\" target=\"_blank\">点此了解更多</a>。",
"workflow_node.apply.form.disable_follow_cname.tooltip": "在 ACME DNS-01 认证时是否禁止 CNAME 跟随。如果你不了解该选项的用途,保持默认即可。<a href=\"https://letsencrypt.org/2019/10/09/onboarding-your-customers-with-lets-encrypt-and-acme/#the-advantages-of-a-cname\" target=\"_blank\">点此了解更多</a>。",
"workflow_node.apply.form.strategy_config.label": "执行策略",
"workflow_node.apply.form.skip_before_expiry_days.label": "续期间隔",
"workflow_node.apply.form.skip_before_expiry_days.placeholder": "请输入续期间隔",
"workflow_node.apply.form.skip_before_expiry_days.prefix": "当距上次申请的证书到期时间前",
"workflow_node.apply.form.skip_before_expiry_days.suffix": "时跳过执行",
"workflow_node.apply.form.skip_before_expiry_days.unit": "天",
"workflow_node.apply.form.skip_before_expiry_days.tooltip": "注意不要超过 CA 的证书有效期限制,否则证书可能永远不会续期。",
"workflow_node.deploy.label": "部署",
"workflow_node.deploy.search.provider.placeholder": "搜索部署目标……",