diff --git a/go.mod b/go.mod
index 0140ddc8..861bfceb 100644
--- a/go.mod
+++ b/go.mod
@@ -140,6 +140,7 @@ require (
github.com/tidwall/gjson v1.18.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
+ github.com/vultr/govultr/v3 v3.21.1 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.mongodb.org/mongo-driver v1.17.2 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
diff --git a/go.sum b/go.sum
index 74227562..959dfd1a 100644
--- a/go.sum
+++ b/go.sum
@@ -887,6 +887,8 @@ github.com/volcengine/volc-sdk-golang v1.0.219 h1:IqMCdpJ6uuqS2ZZQYUVHKVd+2H1au0
github.com/volcengine/volc-sdk-golang v1.0.219/go.mod h1:zHJlaqiMbIB+0mcrsZPTwOb3FB7S/0MCfqlnO8R7hlM=
github.com/volcengine/volcengine-go-sdk v1.1.30 h1:D85LL8euXgxwsZzwQ0azT/hannEsiKxKY4h/7/HU764=
github.com/volcengine/volcengine-go-sdk v1.1.30/go.mod h1:EyKoi6t6eZxoPNGr2GdFCZti2Skd7MO3eUzx7TtSvNo=
+github.com/vultr/govultr/v3 v3.21.1 h1:0cnA8fXiqayPGbAlNHaW+5oCQjpDNkkAm3Nt3LOHplM=
+github.com/vultr/govultr/v3 v3.21.1/go.mod h1:9WwnWGCKnwDlNjHjtt+j+nP+0QWq6hQXzaHgddqrLWY=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
diff --git a/internal/certapply/applicators/sp_vultr.go b/internal/certapply/applicators/sp_vultr.go
new file mode 100644
index 00000000..6101a023
--- /dev/null
+++ b/internal/certapply/applicators/sp_vultr.go
@@ -0,0 +1,29 @@
+package applicators
+
+import (
+ "fmt"
+
+ "github.com/go-acme/lego/v4/challenge"
+
+ "github.com/certimate-go/certimate/internal/domain"
+ "github.com/certimate-go/certimate/pkg/core/ssl-applicator/acme-dns01/providers/vultr"
+ xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
+)
+
+func init() {
+ if err := ACMEDns01Registries.Register(domain.ACMEDns01ProviderTypeVultr, func(options *ProviderFactoryOptions) (challenge.Provider, error) {
+ credentials := domain.AccessConfigForVultr{}
+ if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
+ return nil, fmt.Errorf("failed to populate provider access config: %w", err)
+ }
+
+ provider, err := vultr.NewChallengeProvider(&vultr.ChallengeProviderConfig{
+ ApiKey: credentials.ApiKey,
+ DnsPropagationTimeout: options.DnsPropagationTimeout,
+ DnsTTL: options.DnsTTL,
+ })
+ return provider, err
+ }); err != nil {
+ panic(err)
+ }
+}
diff --git a/internal/domain/access.go b/internal/domain/access.go
index d43462ed..5f745e3c 100644
--- a/internal/domain/access.go
+++ b/internal/domain/access.go
@@ -402,6 +402,10 @@ type AccessConfigForVolcEngine struct {
SecretAccessKey string `json:"secretAccessKey"`
}
+type AccessConfigForVultr struct {
+ ApiKey string `json:"apiKey"`
+}
+
type AccessConfigForWangsu struct {
AccessKeyId string `json:"accessKeyId"`
AccessKeySecret string `json:"accessKeySecret"`
diff --git a/internal/domain/provider.go b/internal/domain/provider.go
index e35919a7..379b6276 100644
--- a/internal/domain/provider.go
+++ b/internal/domain/provider.go
@@ -86,6 +86,7 @@ const (
AccessProviderTypeUpyun = AccessProviderType("upyun")
AccessProviderTypeVercel = AccessProviderType("vercel")
AccessProviderTypeVolcEngine = AccessProviderType("volcengine")
+ AccessProviderTypeVultr = AccessProviderType("vultr")
AccessProviderTypeWangsu = AccessProviderType("wangsu")
AccessProviderTypeWebhook = AccessProviderType("webhook")
AccessProviderTypeWeComBot = AccessProviderType("wecombot")
@@ -171,6 +172,7 @@ const (
ACMEDns01ProviderTypeVercel = ACMEDns01ProviderType(AccessProviderTypeVercel)
ACMEDns01ProviderTypeVolcEngine = ACMEDns01ProviderType(AccessProviderTypeVolcEngine) // 兼容旧值,等同于 [ACMEDns01ProviderTypeVolcEngineDNS]
ACMEDns01ProviderTypeVolcEngineDNS = ACMEDns01ProviderType(AccessProviderTypeVolcEngine + "-dns")
+ ACMEDns01ProviderTypeVultr = ACMEDns01ProviderType(AccessProviderTypeVultr)
ACMEDns01ProviderTypeWestcn = ACMEDns01ProviderType(AccessProviderTypeWestcn)
)
diff --git a/internal/workflow/service.go b/internal/workflow/service.go
index adf2a39e..d869a1c0 100644
--- a/internal/workflow/service.go
+++ b/internal/workflow/service.go
@@ -111,7 +111,9 @@ func (s *WorkflowService) StartRun(ctx context.Context, req *dtos.WorkflowStartR
workflowRun = resp
}
- s.dispatcher.Start(ctx, workflowRun.Id)
+ if err := s.dispatcher.Start(ctx, workflowRun.Id); err != nil {
+ return nil, err
+ }
return &dtos.WorkflowStartRunResp{RunId: workflowRun.Id}, nil
}
@@ -131,7 +133,9 @@ func (s *WorkflowService) CancelRun(ctx context.Context, req *dtos.WorkflowCance
return nil, errors.New("workflow run is not pending or processing")
}
- s.dispatcher.Cancel(ctx, workflowRun.Id)
+ if err := s.dispatcher.Cancel(ctx, workflowRun.Id); err != nil {
+ return nil, err
+ }
return &dtos.WorkflowCancelRunResp{}, nil
}
diff --git a/pkg/core/ssl-applicator/acme-dns01/providers/vultr/vultr.go b/pkg/core/ssl-applicator/acme-dns01/providers/vultr/vultr.go
new file mode 100644
index 00000000..c3badc34
--- /dev/null
+++ b/pkg/core/ssl-applicator/acme-dns01/providers/vultr/vultr.go
@@ -0,0 +1,38 @@
+package vultr
+
+import (
+ "errors"
+ "time"
+
+ "github.com/go-acme/lego/v4/providers/dns/vultr"
+
+ "github.com/certimate-go/certimate/pkg/core"
+)
+
+type ChallengeProviderConfig struct {
+ ApiKey string `json:"apiKey"`
+ DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
+ DnsTTL int32 `json:"dnsTTL,omitempty"`
+}
+
+func NewChallengeProvider(config *ChallengeProviderConfig) (core.ACMEChallenger, error) {
+ if config == nil {
+ return nil, errors.New("the configuration of the acme challenge provider is nil")
+ }
+
+ providerConfig := vultr.NewDefaultConfig()
+ providerConfig.APIKey = config.ApiKey
+ if config.DnsPropagationTimeout != 0 {
+ providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
+ }
+ if config.DnsTTL != 0 {
+ providerConfig.TTL = int(config.DnsTTL)
+ }
+
+ provider, err := vultr.NewDNSProviderConfig(providerConfig)
+ if err != nil {
+ return nil, err
+ }
+
+ return provider, nil
+}
diff --git a/ui/public/imgs/providers/vultr.svg b/ui/public/imgs/providers/vultr.svg
new file mode 100644
index 00000000..cf49d15d
--- /dev/null
+++ b/ui/public/imgs/providers/vultr.svg
@@ -0,0 +1 @@
+
diff --git a/ui/src/components/access/AccessForm.tsx b/ui/src/components/access/AccessForm.tsx
index 976434ae..ed643447 100644
--- a/ui/src/components/access/AccessForm.tsx
+++ b/ui/src/components/access/AccessForm.tsx
@@ -80,6 +80,7 @@ import AccessConfigFieldsProviderUniCloud from "./forms/AccessConfigFieldsProvid
import AccessConfigFieldsProviderUpyun from "./forms/AccessConfigFieldsProviderUpyun";
import AccessConfigFieldsProviderVercel from "./forms/AccessConfigFieldsProviderVercel";
import AccessConfigFieldsProviderVolcEngine from "./forms/AccessConfigFieldsProviderVolcEngine";
+import AccessConfigFieldsProviderVultr from "./forms/AccessConfigFieldsProviderVultr";
import AccessConfigFieldsProviderWangsu from "./forms/AccessConfigFieldsProviderWangsu";
import AccessConfigFieldsProviderWebhook from "./forms/AccessConfigFieldsProviderWebhook";
import AccessConfigFieldsProviderWeComBot from "./forms/AccessConfigFieldsProviderWeComBot";
@@ -335,6 +336,9 @@ const AccessForm = ({ className, style, disabled, initialValues, mode, usage, ..
case ACCESS_PROVIDERS.VOLCENGINE: {
return