forked from TrueCloudLab/lego
gcloud: fix for wildcard (#740)
This commit is contained in:
parent
cb3c4c7937
commit
820c2b7531
9 changed files with 103 additions and 30 deletions
1
Gopkg.lock
generated
1
Gopkg.lock
generated
|
@ -682,6 +682,7 @@
|
|||
"golang.org/x/oauth2/clientcredentials",
|
||||
"golang.org/x/oauth2/google",
|
||||
"google.golang.org/api/dns/v1",
|
||||
"google.golang.org/api/googleapi",
|
||||
"gopkg.in/ns1/ns1-go.v2/rest",
|
||||
"gopkg.in/ns1/ns1-go.v2/rest/model/dns",
|
||||
"gopkg.in/square/go-jose.v2",
|
||||
|
|
|
@ -123,7 +123,7 @@ func (c *Challenge) Solve(authz acme.Authorization) error {
|
|||
|
||||
log.Infof("[%s] acme: Checking DNS record propagation using %+v", domain, recursiveNameservers)
|
||||
|
||||
err = wait.For(timeout, interval, func() (bool, error) {
|
||||
err = wait.For("propagation", timeout, interval, func() (bool, error) {
|
||||
stop, errP := c.preCheck.call(fqdn, value)
|
||||
if !stop || errP != nil {
|
||||
log.Infof("[%s] acme: Waiting for DNS record propagation.", domain)
|
||||
|
|
|
@ -91,10 +91,14 @@ func checkAuthoritativeNss(fqdn, value string, nameservers []string) (bool, erro
|
|||
return false, fmt.Errorf("NS %s returned %s for %s", ns, dns.RcodeToString[r.Rcode], fqdn)
|
||||
}
|
||||
|
||||
var records []string
|
||||
|
||||
var found bool
|
||||
for _, rr := range r.Answer {
|
||||
if txt, ok := rr.(*dns.TXT); ok {
|
||||
if strings.Join(txt.Txt, "") == value {
|
||||
record := strings.Join(txt.Txt, "")
|
||||
records = append(records, record)
|
||||
if record == value {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
|
@ -102,7 +106,7 @@ func checkAuthoritativeNss(fqdn, value string, nameservers []string) (bool, erro
|
|||
}
|
||||
|
||||
if !found {
|
||||
return false, fmt.Errorf("NS %s did not return the expected TXT record [fqdn: %s]", ns, fqdn)
|
||||
return false, fmt.Errorf("NS %s did not return the expected TXT record [fqdn: %s, value: %s]: %s", ns, fqdn, value, strings.Join(records, " ,"))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ func (l *EnvLoader) cmdPebble() (*exec.Cmd, *bytes.Buffer) {
|
|||
|
||||
func pebbleHealthCheck(options *CmdOption) {
|
||||
client := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}}
|
||||
err := wait.For(10*time.Second, 500*time.Millisecond, func() (bool, error) {
|
||||
err := wait.For("pebble", 10*time.Second, 500*time.Millisecond, func() (bool, error) {
|
||||
resp, err := client.Get(options.HealthCheckURL)
|
||||
if err != nil {
|
||||
return false, err
|
||||
|
|
|
@ -8,8 +8,8 @@ import (
|
|||
)
|
||||
|
||||
// For polls the given function 'f', once every 'interval', up to 'timeout'.
|
||||
func For(timeout, interval time.Duration, f func() (bool, error)) error {
|
||||
log.Infof("Wait [timeout: %s, interval: %s]", timeout, interval)
|
||||
func For(msg string, timeout, interval time.Duration, f func() (bool, error)) error {
|
||||
log.Infof("Wait for %s [timeout: %s, interval: %s]", msg, timeout, interval)
|
||||
|
||||
var lastErr string
|
||||
timeUp := time.After(timeout)
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
func TestForTimeout(t *testing.T) {
|
||||
c := make(chan error)
|
||||
go func() {
|
||||
err := For(3*time.Second, 1*time.Second, func() (bool, error) {
|
||||
err := For("", 3*time.Second, 1*time.Second, func() (bool, error) {
|
||||
return false, nil
|
||||
})
|
||||
c <- err
|
||||
|
|
|
@ -8,17 +8,22 @@ import (
|
|||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/xenolf/lego/challenge/dns01"
|
||||
"github.com/xenolf/lego/log"
|
||||
"github.com/xenolf/lego/platform/config/env"
|
||||
"github.com/xenolf/lego/platform/wait"
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2/google"
|
||||
"google.golang.org/api/dns/v1"
|
||||
"google.golang.org/api/googleapi"
|
||||
)
|
||||
|
||||
// Config is used to configure the creation of the DNSProvider
|
||||
type Config struct {
|
||||
Debug bool
|
||||
Project string
|
||||
PropagationTimeout time.Duration
|
||||
PollingInterval time.Duration
|
||||
|
@ -29,6 +34,7 @@ type Config struct {
|
|||
// NewDefaultConfig returns a default configuration for the DNSProvider
|
||||
func NewDefaultConfig() *Config {
|
||||
return &Config{
|
||||
Debug: env.GetOrDefaultBool("GCE_DEBUG", false),
|
||||
TTL: env.GetOrDefaultInt("GCE_TTL", dns01.DefaultTTL),
|
||||
PropagationTimeout: env.GetOrDefaultSecond("GCE_PROPAGATION_TIMEOUT", 180*time.Second),
|
||||
PollingInterval: env.GetOrDefaultSecond("GCE_POLLING_INTERVAL", 5*time.Second),
|
||||
|
@ -131,11 +137,32 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||
}
|
||||
|
||||
// Look for existing records.
|
||||
existing, err := d.findTxtRecords(zone, fqdn)
|
||||
existingRrSet, err := d.findTxtRecords(zone, fqdn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("googlecloud: %v", err)
|
||||
}
|
||||
|
||||
for _, rrSet := range existingRrSet {
|
||||
var rrd []string
|
||||
for _, rr := range rrSet.Rrdatas {
|
||||
data := mustUnquote(rr)
|
||||
rrd = append(rrd, data)
|
||||
|
||||
if data == value {
|
||||
log.Printf("skip: the record already exists: %s", value)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
rrSet.Rrdatas = rrd
|
||||
}
|
||||
|
||||
// Attempt to delete the existing records before adding the new one.
|
||||
if len(existingRrSet) > 0 {
|
||||
if err = d.applyChanges(zone, &dns.Change{Deletions: existingRrSet}); err != nil {
|
||||
return fmt.Errorf("googlecloud: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
rec := &dns.ResourceRecordSet{
|
||||
Name: fqdn,
|
||||
Rrdatas: []string{value},
|
||||
|
@ -143,36 +170,69 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||
Type: "TXT",
|
||||
}
|
||||
|
||||
change := &dns.Change{}
|
||||
|
||||
if len(existing) > 0 {
|
||||
// Attempt to delete the existing records when adding our new one.
|
||||
change.Deletions = existing
|
||||
|
||||
// Append existing TXT record data to the new TXT record data
|
||||
for _, value := range existing {
|
||||
rec.Rrdatas = append(rec.Rrdatas, value.Rrdatas...)
|
||||
// Append existing TXT record data to the new TXT record data
|
||||
for _, rrSet := range existingRrSet {
|
||||
for _, rr := range rrSet.Rrdatas {
|
||||
if rr != value {
|
||||
rec.Rrdatas = append(rec.Rrdatas, rrSet.Rrdatas...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
change.Additions = []*dns.ResourceRecordSet{rec}
|
||||
change := &dns.Change{
|
||||
Additions: []*dns.ResourceRecordSet{rec},
|
||||
}
|
||||
|
||||
chg, err := d.client.Changes.Create(d.config.Project, zone, change).Do()
|
||||
if err != nil {
|
||||
if err = d.applyChanges(zone, change); err != nil {
|
||||
return fmt.Errorf("googlecloud: %v", err)
|
||||
}
|
||||
|
||||
// wait for change to be acknowledged
|
||||
for chg.Status == "pending" {
|
||||
time.Sleep(time.Second)
|
||||
return nil
|
||||
}
|
||||
|
||||
chg, err = d.client.Changes.Get(d.config.Project, zone, chg.Id).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("googlecloud: %v", err)
|
||||
}
|
||||
func (d *DNSProvider) applyChanges(zone string, change *dns.Change) error {
|
||||
if d.config.Debug {
|
||||
data, _ := json.Marshal(change)
|
||||
log.Printf("change (Create): %s", string(data))
|
||||
}
|
||||
|
||||
return nil
|
||||
chg, err := d.client.Changes.Create(d.config.Project, zone, change).Do()
|
||||
if err != nil {
|
||||
if v, ok := err.(*googleapi.Error); ok {
|
||||
if v.Code == http.StatusNotFound {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
data, _ := json.Marshal(change)
|
||||
return fmt.Errorf("failed to perform changes [zone %s, change %s]: %v", zone, string(data), err)
|
||||
}
|
||||
|
||||
if chg.Status == "done" {
|
||||
return nil
|
||||
}
|
||||
|
||||
chgID := chg.Id
|
||||
|
||||
// wait for change to be acknowledged
|
||||
return wait.For("apply change", 30*time.Second, 3*time.Second, func() (bool, error) {
|
||||
if d.config.Debug {
|
||||
data, _ := json.Marshal(change)
|
||||
log.Printf("change (Get): %s", string(data))
|
||||
}
|
||||
|
||||
chg, err = d.client.Changes.Get(d.config.Project, zone, chgID).Do()
|
||||
if err != nil {
|
||||
data, _ := json.Marshal(change)
|
||||
return false, fmt.Errorf("failed to get changes [zone %s, change %s]: %v", zone, string(data), err)
|
||||
}
|
||||
|
||||
if chg.Status == "done" {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, fmt.Errorf("status: %s", chg.Status)
|
||||
})
|
||||
}
|
||||
|
||||
// CleanUp removes the TXT record matching the specified parameters.
|
||||
|
@ -236,3 +296,11 @@ func (d *DNSProvider) findTxtRecords(zone, fqdn string) ([]*dns.ResourceRecordSe
|
|||
|
||||
return recs.Rrsets, nil
|
||||
}
|
||||
|
||||
func mustUnquote(raw string) string {
|
||||
clean, err := strconv.Unquote(raw)
|
||||
if err != nil {
|
||||
return raw
|
||||
}
|
||||
return clean
|
||||
}
|
||||
|
|
|
@ -146,7 +146,7 @@ func (d *DNSProvider) changeRecord(action, fqdn, value, domain string, ttl int)
|
|||
|
||||
statusID := resp.ChangeInfo.ID
|
||||
|
||||
return wait.For(120*time.Second, 4*time.Second, func() (bool, error) {
|
||||
return wait.For("nifcloud", 120*time.Second, 4*time.Second, func() (bool, error) {
|
||||
resp, err := d.client.GetChange(statusID)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to query NIFCLOUD DNS change status: %v", err)
|
||||
|
|
|
@ -197,7 +197,7 @@ func (d *DNSProvider) changeRecord(action, hostedZoneID string, recordSet *route
|
|||
|
||||
changeID := resp.ChangeInfo.Id
|
||||
|
||||
return wait.For(d.config.PropagationTimeout, d.config.PollingInterval, func() (bool, error) {
|
||||
return wait.For("route53", d.config.PropagationTimeout, d.config.PollingInterval, func() (bool, error) {
|
||||
reqParams := &route53.GetChangeInput{Id: changeID}
|
||||
|
||||
resp, err := d.client.GetChange(reqParams)
|
||||
|
|
Loading…
Reference in a new issue