selectelv2: add missing options (#2639)

This commit is contained in:
Ludovic Fernandez 2025-09-07 23:30:00 +02:00 committed by GitHub
commit 6bfc090680
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 66 additions and 29 deletions

View file

@ -2935,11 +2935,14 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "SELECTELV2_AUTH_REGION": Location for auth endpoint like ResellAPI or Keystone (default: 'ru-1')`)
ew.writeln(` - "SELECTELV2_AUTH_URL": Identity endpoint (defaul: 'https://cloud.api.selcloud.ru/identity/v3/')`)
ew.writeln(` - "SELECTELV2_BASE_URL": API endpoint URL`)
ew.writeln(` - "SELECTELV2_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "SELECTELV2_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 5)`)
ew.writeln(` - "SELECTELV2_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 120)`)
ew.writeln(` - "SELECTELV2_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)`)
ew.writeln(` - "SELECTELV2_USER_DOMAIN_NAME": To specify the domain name (account ID) where the user is located. (default: SELECTELV2_ACCOUNT_ID)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/selectelv2`)

View file

@ -53,11 +53,14 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
| Environment Variable Name | Description |
|--------------------------------|-------------|
| `SELECTELV2_AUTH_REGION` | Location for auth endpoint like ResellAPI or Keystone (default: 'ru-1') |
| `SELECTELV2_AUTH_URL` | Identity endpoint (defaul: 'https://cloud.api.selcloud.ru/identity/v3/') |
| `SELECTELV2_BASE_URL` | API endpoint URL |
| `SELECTELV2_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
| `SELECTELV2_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 5) |
| `SELECTELV2_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 120) |
| `SELECTELV2_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 60) |
| `SELECTELV2_USER_DOMAIN_NAME` | To specify the domain name (account ID) where the user is located. (default: SELECTELV2_ACCOUNT_ID) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).

View file

@ -21,11 +21,14 @@ import (
const (
envNamespace = "SELECTELV2_"
EnvBaseURL = envNamespace + "BASE_URL"
EnvUsernameOS = envNamespace + "USERNAME"
EnvPasswordOS = envNamespace + "PASSWORD"
EnvAccount = envNamespace + "ACCOUNT_ID"
EnvProjectID = envNamespace + "PROJECT_ID"
EnvBaseURL = envNamespace + "BASE_URL"
EnvUsernameOS = envNamespace + "USERNAME"
EnvPasswordOS = envNamespace + "PASSWORD"
EnvDomainName = envNamespace + "ACCOUNT_ID"
EnvProjectID = envNamespace + "PROJECT_ID"
EnvAuthRegion = envNamespace + "AUTH_REGION"
EnvAuthURL = envNamespace + "AUTH_URL"
EnvUserDomainName = envNamespace + "USER_DOMAIN_NAME"
EnvTTL = envNamespace + "TTL"
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
@ -34,7 +37,12 @@ const (
)
const (
defaultBaseURL = "https://api.selectel.ru/domains/v2"
defaultBaseURL = "https://api.selectel.ru/domains/v2"
defaultAuthRegion = "ru-1"
defaultAuthURL = "https://cloud.api.selcloud.ru/identity/v3/"
)
const (
defaultTTL = 60
defaultPropagationTimeout = 120 * time.Second
defaultPollingInterval = 5 * time.Second
@ -47,11 +55,15 @@ var errNotFound = errors.New("rrset not found")
// Config is used to configure the creation of the DNSProvider.
type Config struct {
BaseURL string
Username string
Password string
Account string
ProjectID string
BaseURL string
Username string
Password string
DomainName string
ProjectID string
AuthURL string
AuthRegion string
UserDomainName string
TTL int
PropagationTimeout time.Duration
PollingInterval time.Duration
@ -61,7 +73,10 @@ type Config struct {
// NewDefaultConfig returns a default configuration for the DNSProvider.
func NewDefaultConfig() *Config {
return &Config{
BaseURL: env.GetOrDefaultString(EnvBaseURL, defaultBaseURL),
BaseURL: env.GetOrDefaultString(EnvBaseURL, defaultBaseURL),
AuthRegion: env.GetOrDefaultString(EnvAuthRegion, defaultAuthRegion),
AuthURL: env.GetOrDefaultString(EnvAuthURL, defaultAuthURL),
TTL: env.GetOrDefaultInt(EnvTTL, defaultTTL),
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, defaultPropagationTimeout),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, defaultPollingInterval),
@ -78,7 +93,7 @@ type DNSProvider struct {
// NewDNSProvider returns a DNSProvider instance configured for Selectel Domains APIv2.
func NewDNSProvider() (*DNSProvider, error) {
values, err := env.Get(EnvUsernameOS, EnvPasswordOS, EnvAccount, EnvProjectID)
values, err := env.Get(EnvUsernameOS, EnvPasswordOS, EnvDomainName, EnvProjectID)
if err != nil {
return nil, fmt.Errorf("selectelv2: %w", err)
}
@ -86,8 +101,9 @@ func NewDNSProvider() (*DNSProvider, error) {
config := NewDefaultConfig()
config.Username = values[EnvUsernameOS]
config.Password = values[EnvPasswordOS]
config.Account = values[EnvAccount]
config.DomainName = values[EnvDomainName]
config.ProjectID = values[EnvProjectID]
config.UserDomainName = env.GetOrDefaultString(EnvUserDomainName, "")
return NewDNSProviderConfig(config)
}
@ -106,8 +122,8 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("selectelv2: missing password")
}
if config.Account == "" {
return nil, errors.New("selectelv2: missing account")
if config.DomainName == "" {
return nil, errors.New("selectelv2: missing account ID")
}
if config.ProjectID == "" {
@ -133,7 +149,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
func (d *DNSProvider) Present(domain, _, keyAuth string) error {
ctx := context.Background()
client, err := d.authorize()
client, err := d.authorize(ctx)
if err != nil {
return fmt.Errorf("selectelv2: authorize: %w", err)
}
@ -180,7 +196,7 @@ func (d *DNSProvider) Present(domain, _, keyAuth string) error {
func (d *DNSProvider) CleanUp(domain, _, keyAuth string) error {
ctx := context.Background()
client, err := d.authorize()
client, err := d.authorize(ctx)
if err != nil {
return fmt.Errorf("selectelv2: authorize: %w", err)
}
@ -221,8 +237,8 @@ func (d *DNSProvider) CleanUp(domain, _, keyAuth string) error {
return nil
}
func (d *DNSProvider) authorize() (*clientWrapper, error) {
token, err := obtainOpenstackToken(d.config)
func (d *DNSProvider) authorize(ctx context.Context) (*clientWrapper, error) {
token, err := obtainOpenstackToken(ctx, d.config)
if err != nil {
return nil, err
}
@ -235,12 +251,16 @@ func (d *DNSProvider) authorize() (*clientWrapper, error) {
}, nil
}
func obtainOpenstackToken(config *Config) (string, error) {
func obtainOpenstackToken(ctx context.Context, config *Config) (string, error) {
vpcClient, err := selvpcclient.NewClient(&selvpcclient.ClientOptions{
Context: ctx,
DomainName: config.DomainName,
AuthURL: config.AuthURL,
AuthRegion: config.AuthRegion,
Username: config.Username,
Password: config.Password,
UserDomainName: config.Account,
ProjectID: config.ProjectID,
UserDomainName: config.UserDomainName,
})
if err != nil {
return "", fmt.Errorf("new VPC client: %w", err)

View file

@ -20,6 +20,9 @@ lego --email you@example.com --dns selectelv2 -d '*.example.com' -d example.com
SELECTELV2_PROJECT_ID = "Cloud project ID (UUID)"
[Configuration.Additional]
SELECTELV2_BASE_URL = "API endpoint URL"
SELECTELV2_AUTH_REGION = "Location for auth endpoint like ResellAPI or Keystone (default: 'ru-1')"
SELECTELV2_AUTH_URL = "Identity endpoint (defaul: 'https://cloud.api.selcloud.ru/identity/v3/')"
SELECTELV2_USER_DOMAIN_NAME = "To specify the domain name (account ID) where the user is located. (default: SELECTELV2_ACCOUNT_ID)"
SELECTELV2_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 5)"
SELECTELV2_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 120)"
SELECTELV2_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)"

View file

@ -11,7 +11,15 @@ import (
const envDomain = envNamespace + "DOMAIN"
var envTest = tester.NewEnvTest(EnvUsernameOS, EnvPasswordOS, EnvAccount, EnvProjectID).
var envTest = tester.NewEnvTest(
EnvUsernameOS,
EnvPasswordOS,
EnvDomainName,
EnvUserDomainName,
EnvProjectID,
EnvAuthRegion,
EnvAuthURL,
).
WithDomain(envDomain)
func TestNewDNSProvider(t *testing.T) {
@ -25,7 +33,7 @@ func TestNewDNSProvider(t *testing.T) {
envVars: map[string]string{
EnvUsernameOS: "someName",
EnvPasswordOS: "qwerty",
EnvAccount: "1",
EnvDomainName: "1",
EnvProjectID: "111a11111aaa11aa1a11aaa11111aa1a",
},
},
@ -33,7 +41,7 @@ func TestNewDNSProvider(t *testing.T) {
desc: "missing username",
envVars: map[string]string{
EnvPasswordOS: "qwerty",
EnvAccount: "1",
EnvDomainName: "1",
EnvProjectID: "111a11111aaa11aa1a11aaa11111aa1a",
},
expected: "selectelv2: some credentials information are missing: SELECTELV2_USERNAME",
@ -42,7 +50,7 @@ func TestNewDNSProvider(t *testing.T) {
desc: "missing password",
envVars: map[string]string{
EnvUsernameOS: "someName",
EnvAccount: "1",
EnvDomainName: "1",
EnvProjectID: "111a11111aaa11aa1a11aaa11111aa1a",
},
expected: "selectelv2: some credentials information are missing: SELECTELV2_PASSWORD",
@ -61,7 +69,7 @@ func TestNewDNSProvider(t *testing.T) {
envVars: map[string]string{
EnvUsernameOS: "someName",
EnvPasswordOS: "qwerty",
EnvAccount: "1",
EnvDomainName: "1",
},
expected: "selectelv2: some credentials information are missing: SELECTELV2_PROJECT_ID",
},
@ -123,7 +131,7 @@ func TestNewDNSProviderConfig(t *testing.T) {
username: "user",
password: "secret",
projectID: "111a11111aaa11aa1a11aaa11111aa1a",
expected: "selectelv2: missing account",
expected: "selectelv2: missing account ID",
},
{
desc: "missing projectID",
@ -139,7 +147,7 @@ func TestNewDNSProviderConfig(t *testing.T) {
config := NewDefaultConfig()
config.Username = test.username
config.Password = test.password
config.Account = test.account
config.DomainName = test.account
config.ProjectID = test.projectID
p, err := NewDNSProviderConfig(config)