-
Notifications
You must be signed in to change notification settings - Fork 76
/
client.go
128 lines (111 loc) · 4.01 KB
/
client.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package dnsplugin
import (
"context"
"errors"
"fmt"
"os"
"os/exec"
"time"
"github.com/go-acme/lego/v4/challenge"
"github.com/hashicorp/go-plugin"
dnspluginproto "github.com/vancluever/terraform-provider-acme/v2/proto/dnsplugin/v1"
)
type NewClientResult struct {
Provider challenge.ProviderTimeout
Closer func()
IsSequential bool
SequentialInterval time.Duration
}
// NewClient creates a new DNS provider instance by dispatching to itself via
// go-plugin. The client for the new provider is returned, along with a closer
// function that should be called when done to shut down the plugin.
//
// The plugin is initialized with the settings passed in:
// - The environment is set with the config map.
// - If supplied, the global recursive nameservers are also set (via the
// dns01 package - some providers use these facilities).
func NewClient(
providerName string,
config map[string]string,
recursiveNameservers []string,
) (NewClientResult, error) {
// Discover the path to the executable that we are running at.
execPath, err := os.Executable()
if err != nil {
return NewClientResult{}, fmt.Errorf("error getting plugin path: %w", err)
}
cmd := exec.Command(execPath, "-dnsplugin")
client := plugin.NewClient(&plugin.ClientConfig{
HandshakeConfig: Handshake,
AutoMTLS: true,
Plugins: map[string]plugin.Plugin{PluginName: &DnsPlugin{}},
Cmd: cmd,
AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC},
})
rpcClient, err := client.Client()
if err != nil {
return NewClientResult{}, fmt.Errorf("error getting plugin client: %w", err)
}
raw, err := rpcClient.Dispense(PluginName)
if err != nil {
return NewClientResult{}, fmt.Errorf("error dispensing plugin: %w", err)
}
// First call the plugin as its gRPC server interface so that we can
// configure it.
var isSequential bool
var sequentialInterval time.Duration
if dnsProviderClient, ok := raw.(*DnsProviderClient); ok {
if err := dnsProviderClient.Configure(providerName, config, recursiveNameservers); err != nil {
return NewClientResult{}, fmt.Errorf("error configuring plugin: %w", err)
}
// Probe for sequential providers
sequentialInterval, isSequential = dnsProviderClient.IsSequential()
} else {
return NewClientResult{}, errors.New("internal error: returned plugin not a DnsProviderClient")
}
provider, ok := raw.(challenge.ProviderTimeout)
if !ok {
return NewClientResult{}, errors.New("internal error: returned plugin not a challenge provider")
}
return NewClientResult{
Provider: provider,
Closer: func() { rpcClient.Close() },
IsSequential: isSequential,
SequentialInterval: sequentialInterval,
}, nil
}
type DnsProviderClient struct {
client dnspluginproto.DNSProviderServiceClient
}
func (m *DnsProviderClient) Configure(providerName string, config map[string]string, recursiveNameservers []string) error {
_, err := m.client.Configure(context.Background(), &dnspluginproto.ConfigureRequest{
ProviderName: providerName,
Config: config,
RecursiveNameservers: recursiveNameservers,
})
return err
}
func (m *DnsProviderClient) Present(domain, token, keyAuth string) error {
_, err := m.client.Present(context.Background(), &dnspluginproto.PresentRequest{
Domain: domain,
Token: token,
KeyAuth: keyAuth,
})
return err
}
func (m *DnsProviderClient) CleanUp(domain, token, keyAuth string) error {
_, err := m.client.CleanUp(context.Background(), &dnspluginproto.CleanUpRequest{
Domain: domain,
Token: token,
KeyAuth: keyAuth,
})
return err
}
func (m *DnsProviderClient) Timeout() (time.Duration, time.Duration) {
resp, _ := m.client.Timeout(context.Background(), &dnspluginproto.TimeoutRequest{})
return resp.GetTimeout().AsDuration(), resp.GetInterval().AsDuration()
}
func (m *DnsProviderClient) IsSequential() (time.Duration, bool) {
resp, _ := m.client.IsSequential(context.Background(), &dnspluginproto.IsSequentialRequest{})
return resp.GetInterval().AsDuration(), resp.GetOk()
}