mirror of
https://gitee.com/fit2cloud-feizhiyun/1Panel.git
synced 2024-11-29 18:37:41 +08:00
feat(ssl证书): 实现华为云dns (#6407)
This commit is contained in:
parent
535d4bbe1b
commit
f77681b9c9
@ -3,6 +3,7 @@ package ssl
|
||||
import (
|
||||
"crypto"
|
||||
"encoding/json"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/ssl/huaweicloud"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
@ -72,6 +73,7 @@ const (
|
||||
NameCom DnsType = "NameCom"
|
||||
Godaddy DnsType = "Godaddy"
|
||||
TencentCloud DnsType = "TencentCloud"
|
||||
HuaweiCloud DnsType = "HuaweiCloud"
|
||||
)
|
||||
|
||||
type DNSParam struct {
|
||||
@ -84,6 +86,7 @@ type DNSParam struct {
|
||||
APIUser string `json:"apiUser"`
|
||||
APISecret string `json:"apiSecret"`
|
||||
SecretID string `json:"secretID"`
|
||||
Region string `json:"region"`
|
||||
}
|
||||
|
||||
var (
|
||||
@ -166,6 +169,15 @@ func (c *AcmeClient) UseDns(dnsType DnsType, params string, websiteSSL model.Web
|
||||
tencentCloudConfig.PollingInterval = pollingInterval
|
||||
tencentCloudConfig.TTL = ttl
|
||||
p, err = tencentcloud.NewDNSProviderConfig(tencentCloudConfig)
|
||||
case HuaweiCloud:
|
||||
huaweiCloudConfig := huaweicloud.NewDefaultConfig()
|
||||
huaweiCloudConfig.AccessKeyID = param.AccessKey
|
||||
huaweiCloudConfig.SecretAccessKey = param.SecretKey
|
||||
huaweiCloudConfig.Region = param.Region
|
||||
huaweiCloudConfig.PropagationTimeout = propagationTimeout
|
||||
huaweiCloudConfig.PollingInterval = pollingInterval
|
||||
huaweiCloudConfig.TTL = int32(ttl)
|
||||
p, err = huaweicloud.NewDNSProviderConfig(huaweiCloudConfig)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
|
288
backend/utils/ssl/huaweicloud/huaweicloud.go
Normal file
288
backend/utils/ssl/huaweicloud/huaweicloud.go
Normal file
@ -0,0 +1,288 @@
|
||||
// Package huaweicloud implements a DNS provider for solving the DNS-01 challenge using Huawei Cloud.
|
||||
package huaweicloud
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/challenge/dns01"
|
||||
"github.com/go-acme/lego/v4/platform/config/env"
|
||||
"github.com/go-acme/lego/v4/platform/wait"
|
||||
hwauthbasic "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic"
|
||||
hwconfig "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/config"
|
||||
hwdns "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/dns/v2"
|
||||
hwmodel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/dns/v2/model"
|
||||
hwregion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/dns/v2/region"
|
||||
)
|
||||
|
||||
// Environment variables names.
|
||||
const (
|
||||
envNamespace = "HUAWEICLOUD_"
|
||||
|
||||
EnvAccessKeyID = envNamespace + "ACCESS_KEY_ID"
|
||||
EnvSecretAccessKey = envNamespace + "SECRET_ACCESS_KEY"
|
||||
EnvRegion = envNamespace + "REGION"
|
||||
|
||||
EnvTTL = envNamespace + "TTL"
|
||||
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
|
||||
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
|
||||
EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
|
||||
)
|
||||
|
||||
// Config is used to configure the creation of the DNSProvider.
|
||||
type Config struct {
|
||||
AccessKeyID string
|
||||
SecretAccessKey string
|
||||
Region string
|
||||
|
||||
PropagationTimeout time.Duration
|
||||
PollingInterval time.Duration
|
||||
TTL int32
|
||||
HTTPTimeout time.Duration
|
||||
}
|
||||
|
||||
// NewDefaultConfig returns a default configuration for the DNSProvider.
|
||||
func NewDefaultConfig() *Config {
|
||||
return &Config{
|
||||
TTL: int32(env.GetOrDefaultInt(EnvTTL, 300)),
|
||||
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
|
||||
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
|
||||
HTTPTimeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
|
||||
}
|
||||
}
|
||||
|
||||
// DNSProvider implements the challenge.Provider interface.
|
||||
type DNSProvider struct {
|
||||
config *Config
|
||||
client *hwdns.DnsClient
|
||||
|
||||
recordIDs map[string]string
|
||||
recordIDsMu sync.Mutex
|
||||
}
|
||||
|
||||
// NewDNSProvider returns a DNSProvider instance configured for Huawei Cloud.
|
||||
// Credentials must be passed in the environment variables:
|
||||
// HUAWEICLOUD_ACCESS_KEY_ID, HUAWEICLOUD_SECRET_ACCESS_KEY, and HUAWEICLOUD_REGION.
|
||||
func NewDNSProvider() (*DNSProvider, error) {
|
||||
values, err := env.Get(EnvAccessKeyID, EnvSecretAccessKey, EnvRegion)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("huaweicloud: %w", err)
|
||||
}
|
||||
|
||||
config := NewDefaultConfig()
|
||||
config.AccessKeyID = values[EnvAccessKeyID]
|
||||
config.SecretAccessKey = values[EnvSecretAccessKey]
|
||||
config.Region = values[EnvRegion]
|
||||
|
||||
return NewDNSProviderConfig(config)
|
||||
}
|
||||
|
||||
// NewDNSProviderConfig return a DNSProvider instance configured for Huawei Cloud.
|
||||
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||
if config == nil {
|
||||
return nil, errors.New("huaweicloud: the configuration of the DNS provider is nil")
|
||||
}
|
||||
|
||||
if config.AccessKeyID == "" || config.SecretAccessKey == "" || config.Region == "" {
|
||||
return nil, errors.New("huaweicloud: credentials missing")
|
||||
}
|
||||
|
||||
auth, err := hwauthbasic.NewCredentialsBuilder().
|
||||
WithAk(config.AccessKeyID).
|
||||
WithSk(config.SecretAccessKey).
|
||||
SafeBuild()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("huaweicloud: crendential build: %w", err)
|
||||
}
|
||||
|
||||
region, err := hwregion.SafeValueOf(config.Region)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("huaweicloud: safe region: %w", err)
|
||||
}
|
||||
|
||||
client, err := hwdns.DnsClientBuilder().
|
||||
WithHttpConfig(hwconfig.DefaultHttpConfig().WithTimeout(config.HTTPTimeout)).
|
||||
WithRegion(region).
|
||||
WithCredential(auth).
|
||||
SafeBuild()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("huaweicloud: client build: %w", err)
|
||||
}
|
||||
|
||||
return &DNSProvider{
|
||||
config: config,
|
||||
client: hwdns.NewDnsClient(client),
|
||||
recordIDs: map[string]string{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Present creates a TXT record using the specified parameters.
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||
|
||||
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("huaweicloud: could not find zone for domain %q: %w", domain, err)
|
||||
}
|
||||
|
||||
zoneID, err := d.getZoneID(authZone)
|
||||
if err != nil {
|
||||
return fmt.Errorf("huaweicloud: %w", err)
|
||||
}
|
||||
|
||||
recordSetID, err := d.getOrCreateRecordSetID(domain, zoneID, info)
|
||||
if err != nil {
|
||||
return fmt.Errorf("huaweicloud: %w", err)
|
||||
}
|
||||
|
||||
d.recordIDsMu.Lock()
|
||||
d.recordIDs[token] = recordSetID
|
||||
d.recordIDsMu.Unlock()
|
||||
|
||||
err = wait.For("record set sync on "+domain, d.config.PropagationTimeout, d.config.PollingInterval, func() (bool, error) {
|
||||
rs, errShow := d.client.ShowRecordSet(&hwmodel.ShowRecordSetRequest{
|
||||
ZoneId: zoneID,
|
||||
RecordsetId: recordSetID,
|
||||
})
|
||||
if errShow != nil {
|
||||
return false, fmt.Errorf("show record set: %w", errShow)
|
||||
}
|
||||
|
||||
return !strings.HasSuffix(deref(rs.Status), "PENDING_"), nil
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("huaweicloud: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CleanUp removes the TXT record matching the specified parameters.
|
||||
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||
|
||||
// gets the record's unique ID from when we created it
|
||||
d.recordIDsMu.Lock()
|
||||
recordID, ok := d.recordIDs[token]
|
||||
d.recordIDsMu.Unlock()
|
||||
if !ok {
|
||||
return fmt.Errorf("huaweicloud: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
|
||||
}
|
||||
|
||||
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("huaweicloud: could not find zone for domain %q: %w", domain, err)
|
||||
}
|
||||
|
||||
zoneID, err := d.getZoneID(authZone)
|
||||
if err != nil {
|
||||
return fmt.Errorf("huaweicloud: %w", err)
|
||||
}
|
||||
|
||||
request := &hwmodel.DeleteRecordSetRequest{
|
||||
ZoneId: zoneID,
|
||||
RecordsetId: recordID,
|
||||
}
|
||||
|
||||
_, err = d.client.DeleteRecordSet(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("huaweicloud: delete record: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Timeout returns the timeout and interval to use when checking for DNS propagation.
|
||||
// Adjusting here to cope with spikes in propagation times.
|
||||
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
||||
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||
}
|
||||
|
||||
func (d *DNSProvider) getOrCreateRecordSetID(domain, zoneID string, info dns01.ChallengeInfo) (string, error) {
|
||||
records, err := d.client.ListRecordSetsByZone(&hwmodel.ListRecordSetsByZoneRequest{
|
||||
ZoneId: zoneID,
|
||||
Name: pointer(info.EffectiveFQDN),
|
||||
})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("record list: unable to get record %s for zone %s: %w", info.EffectiveFQDN, domain, err)
|
||||
}
|
||||
|
||||
var existingRecordSet *hwmodel.ListRecordSets
|
||||
|
||||
for _, record := range deref(records.Recordsets) {
|
||||
if deref(record.Type) == "TXT" && deref(record.Name) == info.EffectiveFQDN {
|
||||
existingRecordSet = &record
|
||||
}
|
||||
}
|
||||
|
||||
value := strconv.Quote(info.Value)
|
||||
|
||||
if existingRecordSet == nil {
|
||||
request := &hwmodel.CreateRecordSetRequest{
|
||||
ZoneId: zoneID,
|
||||
Body: &hwmodel.CreateRecordSetRequestBody{
|
||||
Name: info.EffectiveFQDN,
|
||||
Description: pointer("Added TXT record for ACME dns-01 challenge using lego client"),
|
||||
Type: "TXT",
|
||||
Ttl: pointer(d.config.TTL),
|
||||
Records: []string{value},
|
||||
},
|
||||
}
|
||||
|
||||
resp, errCreate := d.client.CreateRecordSet(request)
|
||||
if errCreate != nil {
|
||||
return "", fmt.Errorf("create record set: %w", errCreate)
|
||||
}
|
||||
|
||||
return deref(resp.Id), nil
|
||||
}
|
||||
|
||||
updateRequest := &hwmodel.UpdateRecordSetRequest{
|
||||
ZoneId: zoneID,
|
||||
RecordsetId: deref(existingRecordSet.Id),
|
||||
Body: &hwmodel.UpdateRecordSetReq{
|
||||
Name: existingRecordSet.Name,
|
||||
Description: existingRecordSet.Description,
|
||||
Type: existingRecordSet.Type,
|
||||
Ttl: existingRecordSet.Ttl,
|
||||
Records: pointer(append(deref(existingRecordSet.Records), value)),
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := d.client.UpdateRecordSet(updateRequest)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("update record set: %w", err)
|
||||
}
|
||||
|
||||
return deref(resp.Id), nil
|
||||
}
|
||||
|
||||
func (d *DNSProvider) getZoneID(authZone string) (string, error) {
|
||||
zones, err := d.client.ListPublicZones(&hwmodel.ListPublicZonesRequest{})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to get zone: %w", err)
|
||||
}
|
||||
|
||||
for _, zone := range deref(zones.Zones) {
|
||||
if deref(zone.Name) == authZone {
|
||||
return deref(zone.Id), nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("zone %q not found", authZone)
|
||||
}
|
||||
|
||||
func pointer[T any](v T) *T { return &v }
|
||||
|
||||
func deref[T any](v *T) T {
|
||||
if v == nil {
|
||||
var zero T
|
||||
return zero
|
||||
}
|
||||
|
||||
return *v
|
||||
}
|
29
backend/utils/ssl/huaweicloud/huaweicloud.toml
Normal file
29
backend/utils/ssl/huaweicloud/huaweicloud.toml
Normal file
@ -0,0 +1,29 @@
|
||||
Name = "Huawei Cloud"
|
||||
Description = ''''''
|
||||
URL = "https://huaweicloud.com"
|
||||
Code = "huaweicloud"
|
||||
Since = "v4.19"
|
||||
|
||||
Example = '''
|
||||
HUAWEICLOUD_ACCESS_KEY_ID=your-access-key-id \
|
||||
HUAWEICLOUD_SECRET_ACCESS_KEY=your-secret-access-key \
|
||||
HUAWEICLOUD_REGION=cn-south-1 \
|
||||
lego --email you@example.com --dns huaweicloud --domains my.example.org run
|
||||
'''
|
||||
|
||||
[Configuration]
|
||||
[Configuration.Credentials]
|
||||
HUAWEICLOUD_ACCESS_KEY_ID = "Access key ID"
|
||||
HUAWEICLOUD_SECRET_ACCESS_KEY = "Access Key secret"
|
||||
HUAWEICLOUD_REGION = "Region"
|
||||
|
||||
[Configuration.Additional]
|
||||
HUAWEICLOUD_POLLING_INTERVAL = "Time between DNS propagation check"
|
||||
HUAWEICLOUD_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation"
|
||||
HUAWEICLOUD_TTL = "The TTL of the TXT record used for the DNS challenge"
|
||||
HUAWEICLOUD_HTTP_TIMEOUT = "API request timeout"
|
||||
|
||||
[Links]
|
||||
API = "https://console-intl.huaweicloud.com/apiexplorer/#/openapi/DNS/doc?locale=en-us"
|
||||
CN_API = "https://support.huaweicloud.com/api-dns/zh-cn_topic_0132421999.html"
|
||||
GoClient = "https://github.com/huaweicloud/huaweicloud-sdk-go-v3"
|
183
backend/utils/ssl/huaweicloud/huaweicloud_test.go
Normal file
183
backend/utils/ssl/huaweicloud/huaweicloud_test.go
Normal file
@ -0,0 +1,183 @@
|
||||
package huaweicloud
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/platform/tester"
|
||||
hwregion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/dns/v2/region"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const envDomain = envNamespace + "DOMAIN"
|
||||
|
||||
var envTest = tester.NewEnvTest(EnvAccessKeyID, EnvSecretAccessKey, EnvRegion).
|
||||
WithDomain(envDomain)
|
||||
|
||||
func TestNewDNSProvider(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
envVars map[string]string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "success",
|
||||
envVars: map[string]string{
|
||||
EnvAccessKeyID: "123",
|
||||
EnvSecretAccessKey: "456",
|
||||
EnvRegion: hwregion.CN_EAST_2.Id,
|
||||
},
|
||||
// The "success" cannot be tested because there is an API call that require a valid authentication.
|
||||
// Also, there is a bug during the error message creation:
|
||||
// https://github.com/huaweicloud/huaweicloud-sdk-go-v3/pull/81
|
||||
expected: "huaweicloud: client build: runtime error: invalid memory address or nil pointer dereference",
|
||||
},
|
||||
{
|
||||
desc: "missing credentials",
|
||||
envVars: map[string]string{
|
||||
EnvAccessKeyID: "",
|
||||
EnvSecretAccessKey: "",
|
||||
EnvRegion: "",
|
||||
},
|
||||
expected: "huaweicloud: some credentials information are missing: HUAWEICLOUD_ACCESS_KEY_ID,HUAWEICLOUD_SECRET_ACCESS_KEY,HUAWEICLOUD_REGION",
|
||||
},
|
||||
{
|
||||
desc: "missing access id",
|
||||
envVars: map[string]string{
|
||||
EnvAccessKeyID: "",
|
||||
EnvSecretAccessKey: "456",
|
||||
EnvRegion: hwregion.CN_EAST_2.Id,
|
||||
},
|
||||
expected: "huaweicloud: some credentials information are missing: HUAWEICLOUD_ACCESS_KEY_ID",
|
||||
},
|
||||
{
|
||||
desc: "missing secret key",
|
||||
envVars: map[string]string{
|
||||
EnvAccessKeyID: "123",
|
||||
EnvSecretAccessKey: "",
|
||||
EnvRegion: hwregion.CN_EAST_2.Id,
|
||||
},
|
||||
expected: "huaweicloud: some credentials information are missing: HUAWEICLOUD_SECRET_ACCESS_KEY",
|
||||
},
|
||||
{
|
||||
desc: "missing secret key",
|
||||
envVars: map[string]string{
|
||||
EnvAccessKeyID: "123",
|
||||
EnvSecretAccessKey: "456",
|
||||
EnvRegion: "",
|
||||
},
|
||||
expected: "huaweicloud: some credentials information are missing: HUAWEICLOUD_REGION",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
defer envTest.RestoreEnv()
|
||||
envTest.ClearEnv()
|
||||
|
||||
envTest.Apply(test.envVars)
|
||||
|
||||
p, err := NewDNSProvider()
|
||||
|
||||
if test.expected == "" {
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, p)
|
||||
require.NotNil(t, p.config)
|
||||
require.NotNil(t, p.client)
|
||||
} else {
|
||||
require.EqualError(t, err, test.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewDNSProviderConfig(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
accessKeyID string
|
||||
secretAccessKey string
|
||||
region string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "success",
|
||||
accessKeyID: "123",
|
||||
secretAccessKey: "456",
|
||||
region: hwregion.CN_EAST_2.Id,
|
||||
// The "success" cannot be tested because there is an API call that require a valid authentication.
|
||||
// Also, there is a bug during the error message creation:
|
||||
// https://github.com/huaweicloud/huaweicloud-sdk-go-v3/pull/81
|
||||
expected: "huaweicloud: client build: runtime error: invalid memory address or nil pointer dereference",
|
||||
},
|
||||
{
|
||||
desc: "missing credentials",
|
||||
expected: "huaweicloud: credentials missing",
|
||||
},
|
||||
{
|
||||
desc: "missing secret id",
|
||||
secretAccessKey: "456",
|
||||
region: hwregion.CN_EAST_2.Id,
|
||||
expected: "huaweicloud: credentials missing",
|
||||
},
|
||||
{
|
||||
desc: "missing secret key",
|
||||
accessKeyID: "123",
|
||||
region: hwregion.CN_EAST_2.Id,
|
||||
expected: "huaweicloud: credentials missing",
|
||||
},
|
||||
{
|
||||
desc: "missing region",
|
||||
accessKeyID: "123",
|
||||
secretAccessKey: "456",
|
||||
expected: "huaweicloud: credentials missing",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
config := NewDefaultConfig()
|
||||
config.AccessKeyID = test.accessKeyID
|
||||
config.SecretAccessKey = test.secretAccessKey
|
||||
config.Region = test.region
|
||||
|
||||
p, err := NewDNSProviderConfig(config)
|
||||
|
||||
if test.expected == "" {
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, p)
|
||||
require.NotNil(t, p.config)
|
||||
require.NotNil(t, p.client)
|
||||
} else {
|
||||
require.EqualError(t, err, test.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLivePresent(t *testing.T) {
|
||||
if !envTest.IsLiveTest() {
|
||||
t.Skip("skipping live test")
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = provider.Present(envTest.GetDomain(), "", "123d==")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestLiveCleanUp(t *testing.T) {
|
||||
if !envTest.IsLiveTest() {
|
||||
t.Skip("skipping live test")
|
||||
}
|
||||
|
||||
envTest.RestoreEnv()
|
||||
provider, err := NewDNSProvider()
|
||||
require.NoError(t, err)
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
|
||||
require.NoError(t, err)
|
||||
}
|
3
go.mod
3
go.mod
@ -24,6 +24,7 @@ require (
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gorilla/websocket v1.5.1
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.113
|
||||
github.com/jackc/pgx/v5 v5.5.4
|
||||
github.com/jinzhu/copier v0.4.0
|
||||
github.com/jinzhu/gorm v1.9.16
|
||||
@ -221,6 +222,7 @@ require (
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.898 // indirect
|
||||
github.com/therootcompany/xz v1.0.1 // indirect
|
||||
github.com/theupdateframework/notary v0.7.0 // indirect
|
||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.13 // indirect
|
||||
github.com/tklauser/numcpus v0.7.0 // indirect
|
||||
github.com/tonistiigi/fsutil v0.0.0-20240301111122-7525a1af2bb5 // indirect
|
||||
@ -233,6 +235,7 @@ require (
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
go.mongodb.org/mongo-driver v1.12.0 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.48.0 // indirect
|
||||
|
21
go.sum
21
go.sum
@ -369,6 +369,7 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
@ -453,6 +454,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.113 h1:odui9Ua0u1hPfpkutN/tGvtt0ms55I+gQqIdU8K1rlo=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.113/go.mod h1:JWz2ujO9X3oU5wb6kXp+DpR2UuDj2SldDbX8T0FSuhI=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
||||
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||
@ -501,6 +504,7 @@ github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI=
|
||||
github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
@ -599,6 +603,7 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mojocn/base64Captcha v1.3.6 h1:gZEKu1nsKpttuIAQgWHO+4Mhhls8cAKyiV2Ew03H+Tw=
|
||||
github.com/mojocn/base64Captcha v1.3.6/go.mod h1:i5CtHvm+oMbj1UzEPXaA8IH/xHFZ3DGY3Wh3dBpZ28E=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60=
|
||||
@ -780,6 +785,8 @@ github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+x
|
||||
github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY=
|
||||
github.com/theupdateframework/notary v0.7.0 h1:QyagRZ7wlSpjT5N2qQAh/pN+DVqgekv4DzbAiAiEL3c=
|
||||
github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnHqbFDGRSlXPO0AhYWw=
|
||||
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||
github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4=
|
||||
github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0=
|
||||
@ -807,6 +814,9 @@ github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
|
||||
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts=
|
||||
github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
@ -816,6 +826,7 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/xlzd/gotp v0.1.0 h1:37blvlKCh38s+fkem+fFh7sMnceltoIEBYTVXyoa5Po=
|
||||
github.com/xlzd/gotp v0.1.0/go.mod h1:ndLJ3JKzi3xLmUProq4LLxCuECL93dG9WASNLpHz8qg=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
@ -824,6 +835,8 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t
|
||||
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.mongodb.org/mongo-driver v1.12.0 h1:aPx33jmn/rQuJXPQLZQ8NtfPQG8CaqgLThFtqRb0PiE=
|
||||
go.mongodb.org/mongo-driver v1.12.0/go.mod h1:AZkxhPnFJUoH7kZlFkVKucV20K387miPfm7oimrSmK0=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
@ -872,11 +885,14 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@ -994,12 +1010,14 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@ -1009,9 +1027,12 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
Loading…
Reference in New Issue
Block a user