feat(provider): new deployment provider: ksyun cdn

This commit is contained in:
Fu Diwei 2025-11-06 13:19:37 +08:00
parent 6179faca5a
commit 28340f45ab
19 changed files with 463 additions and 1 deletions

2
go.mod
View File

@ -9,6 +9,7 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.0
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates v1.4.0
github.com/G-Core/gcorelabscdn-go v1.0.35
github.com/KscSDK/ksc-sdk-go v0.14.0
github.com/alibabacloud-go/alb-20200616/v2 v2.2.9
github.com/alibabacloud-go/apig-20240327/v5 v5.0.1
github.com/alibabacloud-go/cas-20200407/v4 v4.0.3
@ -27,6 +28,7 @@ require (
github.com/alibabacloud-go/vod-20170321/v4 v4.10.0
github.com/alibabacloud-go/waf-openapi-20211001/v6 v6.7.0
github.com/aliyun/alibabacloud-oss-go-sdk-v2 v1.3.0
github.com/aws/aws-sdk-go v1.40.45
github.com/aws/aws-sdk-go-v2/service/acm v1.37.10
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.55.3
github.com/aws/aws-sdk-go-v2/service/iam v1.49.1

5
go.sum
View File

@ -71,6 +71,8 @@ github.com/G-Core/gcorelabscdn-go v1.0.35/go.mod h1:iSGXaTvZBzDHQW+rKFS918BgFVpO
github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/KscSDK/ksc-sdk-go v0.14.0 h1:3bw0XicOLDNfxhljsTCtf1Ya93ZBxRtFtp5gD31bsjs=
github.com/KscSDK/ksc-sdk-go v0.14.0/go.mod h1:isHlJZi429ff5JLemSc10h7nznNgzJAY4MmNM8u7SBo=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/sarama v1.30.1/go.mod h1:hGgx05L/DiW8XYBXeJdKIN6V2QUy2H6JqME5VT1NLRw=
@ -216,6 +218,8 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0=
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.40.45 h1:QN1nsY27ssD/JmW4s83qmSb+uL6DG4GmCDzjmJB4xUI=
github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
github.com/aws/aws-sdk-go-v2 v1.39.5 h1:e/SXuia3rkFtapghJROrydtQpfQaaUgd1cUvyO1mp2w=
@ -568,6 +572,7 @@ github.com/jdcloud-api/jdcloud-sdk-go v1.64.0/go.mod h1:UrKjuULIWLjHFlG6aSPunArE
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jinzhu/copier v0.3.4 h1:mfU6jI9PtCeUjkjQ322dlff9ELjGDu975C2p/nrubVI=
github.com/jinzhu/copier v0.3.4/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=

View File

@ -0,0 +1,29 @@
package deployers
import (
"fmt"
"github.com/certimate-go/certimate/internal/domain"
"github.com/certimate-go/certimate/pkg/core"
ksyuncdn "github.com/certimate-go/certimate/pkg/core/ssl-deployer/providers/ksyun-cdn"
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
)
func init() {
if err := Registries.Register(domain.DeploymentProviderTypeKsyunCDN, func(options *ProviderFactoryOptions) (core.SSLDeployer, error) {
credentials := domain.AccessConfigForKsyun{}
if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
}
provider, err := ksyuncdn.NewSSLDeployerProvider(&ksyuncdn.SSLDeployerProviderConfig{
AccessKeyId: credentials.AccessKeyId,
SecretAccessKey: credentials.SecretAccessKey,
Domain: xmaps.GetString(options.ProviderExtendedConfig, "domain"),
CertificateId: xmaps.GetString(options.ProviderExtendedConfig, "certificateId"),
})
return provider, err
}); err != nil {
panic(err)
}
}

View File

@ -298,6 +298,11 @@ type AccessConfigForKubernetes struct {
KubeConfig string `json:"kubeConfig,omitempty"`
}
type AccessConfigForKsyun struct {
AccessKeyId string `json:"accessKeyId"`
SecretAccessKey string `json:"secretAccessKey"`
}
type AccessConfigForLarkBot struct {
WebhookUrl string `json:"webhookUrl"`
Secret string `json:"secret,omitempty"`

View File

@ -64,7 +64,7 @@ const (
AccessProviderTypeIONOS = AccessProviderType("ionos")
AccessProviderTypeJDCloud = AccessProviderType("jdcloud")
AccessProviderTypeKong = AccessProviderType("kong")
AccessProviderTypeKsyun = AccessProviderType("ksyun") // 金山云(预留)
AccessProviderTypeKsyun = AccessProviderType("ksyun")
AccessProviderTypeKubernetes = AccessProviderType("k8s")
AccessProviderTypeLarkBot = AccessProviderType("larkbot")
AccessProviderTypeLeCDN = AccessProviderType("lecdn")
@ -290,6 +290,7 @@ const (
DeploymentProviderTypeJDCloudVOD = DeploymentProviderType(AccessProviderTypeJDCloud + "-vod")
DeploymentProviderTypeKong = DeploymentProviderType(AccessProviderTypeKong)
DeploymentProviderTypeKubernetesSecret = DeploymentProviderType(AccessProviderTypeKubernetes + "-secret")
DeploymentProviderTypeKsyunCDN = DeploymentProviderType(AccessProviderTypeKsyun + "-cdn")
DeploymentProviderTypeLeCDN = DeploymentProviderType(AccessProviderTypeLeCDN)
DeploymentProviderTypeLocal = DeploymentProviderType(AccessProviderTypeLocal)
DeploymentProviderTypeNetlifySite = DeploymentProviderType(AccessProviderTypeNetlify + "-site")

View File

@ -0,0 +1,174 @@
package ksyuncdn
import (
"context"
"errors"
"fmt"
"log/slog"
"strings"
"time"
"github.com/KscSDK/ksc-sdk-go/ksc"
ksccdnv1 "github.com/KscSDK/ksc-sdk-go/service/cdnv1"
"github.com/go-viper/mapstructure/v2"
"github.com/certimate-go/certimate/pkg/core"
)
type SSLDeployerProviderConfig struct {
// 金山云 AccessKeyId。
AccessKeyId string `json:"accessKeyId"`
// 金山云 SecretAccessKey。
SecretAccessKey string `json:"secretAccessKey"`
// 加速域名(支持泛域名)。
Domain string `json:"domain"`
// 证书 ID。
// 选填。零值时表示新建证书;否则表示更新证书。
CertificateId string `json:"certificateId,omitempty"`
}
type SSLDeployerProvider struct {
config *SSLDeployerProviderConfig
logger *slog.Logger
sdkClient *ksccdnv1.Cdnv1
}
var _ core.SSLDeployer = (*SSLDeployerProvider)(nil)
func NewSSLDeployerProvider(config *SSLDeployerProviderConfig) (*SSLDeployerProvider, error) {
if config == nil {
return nil, errors.New("the configuration of the ssl deployer provider is nil")
}
client, err := createSDKClient(config.AccessKeyId, config.SecretAccessKey)
if err != nil {
return nil, fmt.Errorf("could not create sdk client: %w", err)
}
return &SSLDeployerProvider{
config: config,
logger: slog.Default(),
sdkClient: client,
}, nil
}
func (d *SSLDeployerProvider) SetLogger(logger *slog.Logger) {
if logger == nil {
d.logger = slog.New(slog.DiscardHandler)
} else {
d.logger = logger
}
}
func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*core.SSLDeployResult, error) {
// // 如果原证书 ID 为空,则创建证书;否则更新证书。
if d.config.CertificateId == "" {
if d.config.Domain == "" {
return nil, errors.New("config `domain` is required")
}
// 遍历查询域名列表,获取域名 ID
// https://docs.ksyun.com/documents/198
var domainId string
getCdnDomainsPageNumber := int32(1)
getCdnDomainsPageSize := int32(100)
for {
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
}
getCdnDomainsInput := map[string]any{
"PageNumber": getCdnDomainsPageNumber,
"PageSize": getCdnDomainsPageSize,
"DomainName": d.config.Domain,
"FuzzyMatch": "off",
}
getCdnDomainsReq, getCdnDomainsOutput := d.sdkClient.GetCdnDomainsPostRequest(&getCdnDomainsInput)
getCdnDomainsErr := getCdnDomainsReq.Send()
d.logger.Debug("sdk request 'cdn.GetCdnDomains'", slog.Any("request", getCdnDomainsInput), slog.Any("response", getCdnDomainsOutput))
if getCdnDomainsErr != nil {
return nil, fmt.Errorf("failed to execute sdk request 'cdn.GetCdnDomains': %w", getCdnDomainsErr)
}
type GetCdnDomainsResponse struct {
PageNumber int32 `json:"PageNumber"`
PageSize int32 `json:"PageSize"`
TotalCount int32 `json:"TotalCount"`
Domains []*struct {
DomainId string `json:"DomainId"`
DomainName string `json:"DomainName"`
Cname string `json:"Cname"`
CdnType string `json:"CdnType"`
CreatedTime string `json:"CreatedTime"`
ModifiedTime string `json:"ModifiedTime"`
Region string `json:"Region"`
} `json:"Domains"`
}
var getCdnDomainsResp *GetCdnDomainsResponse
mapstructure.Decode(getCdnDomainsOutput, &getCdnDomainsResp)
if getCdnDomainsResp != nil {
for _, domainItem := range getCdnDomainsResp.Domains {
if strings.EqualFold(domainItem.DomainName, d.config.Domain) {
domainId = domainItem.DomainId
break
}
}
if domainId != "" {
break
}
}
if getCdnDomainsResp == nil || len(getCdnDomainsResp.Domains) < int(getCdnDomainsPageSize) {
break
} else {
getCdnDomainsPageNumber++
}
}
if domainId == "" {
return nil, errors.New("domain not found")
}
// 为加速域名配置证书接口
// https://docs.ksyun.com/documents/261
configCertificateInput := map[string]any{
"Enable": "on",
"DomainIds": domainId,
"CertificateName": fmt.Sprintf("certimate_%d", time.Now().UnixMilli()),
"ServerCertificate": certPEM,
"PrivateKey": privkeyPEM,
}
configCertificateReq, configCertificateOutput := d.sdkClient.ConfigCertificatePostRequest(&configCertificateInput)
configCertificateErr := configCertificateReq.Send()
d.logger.Debug("sdk request 'cdn.ConfigCertificate'", slog.Any("request", configCertificateInput), slog.Any("response", configCertificateOutput))
if configCertificateErr != nil {
return nil, fmt.Errorf("failed to execute sdk request 'cdn.ConfigCertificate': %w", configCertificateErr)
}
} else {
// 更新证书
// https://docs.ksyun.com/documents/259
setCertificateInput := map[string]any{
"CertificateId": d.config.CertificateId,
"CertificateName": fmt.Sprintf("certimate_%d", time.Now().UnixMilli()),
"ServerCertificate": certPEM,
"PrivateKey": privkeyPEM,
}
setCertificateReq, setCertificateOutput := d.sdkClient.SetCertificatePostRequest(&setCertificateInput)
setCertificateErr := setCertificateReq.Send()
d.logger.Debug("sdk request 'cdn.SetCertificate'", slog.Any("request", setCertificateInput), slog.Any("response", setCertificateOutput))
if setCertificateErr != nil {
return nil, fmt.Errorf("failed to execute sdk request 'cdn.SetCertificate': %w", setCertificateErr)
}
}
return &core.SSLDeployResult{}, nil
}
func createSDKClient(accessKeyId, secretAccessKey string) (*ksccdnv1.Cdnv1, error) {
region := "cn-beijing-6"
client := ksccdnv1.SdkNew(ksc.NewClient(accessKeyId, secretAccessKey), &ksc.Config{Region: &region})
return client, nil
}

View File

@ -0,0 +1,80 @@
package ksyuncdn_test
import (
"context"
"flag"
"fmt"
"os"
"strings"
"testing"
provider "github.com/certimate-go/certimate/pkg/core/ssl-deployer/providers/ksyun-cdn"
)
var (
fInputCertPath string
fInputKeyPath string
fAccessKeyId string
fSecretAccessKey string
fDomain string
fCertificateId string
)
func init() {
argsPrefix := "CERTIMATE_SSLDEPLOYER_KSYUNCDN_"
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
flag.StringVar(&fSecretAccessKey, argsPrefix+"SECRETACCESSKEY", "", "")
flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "")
flag.StringVar(&fCertificateId, argsPrefix+"CERTIFICATEID", "", "")
}
/*
Shell command to run this test:
go test -v ./ksyun_cdn_test.go -args \
--CERTIMATE_SSLDEPLOYER_KSYUNCDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \
--CERTIMATE_SSLDEPLOYER_KSYUNCDN_INPUTKEYPATH="/path/to/your-input-key.pem" \
--CERTIMATE_SSLDEPLOYER_KSYUNCDN_ACCESSKEYID="your-access-key-id" \
--CERTIMATE_SSLDEPLOYER_KSYUNCDN_SECRETACCESSKEY="your-secret-access-key" \
--CERTIMATE_SSLDEPLOYER_KSYUNCDN_DOMAIN="example.com" \
--CERTIMATE_SSLDEPLOYER_KSYUNCDN_CERTIFICATEID="your-certificate-id"
*/
func TestDeploy(t *testing.T) {
flag.Parse()
t.Run("Deploy", func(t *testing.T) {
t.Log(strings.Join([]string{
"args:",
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
fmt.Sprintf("SECRETACCESSKEY: %v", fSecretAccessKey),
fmt.Sprintf("DOMAIN: %v", fDomain),
fmt.Sprintf("CERTIFICATEID: %v", fCertificateId),
}, "\n"))
deployer, err := provider.NewSSLDeployerProvider(&provider.SSLDeployerProviderConfig{
AccessKeyId: fAccessKeyId,
SecretAccessKey: fSecretAccessKey,
Domain: fDomain,
CertificateId: fCertificateId,
})
if err != nil {
t.Errorf("err: %+v", err)
return
}
fInputCertData, _ := os.ReadFile(fInputCertPath)
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
if err != nil {
t.Errorf("err: %+v", err)
return
}
t.Logf("ok: %v", res)
})
}

View File

@ -0,0 +1 @@
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M718.5408 453.8368c-4.1984 0-8.3968-0.7168-12.5952-0.7168a103.8336 103.8336 0 0 0-67.8912 25.088 139.6736 139.6736 0 0 0 13.6192-60.3136 133.12 133.12 0 0 0-2.4576-25.7024 139.5712 139.5712 0 0 0-274.432 0 133.12 133.12 0 0 0-2.4576 25.7024 139.6736 139.6736 0 0 0 13.6192 60.3136 103.8336 103.8336 0 0 0-67.8912-25.088c-4.1984 0-8.3968 0-12.5952 0.7168a104.5504 104.5504 0 1 0 101.0688 159.4368 116.736 116.736 0 0 0 6.144-11.0592 105.1648 105.1648 0 0 0 4.9152-76.6976 62.6688 62.6688 0 0 1 27.3408 20.48l2.6624 3.8912a83.2512 83.2512 0 0 1 133.9392-3.3792l4.7104 6.8608 51.2 73.9328a84.0704 84.0704 0 0 0 62.464 34.6112h5.5296a104.5504 104.5504 0 0 0 12.5952-208.384z" fill="#E6002D"></path><path d="M512 0a512 512 0 1 0 512 512A512 512 0 0 0 512 0z m200.8064 732.3648h-6.8608a152.4736 152.4736 0 0 1-120.5248-58.9824S509.2352 564.6336 508.0064 563.2a42.1888 42.1888 0 0 0-32.4608-15.2576 40.96 40.96 0 0 0-24.064 7.5776l122.88 175.4112a62.5664 62.5664 0 0 0 77.0048 20.48A97.5872 97.5872 0 0 1 593.92 783.5648a97.0752 97.0752 0 0 1-95.5392-39.1168l-49.4592-70.656a174.8992 174.8992 0 1 1-143.36-290.5088 209.7152 209.7152 0 0 1 413.9008 0 174.7968 174.7968 0 0 1-6.144 349.0816z" fill="#E6002D"></path></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -54,6 +54,7 @@ import AccessConfigFieldsProviderInfomaniak from "./AccessConfigFieldsProviderIn
import AccessConfigFieldsProviderIONOS from "./AccessConfigFieldsProviderIONOS";
import AccessConfigFieldsProviderJDCloud from "./AccessConfigFieldsProviderJDCloud";
import AccessConfigFieldsProviderKong from "./AccessConfigFieldsProviderKong";
import AccessConfigFieldsProviderKsyun from "./AccessConfigFieldsProviderKsyun";
import AccessConfigFieldsProviderKubernetes from "./AccessConfigFieldsProviderKubernetes";
import AccessConfigFieldsProviderLarkBot from "./AccessConfigFieldsProviderLarkBot";
import AccessConfigFieldsProviderLeCDN from "./AccessConfigFieldsProviderLeCDN";
@ -151,6 +152,7 @@ const providerComponentMap: Partial<Record<AccessProviderType, React.ComponentTy
[ACCESS_PROVIDERS.JDCLOUD]: AccessConfigFieldsProviderJDCloud,
[ACCESS_PROVIDERS.KONG]: AccessConfigFieldsProviderKong,
[ACCESS_PROVIDERS.KUBERNETES]: AccessConfigFieldsProviderKubernetes,
[ACCESS_PROVIDERS.KSYUN]: AccessConfigFieldsProviderKsyun,
[ACCESS_PROVIDERS.LARKBOT]: AccessConfigFieldsProviderLarkBot,
[ACCESS_PROVIDERS.LECDN]: AccessConfigFieldsProviderLeCDN,
[ACCESS_PROVIDERS.INFOMANIAK]: AccessConfigFieldsProviderInfomaniak,

View File

@ -0,0 +1,64 @@
import { getI18n, useTranslation } from "react-i18next";
import { Form, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
import { useFormNestedFieldsContext } from "./_context";
const AccessConfigFormFieldsProviderKsyun = () => {
const { i18n, t } = useTranslation();
const { parentNamePath } = useFormNestedFieldsContext();
const formSchema = z.object({
[parentNamePath]: getSchema({ i18n }),
});
const formRule = createSchemaFieldRule(formSchema);
const initialValues = getInitialValues();
return (
<>
<Form.Item
name={[parentNamePath, "accessKeyId"]}
initialValue={initialValues.accessKeyId}
label={t("access.form.ksyun_access_key_id.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.ksyun_access_key_id.tooltip") }}></span>}
>
<Input autoComplete="new-password" placeholder={t("access.form.ksyun_access_key_id.placeholder")} />
</Form.Item>
<Form.Item
name={[parentNamePath, "secretAccessKey"]}
initialValue={initialValues.secretAccessKey}
label={t("access.form.ksyun_secret_access_key.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.ksyun_secret_access_key.tooltip") }}></span>}
>
<Input.Password autoComplete="new-password" placeholder={t("access.form.ksyun_secret_access_key.placeholder")} />
</Form.Item>
</>
);
};
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
return {
accessKeyId: "",
secretAccessKey: "",
};
};
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
const { t } = i18n;
return z.object({
accessKeyId: z.string().nonempty(t("access.form.ksyun_access_key_id.placeholder")),
secretAccessKey: z.string().nonempty(t("access.form.ksyun_secret_access_key.placeholder")),
});
};
const _default = Object.assign(AccessConfigFormFieldsProviderKsyun, {
getInitialValues,
getSchema,
});
export default _default;

View File

@ -55,6 +55,7 @@ import BizDeployNodeConfigFieldsProviderJDCloudCDN from "./BizDeployNodeConfigFi
import BizDeployNodeConfigFieldsProviderJDCloudLive from "./BizDeployNodeConfigFieldsProviderJDCloudLive";
import BizDeployNodeConfigFieldsProviderJDCloudVOD from "./BizDeployNodeConfigFieldsProviderJDCloudVOD";
import BizDeployNodeConfigFieldsProviderKong from "./BizDeployNodeConfigFieldsProviderKong";
import BizDeployNodeConfigFieldsProviderKsyunCDN from "./BizDeployNodeConfigFieldsProviderKsyunCDN";
import BizDeployNodeConfigFieldsProviderKubernetesSecret from "./BizDeployNodeConfigFieldsProviderKubernetesSecret";
import BizDeployNodeConfigFieldsProviderLeCDN from "./BizDeployNodeConfigFieldsProviderLeCDN";
import BizDeployNodeConfigFieldsProviderLocal from "./BizDeployNodeConfigFieldsProviderLocal";
@ -157,6 +158,7 @@ const providerComponentMap: Partial<Record<DeploymentProviderType, React.Compone
[DEPLOYMENT_PROVIDERS.JDCLOUD_VOD]: BizDeployNodeConfigFieldsProviderJDCloudVOD,
[DEPLOYMENT_PROVIDERS.KONG]: BizDeployNodeConfigFieldsProviderKong,
[DEPLOYMENT_PROVIDERS.KUBERNETES_SECRET]: BizDeployNodeConfigFieldsProviderKubernetesSecret,
[DEPLOYMENT_PROVIDERS.KSYUN_CDN]: BizDeployNodeConfigFieldsProviderKsyunCDN,
[DEPLOYMENT_PROVIDERS.LECDN]: BizDeployNodeConfigFieldsProviderLeCDN,
[DEPLOYMENT_PROVIDERS.LOCAL]: BizDeployNodeConfigFieldsProviderLocal,
[DEPLOYMENT_PROVIDERS.NETLIFY_SITE]: BizDeployNodeConfigFieldsProviderNetlifySite,

View File

@ -0,0 +1,65 @@
import { getI18n, useTranslation } from "react-i18next";
import { Form, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
import { validDomainName } from "@/utils/validators";
import { useFormNestedFieldsContext } from "./_context";
const BizDeployNodeConfigFieldsProviderKsyunCDN = () => {
const { i18n, t } = useTranslation();
const { parentNamePath } = useFormNestedFieldsContext();
const formSchema = z.object({
[parentNamePath]: getSchema({ i18n }),
});
const formRule = createSchemaFieldRule(formSchema);
const initialValues = getInitialValues();
return (
<>
<Form.Item
name={[parentNamePath, "domain"]}
initialValue={initialValues.domain}
label={t("workflow_node.deploy.form.ksyun_cdn_domain.label")}
rules={[formRule]}
>
<Input placeholder={t("workflow_node.deploy.form.ksyun_cdn_domain.placeholder")} />
</Form.Item>
<Form.Item
name={[parentNamePath, "certificateId"]}
initialValue={initialValues.certificateId}
label={t("workflow_node.deploy.form.ksyun_cdn_certificate_id.label")}
extra={t("workflow_node.deploy.form.ksyun_cdn_certificate_id.help")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.ksyun_cdn_certificate_id.tooltip") }}></span>}
>
<Input allowClear placeholder={t("workflow_node.deploy.form.ksyun_cdn_certificate_id.placeholder")} />
</Form.Item>
</>
);
};
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
return {
domain: "",
};
};
const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> }) => {
const { t } = i18n;
return z.object({
domain: z.string().refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")),
certificateId: z.string().nullish(),
});
};
const _default = Object.assign(BizDeployNodeConfigFieldsProviderKsyunCDN, {
getInitialValues,
getSchema,
});
export default _default;

View File

@ -68,6 +68,7 @@ export const ACCESS_PROVIDERS = Object.freeze({
JDCLOUD: "jdcloud",
KONG: "kong",
KUBERNETES: "k8s",
KSYUN: "ksyun",
LARKBOT: "larkbot",
LECDN: "lecdn",
LETSENCRYPT: "letsencrypt",
@ -158,6 +159,7 @@ export const accessProvidersMap: Map<AccessProvider["type"] | string, AccessProv
[ACCESS_PROVIDERS.BAISHAN, "provider.baishan", "/imgs/providers/baishan.png", [ACCESS_USAGES.HOSTING]],
[ACCESS_PROVIDERS.WANGSU, "provider.wangsu", "/imgs/providers/wangsu.svg", [ACCESS_USAGES.HOSTING]],
[ACCESS_PROVIDERS.DOGECLOUD, "provider.dogecloud", "/imgs/providers/dogecloud.png", [ACCESS_USAGES.HOSTING]],
[ACCESS_PROVIDERS.KSYUN, "provider.ksyun", "/imgs/providers/ksyun.svg", [ACCESS_USAGES.HOSTING]],
[ACCESS_PROVIDERS.BYTEPLUS, "provider.byteplus", "/imgs/providers/byteplus.svg", [ACCESS_USAGES.HOSTING]],
[ACCESS_PROVIDERS.UNICLOUD, "provider.unicloud", "/imgs/providers/unicloud.png", [ACCESS_USAGES.HOSTING]],
[ACCESS_PROVIDERS["1PANEL"], "provider.1panel", "/imgs/providers/1panel.svg", [ACCESS_USAGES.HOSTING]],
@ -550,6 +552,7 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({
JDCLOUD_VOD: `${ACCESS_PROVIDERS.JDCLOUD}-vod`,
KONG: `${ACCESS_PROVIDERS.KONG}`,
KUBERNETES_SECRET: `${ACCESS_PROVIDERS.KUBERNETES}-secret`,
KSYUN_CDN: `${ACCESS_PROVIDERS.KSYUN}-cdn`,
LECDN: `${ACCESS_PROVIDERS.LECDN}`,
LOCAL: `${ACCESS_PROVIDERS.LOCAL}`,
NETLIFY_SITE: `${ACCESS_PROVIDERS.NETLIFY}-site`,
@ -689,6 +692,7 @@ export const deploymentProvidersMap: Map<DeploymentProvider["type"] | string, De
[DEPLOYMENT_PROVIDERS.WANGSU_CDNPRO, "provider.wangsu.cdnpro", DEPLOYMENT_CATEGORIES.CDN],
[DEPLOYMENT_PROVIDERS.WANGSU_CERTIFICATE, "provider.wangsu.certificate_upload", DEPLOYMENT_CATEGORIES.SSL],
[DEPLOYMENT_PROVIDERS.DOGECLOUD_CDN, "provider.dogecloud.cdn", DEPLOYMENT_CATEGORIES.CDN],
[DEPLOYMENT_PROVIDERS.KSYUN_CDN, "provider.ksyun.cdn", DEPLOYMENT_CATEGORIES.CDN],
[DEPLOYMENT_PROVIDERS.BYTEPLUS_CDN, "provider.byteplus.cdn", DEPLOYMENT_CATEGORIES.CDN],
[DEPLOYMENT_PROVIDERS.UCLOUD_US3, "provider.ucloud.us3", DEPLOYMENT_CATEGORIES.STORAGE],
[DEPLOYMENT_PROVIDERS.UCLOUD_UCDN, "provider.ucloud.ucdn", DEPLOYMENT_CATEGORIES.CDN],

View File

@ -347,6 +347,12 @@
"access.form.kong_api_token.label": "Kong admin API token (Optional)",
"access.form.kong_api_token.placeholder": "Please enter Kong admin API token",
"access.form.kong_api_token.tooltip": "For more information, see <a href=\"https://developer.konghq.com/admin-api/\" target=\"_blank\">https://developer.konghq.com/admin-api/</a>",
"access.form.ksyun_access_key_id.label": "Kingsoft Cloud AccessKeyID",
"access.form.ksyun_access_key_id.placeholder": "Please enter Kingsoft Cloud AccessKeyID",
"access.form.ksyun_access_key_id.tooltip": "For more information, see <a href=\"https://endocs.ksyun.com/documents/37659\" target=\"_blank\">https://endocs.ksyun.com/documents/37659</a>",
"access.form.ksyun_secret_access_key.label": "Kingsoft Cloud SecretAccessKey",
"access.form.ksyun_secret_access_key.placeholder": "Please enter Kingsoft Cloud SecretAccessKey",
"access.form.ksyun_secret_access_key.tooltip": "For more information, see <a href=\"https://endocs.ksyun.com/documents/37659\" target=\"_blank\">https://endocs.ksyun.com/documents/37659</a>",
"access.form.larkbot_webhook_url.label": "Lark bot Webhook URL",
"access.form.larkbot_webhook_url.placeholder": "Please enter Lark bot Webhook URL",
"access.form.larkbot_webhook_url.tooltip": "For more information, see <a href=\"https://open.larksuite.com/document/client-docs/bot-v3/add-custom-bot\" target=\"_blank\">https://open.larksuite.com/document/client-docs/bot-v3/add-custom-bot</a>",

View File

@ -117,6 +117,8 @@
"provider.kong": "Kong",
"provider.kubernetes": "Kubernetes",
"provider.kubernetes.secret": "Kubernetes - Secret",
"provider.ksyun": "Kingsoft Cloud",
"provider.ksyun.cdn": "Kingsoft Cloud - CDN (Content Delivery Network)",
"provider.larkbot": "Lark Bot",
"provider.lecdn": "LeCDN",
"provider.letsencrypt": "Let's Encrypt",

View File

@ -618,6 +618,12 @@
"workflow_node.deploy.form.kong_certificate_id.label": "Kong certificate ID",
"workflow_node.deploy.form.kong_certificate_id.placeholder": "Please enter Kong certificate ID",
"workflow_node.deploy.form.kong_certificate_id.tooltip": "You can find it on Kong dashboard.",
"workflow_node.deploy.form.ksyun_cdn_domain.label": "Kingsoft Cloud CDN domain",
"workflow_node.deploy.form.ksyun_cdn_domain.placeholder": "Please enter Kingsoft Cloud CDN domain name",
"workflow_node.deploy.form.ksyun_cdn_certificate_id.label": "Kingsoft Cloud CDN certificate ID (Optional)",
"workflow_node.deploy.form.ksyun_cdn_certificate_id.placeholder": "Please enter Kingsoft Cloud CDN certificate ID",
"workflow_node.deploy.form.ksyun_cdn_certificate_id.help": "",
"workflow_node.deploy.form.ksyun_cdn_certificate_id.tooltip": "For more information, see <a href=\"https://cdn.console.ksyun.com/\" target=\"_blank\">https://cdn.console.ksyun.com/</a>",
"workflow_node.deploy.form.lecdn_resource_type.label": "Resource type",
"workflow_node.deploy.form.lecdn_resource_type.placeholder": "Please select resource type",
"workflow_node.deploy.form.lecdn_resource_type.option.certificate.label": "Certificate",

View File

@ -346,6 +346,12 @@
"access.form.kong_api_token.label": "Kong Admin API Token可选",
"access.form.kong_api_token.placeholder": "请输入 Kong Admin API Token",
"access.form.kong_api_token.tooltip": "这是什么?请参阅 <a href=\"https://developer.konghq.com/admin-api/\" target=\"_blank\">https://developer.konghq.com/admin-api/</a>",
"access.form.ksyun_access_key_id.label": "金山云 AccessKeyID",
"access.form.ksyun_access_key_id.placeholder": "请输入金山云 AccessKeyID",
"access.form.ksyun_access_key_id.tooltip": "这是什么?请参阅 <a href=\"https://docs.ksyun.com/documents/39976\" target=\"_blank\">https://docs.ksyun.com/documents/39976</a>",
"access.form.ksyun_secret_access_key.label": "金山云 SecretAccessKey",
"access.form.ksyun_secret_access_key.placeholder": "请输入金山云 SecretAccessKey",
"access.form.ksyun_secret_access_key.tooltip": "这是什么?请参阅 <a href=\"https://docs.ksyun.com/documents/39976\" target=\"_blank\">https://docs.ksyun.com/documents/39976</a>",
"access.form.larkbot_webhook_url.label": "飞书群机器人 Webhook 地址",
"access.form.larkbot_webhook_url.placeholder": "请输入飞书群机器人 Webhook 地址",
"access.form.larkbot_webhook_url.tooltip": "这是什么?请参阅 <a href=\"https://open.feishu.cn/document/client-docs/bot-v3/add-custom-bot\" target=\"_blank\">https://open.feishu.cn/document/client-docs/bot-v3/add-custom-bot</a>",

View File

@ -117,6 +117,8 @@
"provider.kong": "Kong",
"provider.kubernetes": "Kubernetes",
"provider.kubernetes.secret": "Kubernetes - Secret",
"provider.ksyun": "金山云",
"provider.ksyun.cdn": "金山云 - 内容分发网络 CDN",
"provider.larkbot": "飞书群机器人",
"provider.lecdn": "LeCDN",
"provider.letsencrypt": "Let's Encrypt",

View File

@ -616,6 +616,12 @@
"workflow_node.deploy.form.kong_certificate_id.label": "Kong 证书 ID",
"workflow_node.deploy.form.kong_certificate_id.placeholder": "请输入 Kong 证书 ID",
"workflow_node.deploy.form.kong_certificate_id.tooltip": "请登录 Kong 控制台查看",
"workflow_node.deploy.form.ksyun_cdn_domain.label": "金山云 CDN 加速域名",
"workflow_node.deploy.form.ksyun_cdn_domain.placeholder": "请输入金山云 CDN 加速域名(支持泛域名)",
"workflow_node.deploy.form.ksyun_cdn_certificate_id.label": "金山云 CDN 原证书 ID可选",
"workflow_node.deploy.form.ksyun_cdn_certificate_id.placeholder": "请输入金山云 CDN 原证书 ID",
"workflow_node.deploy.form.ksyun_cdn_certificate_id.help": "提示:不填写时,将上传新证书;否则,将替换原证书。",
"workflow_node.deploy.form.ksyun_cdn_certificate_id.tooltip": "这是什么?请参阅 <a href=\"https://cdn.console.ksyun.com/\" target=\"_blank\">https://cdn.console.ksyun.com/</a>",
"workflow_node.deploy.form.lecdn_resource_type.label": "证书部署方式",
"workflow_node.deploy.form.lecdn_resource_type.placeholder": "请选择证书部署方式",
"workflow_node.deploy.form.lecdn_resource_type.option.certificate.label": "替换指定证书",