Migrate to golangci-lint (#644)

* refactor: linting.

- errcheck
- govet
- golint
- goconst
- spellcheck
- ...

* refactor: migrate from gometalinter to golangci-lint.
This commit is contained in:
Ludovic Fernandez 2018-09-24 21:07:20 +02:00 committed by Wyatt Johnson
parent 38ffd0577b
commit ad20bf90ff
74 changed files with 950 additions and 810 deletions

42
.golangci.toml Normal file
View file

@ -0,0 +1,42 @@
[run]
deadline = "2m"
[linters-settings]
[linters-settings.govet]
check-shadowing = true
[linters-settings.gocyclo]
min-complexity = 16.0
[linters-settings.maligned]
suggest-new = true
[linters-settings.goconst]
min-len = 2.0
min-occurrences = 3.0
[linters-settings.misspell]
locale = "US"
[linters]
enable-all = true
disable = [
"maligned",
"lll",
"gas",
"dupl",
"prealloc",
]
[issues]
max-per-linter = 0
max-same = 0
exclude = [
"session.New is deprecated:", # providers/dns/route53/route53_integration_test.go | providers/dns/route53/route53_test.go
"func (.+)disableAuthz(.) is unused", # acme/client.go#disableAuthz
"type (.+)deactivateAuthMessage(.) is unused", # acme/messages.go#deactivateAuthMessage
"(.)limitReader(.) - (.)numBytes(.) always receives (.)1048576(.)", # acme/crypto.go#limitReader
"cyclomatic complexity (\\d+) of func (.)NewDNSChallengeProviderByName(.) is high", # providers/dns/dns_providers.go#NewDNSChallengeProviderByName
"cyclomatic complexity (\\d+) of func (.)setup(.) is high", # cli_handler.go#setup
]

View file

@ -18,9 +18,8 @@ before_install:
- chmod +x $GOPATH/bin/dep - chmod +x $GOPATH/bin/dep
# Install linters and misspell # Install linters and misspell
- go get -u github.com/alecthomas/gometalinter - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.10.2
- gometalinter --install - golangci-lint --version
install: install:
- dep status -v - dep status -v

View file

@ -17,8 +17,8 @@ dependencies:
test: clean test: clean
go test -v -cover ./... go test -v -cover ./...
checks: check-fmt checks:
gometalinter ./... golangci-lint run
check-fmt: SHELL := /bin/bash check-fmt: SHELL := /bin/bash
check-fmt: check-fmt:

View file

@ -26,6 +26,9 @@ const (
// “new-reg”, “new-authz” and “new-cert” endpoints. From the documentation the // “new-reg”, “new-authz” and “new-cert” endpoints. From the documentation the
// limitation is 20 requests per second, but using 20 as value doesn't work but 18 do // limitation is 20 requests per second, but using 20 as value doesn't work but 18 do
overallRequestLimit = 18 overallRequestLimit = 18
statusValid = "valid"
statusInvalid = "invalid"
) )
// User interface is to be implemented by users of this library. // User interface is to be implemented by users of this library.
@ -43,7 +46,7 @@ type solver interface {
// Interface for challenges like dns, where we can set a record in advance for ALL challenges. // Interface for challenges like dns, where we can set a record in advance for ALL challenges.
// This saves quite a bit of time vs creating the records and solving them serially. // This saves quite a bit of time vs creating the records and solving them serially.
type presolver interface { type preSolver interface {
PreSolve(challenge challenge, domain string) error PreSolve(challenge challenge, domain string) error
} }
@ -502,9 +505,9 @@ func (c *Client) RenewCertificate(cert CertificateResource, bundle, mustStaple b
// Start by checking to see if the certificate was based off a CSR, and // Start by checking to see if the certificate was based off a CSR, and
// use that if it's defined. // use that if it's defined.
if len(cert.CSR) > 0 { if len(cert.CSR) > 0 {
csr, err := pemDecodeTox509CSR(cert.CSR) csr, errP := pemDecodeTox509CSR(cert.CSR)
if err != nil { if errP != nil {
return nil, err return nil, errP
} }
newCert, failures := c.ObtainCertificateForCSR(*csr, bundle) newCert, failures := c.ObtainCertificateForCSR(*csr, bundle)
return newCert, failures return newCert, failures
@ -537,7 +540,6 @@ func (c *Client) RenewCertificate(cert CertificateResource, bundle, mustStaple b
} }
func (c *Client) createOrderForIdentifiers(domains []string) (orderResource, error) { func (c *Client) createOrderForIdentifiers(domains []string) (orderResource, error) {
var identifiers []identifier var identifiers []identifier
for _, domain := range domains { for _, domain := range domains {
identifiers = append(identifiers, identifier{Type: "dns", Value: domain}) identifiers = append(identifiers, identifier{Type: "dns", Value: domain})
@ -577,16 +579,16 @@ func (c *Client) solveChallengeForAuthz(authorizations []authorization) error {
// loop through the resources, basically through the domains. First pass just selects a solver for each authz. // loop through the resources, basically through the domains. First pass just selects a solver for each authz.
for _, authz := range authorizations { for _, authz := range authorizations {
if authz.Status == "valid" { if authz.Status == statusValid {
// Boulder might recycle recent validated authz (see issue #267) // Boulder might recycle recent validated authz (see issue #267)
log.Infof("[%s] acme: Authorization already valid; skipping challenge", authz.Identifier.Value) log.Infof("[%s] acme: Authorization already valid; skipping challenge", authz.Identifier.Value)
continue continue
} }
if i, solver := c.chooseSolver(authz, authz.Identifier.Value); solver != nil { if i, solvr := c.chooseSolver(authz, authz.Identifier.Value); solvr != nil {
authSolvers = append(authSolvers, &selectedAuthSolver{ authSolvers = append(authSolvers, &selectedAuthSolver{
authz: authz, authz: authz,
challengeIndex: i, challengeIndex: i,
solver: solver, solver: solvr,
}) })
} else { } else {
failures[authz.Identifier.Value] = fmt.Errorf("[%s] acme: Could not determine solvers", authz.Identifier.Value) failures[authz.Identifier.Value] = fmt.Errorf("[%s] acme: Could not determine solvers", authz.Identifier.Value)
@ -597,7 +599,7 @@ func (c *Client) solveChallengeForAuthz(authorizations []authorization) error {
for _, item := range authSolvers { for _, item := range authSolvers {
authz := item.authz authz := item.authz
i := item.challengeIndex i := item.challengeIndex
if presolver, ok := item.solver.(presolver); ok { if presolver, ok := item.solver.(preSolver); ok {
if err := presolver.PreSolve(authz.Challenges[i], authz.Identifier.Value); err != nil { if err := presolver.PreSolve(authz.Challenges[i], authz.Identifier.Value); err != nil {
failures[authz.Identifier.Value] = err failures[authz.Identifier.Value] = err
} }
@ -607,12 +609,12 @@ func (c *Client) solveChallengeForAuthz(authorizations []authorization) error {
defer func() { defer func() {
// clean all created TXT records // clean all created TXT records
for _, item := range authSolvers { for _, item := range authSolvers {
if cleanup, ok := item.solver.(cleanup); ok { if clean, ok := item.solver.(cleanup); ok {
if failures[item.authz.Identifier.Value] != nil { if failures[item.authz.Identifier.Value] != nil {
// already failed in previous loop // already failed in previous loop
continue continue
} }
err := cleanup.CleanUp(item.authz.Challenges[item.challengeIndex], item.authz.Identifier.Value) err := clean.CleanUp(item.authz.Challenges[item.challengeIndex], item.authz.Identifier.Value)
if err != nil { if err != nil {
log.Warnf("Error cleaning up %s: %v ", item.authz.Identifier.Value, err) log.Warnf("Error cleaning up %s: %v ", item.authz.Identifier.Value, err)
} }
@ -755,7 +757,7 @@ func (c *Client) requestCertificateForCsr(order orderResource, bundle bool, csr
return nil, err return nil, err
} }
if retOrder.Status == "invalid" { if retOrder.Status == statusInvalid {
return nil, err return nil, err
} }
@ -765,7 +767,7 @@ func (c *Client) requestCertificateForCsr(order orderResource, bundle bool, csr
PrivateKey: privateKeyPem, PrivateKey: privateKeyPem,
} }
if retOrder.Status == "valid" { if retOrder.Status == statusValid {
// if the certificate is available right away, short cut! // if the certificate is available right away, short cut!
ok, err := c.checkCertResponse(retOrder, &certRes, bundle) ok, err := c.checkCertResponse(retOrder, &certRes, bundle)
if err != nil { if err != nil {
@ -809,9 +811,8 @@ func (c *Client) requestCertificateForCsr(order orderResource, bundle bool, csr
// should already have the Domain (common name) field populated. If bundle is // should already have the Domain (common name) field populated. If bundle is
// true, the certificate will be bundled with the issuer's cert. // true, the certificate will be bundled with the issuer's cert.
func (c *Client) checkCertResponse(order orderMessage, certRes *CertificateResource, bundle bool) (bool, error) { func (c *Client) checkCertResponse(order orderMessage, certRes *CertificateResource, bundle bool) (bool, error) {
switch order.Status { switch order.Status {
case "valid": case statusValid:
resp, err := httpGet(order.Certificate) resp, err := httpGet(order.Certificate)
if err != nil { if err != nil {
return false, err return false, err
@ -860,7 +861,7 @@ func (c *Client) checkCertResponse(order orderMessage, certRes *CertificateResou
case "processing": case "processing":
return false, nil return false, nil
case "invalid": case statusInvalid:
return false, errors.New("order has invalid state: invalid") return false, errors.New("order has invalid state: invalid")
default: default:
return false, nil return false, nil
@ -922,12 +923,12 @@ func validate(j *jws, domain, uri string, c challenge) error {
// Repeatedly check the server for an updated status on our request. // Repeatedly check the server for an updated status on our request.
for { for {
switch chlng.Status { switch chlng.Status {
case "valid": case statusValid:
log.Infof("[%s] The server validated our request", domain) log.Infof("[%s] The server validated our request", domain)
return nil return nil
case "pending": case "pending":
case "processing": case "processing":
case "invalid": case statusInvalid:
return handleChallengeError(chlng) return handleChallengeError(chlng)
default: default:
return errors.New("the server returned an unexpected state") return errors.New("the server returned an unexpected state")

View file

@ -35,7 +35,12 @@ func TestNewClient(t *testing.T) {
RevokeCertURL: "http://test", RevokeCertURL: "http://test",
KeyChangeURL: "http://test", KeyChangeURL: "http://test",
}) })
w.Write(data)
_, err = w.Write(data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
})) }))
client, err := NewClient(ts.URL, user, keyType) client, err := NewClient(ts.URL, user, keyType)
@ -66,7 +71,12 @@ func TestClientOptPort(t *testing.T) {
RevokeCertURL: "http://test", RevokeCertURL: "http://test",
KeyChangeURL: "http://test", KeyChangeURL: "http://test",
}) })
w.Write(data)
_, err = w.Write(data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
})) }))
optPort := "1234" optPort := "1234"
@ -75,7 +85,8 @@ func TestClientOptPort(t *testing.T) {
client, err := NewClient(ts.URL, user, RSA2048) client, err := NewClient(ts.URL, user, RSA2048)
require.NoError(t, err, "Could not create client") require.NoError(t, err, "Could not create client")
client.SetHTTPAddress(net.JoinHostPort(optHost, optPort)) err = client.SetHTTPAddress(net.JoinHostPort(optHost, optPort))
require.NoError(t, err)
require.IsType(t, &httpChallenge{}, client.solvers[HTTP01]) require.IsType(t, &httpChallenge{}, client.solvers[HTTP01])
httpSolver := client.solvers[HTTP01].(*httpChallenge) httpSolver := client.solvers[HTTP01].(*httpChallenge)
@ -88,7 +99,8 @@ func TestClientOptPort(t *testing.T) {
// test setting different host // test setting different host
optHost = "127.0.0.1" optHost = "127.0.0.1"
client.SetHTTPAddress(net.JoinHostPort(optHost, optPort)) err = client.SetHTTPAddress(net.JoinHostPort(optHost, optPort))
require.NoError(t, err)
assert.Equal(t, optHost, httpSolver.provider.(*HTTPProviderServer).iface, "iface") assert.Equal(t, optHost, httpSolver.provider.(*HTTPProviderServer).iface, "iface")
} }
@ -109,11 +121,17 @@ func TestNotHoldingLockWhileMakingHTTPRequests(t *testing.T) {
ch := make(chan bool) ch := make(chan bool)
resultCh := make(chan bool) resultCh := make(chan bool)
go func() { go func() {
j.Nonce() _, errN := j.Nonce()
if errN != nil {
t.Log(errN)
}
ch <- true ch <- true
}() }()
go func() { go func() {
j.Nonce() _, errN := j.Nonce()
if errN != nil {
t.Log(errN)
}
ch <- true ch <- true
}() }()
go func() { go func() {

View file

@ -81,20 +81,20 @@ func GetOCSPForCert(bundle []byte) ([]byte, *ocsp.Response, error) {
return nil, nil, errors.New("no issuing certificate URL") return nil, nil, errors.New("no issuing certificate URL")
} }
resp, err := httpGet(issuedCert.IssuingCertificateURL[0]) resp, errC := httpGet(issuedCert.IssuingCertificateURL[0])
if err != nil { if errC != nil {
return nil, nil, err return nil, nil, errC
} }
defer resp.Body.Close() defer resp.Body.Close()
issuerBytes, err := ioutil.ReadAll(limitReader(resp.Body, 1024*1024)) issuerBytes, errC := ioutil.ReadAll(limitReader(resp.Body, 1024*1024))
if err != nil { if errC != nil {
return nil, nil, err return nil, nil, errC
} }
issuerCert, err := x509.ParseCertificate(issuerBytes) issuerCert, errC := x509.ParseCertificate(issuerBytes)
if err != nil { if errC != nil {
return nil, nil, err return nil, nil, errC
} }
// Insert it into the slice on position 0 // Insert it into the slice on position 0
@ -258,15 +258,6 @@ func pemDecode(data []byte) (*pem.Block, error) {
return pemBlock, nil return pemBlock, nil
} }
func pemDecodeTox509(pem []byte) (*x509.Certificate, error) {
pemBlock, err := pemDecode(pem)
if pemBlock == nil {
return nil, err
}
return x509.ParseCertificate(pemBlock.Bytes)
}
func pemDecodeTox509CSR(pem []byte) (*x509.CertificateRequest, error) { func pemDecodeTox509CSR(pem []byte) (*x509.CertificateRequest, error) {
pemBlock, err := pemDecode(pem) pemBlock, err := pemDecode(pem)
if pemBlock == nil { if pemBlock == nil {

View file

@ -25,14 +25,19 @@ func TestDNSValidServerResponse(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Replay-Nonce", "12345") w.Header().Add("Replay-Nonce", "12345")
w.Write([]byte("{\"type\":\"dns01\",\"status\":\"valid\",\"uri\":\"http://some.url\",\"token\":\"http8\"}"))
_, err = w.Write([]byte("{\"type\":\"dns01\",\"status\":\"valid\",\"uri\":\"http://some.url\",\"token\":\"http8\"}"))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
})) }))
go func() { go func() {
time.Sleep(time.Second * 2) time.Sleep(time.Second * 2)
f := bufio.NewWriter(os.Stdout) f := bufio.NewWriter(os.Stdout)
defer f.Flush() defer f.Flush()
f.WriteString("\n") _, _ = f.WriteString("\n")
}() }()
manualProvider, err := NewDNSProviderManual() manualProvider, err := NewDNSProviderManual()

View file

@ -148,29 +148,25 @@ func getJSON(uri string, respBody interface{}) (http.Header, error) {
func postJSON(j *jws, uri string, reqBody, respBody interface{}) (http.Header, error) { func postJSON(j *jws, uri string, reqBody, respBody interface{}) (http.Header, error) {
jsonBytes, err := json.Marshal(reqBody) jsonBytes, err := json.Marshal(reqBody)
if err != nil { if err != nil {
return nil, errors.New("Failed to marshal network message") return nil, errors.New("failed to marshal network message")
} }
resp, err := j.post(uri, jsonBytes) resp, err := j.post(uri, jsonBytes)
if err != nil { if err != nil {
return nil, fmt.Errorf("Failed to post JWS message. -> %v", err) return nil, fmt.Errorf("failed to post JWS message. -> %v", err)
} }
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode >= http.StatusBadRequest { if resp.StatusCode >= http.StatusBadRequest {
err = handleHTTPError(resp)
err := handleHTTPError(resp)
switch err.(type) { switch err.(type) {
case NonceError: case NonceError:
// Retry once if the nonce was invalidated // Retry once if the nonce was invalidated
retryResp, err := j.post(uri, jsonBytes) retryResp, errP := j.post(uri, jsonBytes)
if err != nil { if errP != nil {
return nil, fmt.Errorf("Failed to post JWS message. -> %v", err) return nil, fmt.Errorf("failed to post JWS message. -> %v", errP)
} }
defer retryResp.Body.Close() defer retryResp.Body.Close()

View file

@ -35,7 +35,7 @@ func (s *HTTPProviderServer) Present(domain, token, keyAuth string) error {
var err error var err error
s.listener, err = net.Listen("tcp", net.JoinHostPort(s.iface, s.port)) s.listener, err = net.Listen("tcp", net.JoinHostPort(s.iface, s.port))
if err != nil { if err != nil {
return fmt.Errorf("Could not start HTTP server for challenge -> %v", err) return fmt.Errorf("could not start HTTP server for challenge -> %v", err)
} }
s.done = make(chan bool) s.done = make(chan bool)
@ -62,20 +62,31 @@ func (s *HTTPProviderServer) serve(domain, token, keyAuth string) {
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.Host, domain) && r.Method == http.MethodGet { if strings.HasPrefix(r.Host, domain) && r.Method == http.MethodGet {
w.Header().Add("Content-Type", "text/plain") w.Header().Add("Content-Type", "text/plain")
w.Write([]byte(keyAuth)) _, err := w.Write([]byte(keyAuth))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
log.Infof("[%s] Served key authentication", domain) log.Infof("[%s] Served key authentication", domain)
} else { } else {
log.Warnf("Received request for domain %s with method %s but the domain did not match any challenge. Please ensure your are passing the HOST header properly.", r.Host, r.Method) log.Warnf("Received request for domain %s with method %s but the domain did not match any challenge. Please ensure your are passing the HOST header properly.", r.Host, r.Method)
w.Write([]byte("TEST")) _, err := w.Write([]byte("TEST"))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
} }
}) })
httpServer := &http.Server{ httpServer := &http.Server{Handler: mux}
Handler: mux,
}
// Once httpServer is shut down we don't want any lingering // Once httpServer is shut down we don't want any lingering
// connections, so disable KeepAlives. // connections, so disable KeepAlives.
httpServer.SetKeepAlivesEnabled(false) httpServer.SetKeepAlivesEnabled(false)
httpServer.Serve(s.listener)
err := httpServer.Serve(s.listener)
if err != nil {
log.Println(err)
}
s.done <- true s.done <- true
} }

View file

@ -3,6 +3,7 @@ package acme
import ( import (
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"log"
"net" "net"
"net/http" "net/http"
) )
@ -65,7 +66,10 @@ func (t *TLSALPNProviderServer) Present(domain, token, keyAuth string) error {
// Shut the server down when we're finished. // Shut the server down when we're finished.
go func() { go func() {
http.Serve(t.listener, nil) err := http.Serve(t.listener, nil)
if err != nil {
log.Println(err)
}
}() }()
return nil return nil

View file

@ -3,16 +3,20 @@ package acme
import ( import (
"fmt" "fmt"
"time" "time"
"github.com/xenolf/lego/log"
) )
// WaitFor polls the given function 'f', once every 'interval', up to 'timeout'. // WaitFor polls the given function 'f', once every 'interval', up to 'timeout'.
func WaitFor(timeout, interval time.Duration, f func() (bool, error)) error { func WaitFor(timeout, interval time.Duration, f func() (bool, error)) error {
log.Infof("Wait [timeout: %s, interval: %s]", timeout, interval)
var lastErr string var lastErr string
timeup := time.After(timeout) timeup := time.After(timeout)
for { for {
select { select {
case <-timeup: case <-timeup:
return fmt.Errorf("Time limit exceeded. Last error: %s", lastErr) return fmt.Errorf("time limit exceeded: last error: %s", lastErr)
default: default:
} }

2
cli.go
View file

@ -177,7 +177,7 @@ func main() {
}, },
cli.BoolFlag{ cli.BoolFlag{
Name: "pem", Name: "pem",
Usage: "Generate a .pem file by concatanating the .key and .crt files together.", Usage: "Generate a .pem file by concatenating the .key and .crt files together.",
}, },
} }

View file

@ -30,7 +30,6 @@ func checkFolder(path string) error {
} }
func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) { func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) {
if c.GlobalIsSet("http-timeout") { if c.GlobalIsSet("http-timeout") {
acme.HTTPClient = http.Client{Timeout: time.Duration(c.GlobalInt("http-timeout")) * time.Second} acme.HTTPClient = http.Client{Timeout: time.Duration(c.GlobalInt("http-timeout")) * time.Second}
} }
@ -60,7 +59,7 @@ func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) {
log.Fatal("You have to pass an account (email address) to the program using --email or -m") log.Fatal("You have to pass an account (email address) to the program using --email or -m")
} }
//TODO: move to account struct? Currently MUST pass email. // TODO: move to account struct? Currently MUST pass email.
acc := NewAccount(c.GlobalString("email"), conf) acc := NewAccount(c.GlobalString("email"), conf)
keyType, err := conf.KeyType() keyType, err := conf.KeyType()
@ -80,35 +79,37 @@ func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) {
} }
if c.GlobalIsSet("webroot") { if c.GlobalIsSet("webroot") {
provider, err := webroot.NewHTTPProvider(c.GlobalString("webroot")) provider, errO := webroot.NewHTTPProvider(c.GlobalString("webroot"))
if err != nil { if errO != nil {
log.Fatal(err) log.Fatal(errO)
} }
err = client.SetChallengeProvider(acme.HTTP01, provider) errO = client.SetChallengeProvider(acme.HTTP01, provider)
if err != nil { if errO != nil {
log.Fatal(err) log.Fatal(errO)
} }
// --webroot=foo indicates that the user specifically want to do a HTTP challenge // --webroot=foo indicates that the user specifically want to do a HTTP challenge
// infer that the user also wants to exclude all other challenges // infer that the user also wants to exclude all other challenges
client.ExcludeChallenges([]acme.Challenge{acme.DNS01, acme.TLSALPN01}) client.ExcludeChallenges([]acme.Challenge{acme.DNS01, acme.TLSALPN01})
} }
if c.GlobalIsSet("memcached-host") { if c.GlobalIsSet("memcached-host") {
provider, err := memcached.NewMemcachedProvider(c.GlobalStringSlice("memcached-host")) provider, errO := memcached.NewMemcachedProvider(c.GlobalStringSlice("memcached-host"))
if err != nil { if errO != nil {
log.Fatal(err) log.Fatal(errO)
} }
err = client.SetChallengeProvider(acme.HTTP01, provider) errO = client.SetChallengeProvider(acme.HTTP01, provider)
if err != nil { if errO != nil {
log.Fatal(err) log.Fatal(errO)
} }
// --memcached-host=foo:11211 indicates that the user specifically want to do a HTTP challenge // --memcached-host=foo:11211 indicates that the user specifically want to do a HTTP challenge
// infer that the user also wants to exclude all other challenges // infer that the user also wants to exclude all other challenges
client.ExcludeChallenges([]acme.Challenge{acme.DNS01, acme.TLSALPN01}) client.ExcludeChallenges([]acme.Challenge{acme.DNS01, acme.TLSALPN01})
} }
if c.GlobalIsSet("http") { if c.GlobalIsSet("http") {
if !strings.Contains(c.GlobalString("http"), ":") { if !strings.Contains(c.GlobalString("http"), ":") {
log.Fatalf("The --http switch only accepts interface:port or :port for its argument.") log.Fatalf("The --http switch only accepts interface:port or :port for its argument.")
@ -124,18 +125,22 @@ func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) {
if !strings.Contains(c.GlobalString("tls"), ":") { if !strings.Contains(c.GlobalString("tls"), ":") {
log.Fatalf("The --tls switch only accepts interface:port or :port for its argument.") log.Fatalf("The --tls switch only accepts interface:port or :port for its argument.")
} }
client.SetTLSAddress(c.GlobalString("tls"))
}
if c.GlobalIsSet("dns") { err = client.SetTLSAddress(c.GlobalString("tls"))
provider, err := dns.NewDNSChallengeProviderByName(c.GlobalString("dns"))
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
}
err = client.SetChallengeProvider(acme.DNS01, provider) if c.GlobalIsSet("dns") {
if err != nil { provider, errO := dns.NewDNSChallengeProviderByName(c.GlobalString("dns"))
log.Fatal(err) if errO != nil {
log.Fatal(errO)
}
errO = client.SetChallengeProvider(acme.DNS01, provider)
if errO != nil {
log.Fatal(errO)
} }
// --dns=foo indicates that the user specifically want to do a DNS challenge // --dns=foo indicates that the user specifically want to do a DNS challenge
@ -311,7 +316,10 @@ func run(c *cli.Context) error {
} }
acc.Registration = reg acc.Registration = reg
acc.Save() err = acc.Save()
if err != nil {
log.Fatal(err)
}
log.Print("!!!! HEADS UP !!!!") log.Print("!!!! HEADS UP !!!!")
log.Printf(` log.Printf(`
@ -421,8 +429,8 @@ func renew(c *cli.Context) error {
} }
if c.IsSet("days") { if c.IsSet("days") {
expTime, err := acme.GetPEMCertExpiration(certBytes) expTime, errE := acme.GetPEMCertExpiration(certBytes)
if err != nil { if errE != nil {
log.Printf("Could not get Certification expiration for domain %s", domain) log.Printf("Could not get Certification expiration for domain %s", domain)
} }
@ -437,14 +445,14 @@ func renew(c *cli.Context) error {
} }
var certRes acme.CertificateResource var certRes acme.CertificateResource
if err := json.Unmarshal(metaBytes, &certRes); err != nil { if err = json.Unmarshal(metaBytes, &certRes); err != nil {
log.Fatalf("Error while marshalling the meta data for domain %s\n\t%v", domain, err) log.Fatalf("Error while marshaling the meta data for domain %s\n\t%v", domain, err)
} }
if c.Bool("reuse-key") { if c.Bool("reuse-key") {
keyBytes, err := ioutil.ReadFile(privPath) keyBytes, errR := ioutil.ReadFile(privPath)
if err != nil { if errR != nil {
log.Fatalf("Error while loading the private key for domain %s\n\t%v", domain, err) log.Fatalf("Error while loading the private key for domain %s\n\t%v", domain, errR)
} }
certRes.PrivateKey = keyBytes certRes.PrivateKey = keyBytes
} }

View file

@ -13,7 +13,6 @@ import (
) )
func generatePrivateKey(file string) (crypto.PrivateKey, error) { func generatePrivateKey(file string) (crypto.PrivateKey, error) {
privateKey, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader) privateKey, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
if err != nil { if err != nil {
return nil, err return nil, err
@ -30,9 +29,12 @@ func generatePrivateKey(file string) (crypto.PrivateKey, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer certOut.Close()
pem.Encode(certOut, &pemKey) err = pem.Encode(certOut, &pemKey)
certOut.Close() if err != nil {
return nil, err
}
return privateKey, nil return privateKey, nil
} }

View file

@ -101,7 +101,7 @@ func (e ErrCNAMERequired) Error() string {
e.Domain, e.Domain, e.FQDN, e.Target) e.Domain, e.Domain, e.FQDN, e.Target)
} }
// Present creates a TXT record to fulfil the DNS-01 challenge. If there is an // Present creates a TXT record to fulfill the DNS-01 challenge. If there is an
// existing account for the domain in the provider's storage then it will be // existing account for the domain in the provider's storage then it will be
// used to set the challenge response TXT record with the ACME-DNS server and // used to set the challenge response TXT record with the ACME-DNS server and
// issuance will continue. If there is not an account for the given domain // issuance will continue. If there is not an account for the given domain

View file

@ -105,7 +105,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
return d.config.PropagationTimeout, d.config.PollingInterval return d.config.PropagationTimeout, d.config.PollingInterval
} }
// Present creates a TXT record to fulfil the dns-01 challenge. // Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, _ := acme.DNS01Record(domain, keyAuth) fqdn, value, _ := acme.DNS01Record(domain, keyAuth)

View file

@ -4,7 +4,7 @@ import (
"os" "os"
"testing" "testing"
"time" "time"
// "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )

View file

@ -99,7 +99,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
return d.config.PropagationTimeout, d.config.PollingInterval return d.config.PropagationTimeout, d.config.PollingInterval
} }
// Present creates a TXT record to fulfil the dns-01 challenge // Present creates a TXT record to fulfill the dns-01 challenge
func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
ctx := context.Background() ctx := context.Background()
fqdn, value, _ := acme.DNS01Record(domain, keyAuth) fqdn, value, _ := acme.DNS01Record(domain, keyAuth)

View file

@ -353,7 +353,7 @@ func (d *DNSProvider) lookupViewID(viewName string) (uint, error) {
queryArgs := map[string]string{ queryArgs := map[string]string{
"parentId": strconv.FormatUint(uint64(confID), 10), "parentId": strconv.FormatUint(uint64(confID), 10),
"name": d.config.DNSView, "name": viewName,
"type": viewType, "type": viewType,
} }

View file

@ -47,7 +47,11 @@ func handlerMock(method string, response *APIResponse, data interface{}) http.Ha
return return
} }
rw.Write(content) _, err = rw.Write(content)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
}) })
} }

View file

@ -98,7 +98,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
return d.config.PropagationTimeout, d.config.PollingInterval return d.config.PropagationTimeout, d.config.PollingInterval
} }
// Present creates a TXT record to fulfil the dns-01 challenge // Present creates a TXT record to fulfill the dns-01 challenge
func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, _ := acme.DNS01Record(domain, keyAuth) fqdn, value, _ := acme.DNS01Record(domain, keyAuth)

View file

@ -42,7 +42,11 @@ func handlerMock(method string, response *apiResponse, data interface{}) http.Ha
return return
} }
rw.Write(content) _, err = rw.Write(content)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
}) })
} }

View file

@ -79,7 +79,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return &DNSProvider{client: client}, nil return &DNSProvider{client: client}, nil
} }
// Present creates a TXT record to fulfil the dns-01 challenge. // Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, _ := acme.DNS01Record(domain, keyAuth) fqdn, value, _ := acme.DNS01Record(domain, keyAuth)

View file

@ -82,7 +82,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return &DNSProvider{client: client}, nil return &DNSProvider{client: client}, nil
} }
// Present creates a TXT record to fulfil the dns-01 challenge. // Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, _ := acme.DNS01Record(domain, keyAuth) fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
@ -182,7 +182,7 @@ func (d *DNSProvider) findTxtRecords(domain, fqdn string) ([]dnsimple.ZoneRecord
result, err := d.client.Zones.ListRecords(accountID, zoneName, &dnsimple.ZoneRecordListOptions{Name: recordName, Type: "TXT", ListOptions: dnsimple.ListOptions{}}) result, err := d.client.Zones.ListRecords(accountID, zoneName, &dnsimple.ZoneRecordListOptions{Name: recordName, Type: "TXT", ListOptions: dnsimple.ListOptions{}})
if err != nil { if err != nil {
return []dnsimple.ZoneRecord{}, fmt.Errorf("API call has failed: %v", err) return nil, fmt.Errorf("API call has failed: %v", err)
} }
return result.Data, nil return result.Data, nil

View file

@ -84,7 +84,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return &DNSProvider{client: client}, nil return &DNSProvider{client: client}, nil
} }
// Present creates a TXT record to fulfil the dns-01 challenge. // Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, _ := acme.DNS01Record(domain, keyAuth) fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
zoneID, zoneName, err := d.getHostedZone(domain) zoneID, zoneName, err := d.getHostedZone(domain)

View file

@ -75,7 +75,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return &DNSProvider{config: config}, nil return &DNSProvider{config: config}, nil
} }
// Present creates a TXT record to fulfil the dns-01 challenge. // Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
_, txtRecord, _ := acme.DNS01Record(domain, keyAuth) _, txtRecord, _ := acme.DNS01Record(domain, keyAuth)
return updateTxtRecord(domain, d.config.Token, txtRecord, false) return updateTxtRecord(domain, d.config.Token, txtRecord, false)

View file

@ -6,6 +6,7 @@ import (
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
var ( var (
@ -32,7 +33,7 @@ func TestLiveDynPresent(t *testing.T) {
} }
provider, err := NewDNSProvider() provider, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
err = provider.Present(dynDomain, "", "123d==") err = provider.Present(dynDomain, "", "123d==")
assert.NoError(t, err) assert.NoError(t, err)

View file

@ -59,7 +59,7 @@ func NewDNSProviderProgram(program string) (*DNSProvider, error) {
return NewDNSProviderConfig(&Config{Program: program}) return NewDNSProviderConfig(&Config{Program: program})
} }
// Present creates a TXT record to fulfil the dns-01 challenge. // Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
var args []string var args []string
if d.config.Mode == "RAW" { if d.config.Mode == "RAW" {

View file

@ -93,7 +93,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return &DNSProvider{client: client, config: config}, nil return &DNSProvider{client: client, config: config}, nil
} }
// Present creates a TXT record to fulfil the dns-01 challenge. // Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, _ := acme.DNS01Record(domain, keyAuth) fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
zone, recordName, err := d.FindZoneAndRecordName(fqdn, domain) zone, recordName, err := d.FindZoneAndRecordName(fqdn, domain)

View file

@ -6,6 +6,7 @@ import (
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
var ( var (
@ -39,7 +40,7 @@ func TestNewDNSProviderValid(t *testing.T) {
config.APISecret = "123" config.APISecret = "123"
_, err := NewDNSProviderConfig(config) _, err := NewDNSProviderConfig(config)
assert.NoError(t, err) require.NoError(t, err)
} }
func TestNewDNSProviderValidEnv(t *testing.T) { func TestNewDNSProviderValidEnv(t *testing.T) {
@ -48,7 +49,7 @@ func TestNewDNSProviderValidEnv(t *testing.T) {
os.Setenv("EXOSCALE_API_SECRET", "123") os.Setenv("EXOSCALE_API_SECRET", "123")
_, err := NewDNSProvider() _, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
} }
func TestNewDNSProviderMissingCredErr(t *testing.T) { func TestNewDNSProviderMissingCredErr(t *testing.T) {
@ -60,32 +61,56 @@ func TestNewDNSProviderMissingCredErr(t *testing.T) {
assert.EqualError(t, err, "exoscale: some credentials information are missing: EXOSCALE_API_KEY,EXOSCALE_API_SECRET") assert.EqualError(t, err, "exoscale: some credentials information are missing: EXOSCALE_API_KEY,EXOSCALE_API_SECRET")
} }
func TestExtractRootRecordName(t *testing.T) { func TestDNSProvider_FindZoneAndRecordName(t *testing.T) {
config := NewDefaultConfig() config := NewDefaultConfig()
config.APIKey = "example@example.com" config.APIKey = "example@example.com"
config.APISecret = "123" config.APISecret = "123"
provider, err := NewDNSProviderConfig(config) provider, err := NewDNSProviderConfig(config)
assert.NoError(t, err) require.NoError(t, err)
zone, recordName, err := provider.FindZoneAndRecordName("_acme-challenge.bar.com.", "bar.com") type expected struct {
assert.NoError(t, err) zone string
assert.Equal(t, "bar.com", zone) recordName string
assert.Equal(t, "_acme-challenge", recordName) }
}
func TestExtractSubRecordName(t *testing.T) { testCases := []struct {
config := NewDefaultConfig() desc string
config.APIKey = "example@example.com" fqdn string
config.APISecret = "123" domain string
expected expected
}{
{
desc: "Extract root record name",
fqdn: "_acme-challenge.bar.com.",
domain: "bar.com",
expected: expected{
zone: "bar.com",
recordName: "_acme-challenge",
},
},
{
desc: "Extract sub record name",
fqdn: "_acme-challenge.foo.bar.com.",
domain: "foo.bar.com",
expected: expected{
zone: "bar.com",
recordName: "_acme-challenge.foo",
},
},
}
provider, err := NewDNSProviderConfig(config) for _, test := range testCases {
assert.NoError(t, err) test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
zone, recordName, err := provider.FindZoneAndRecordName("_acme-challenge.foo.bar.com.", "foo.bar.com") zone, recordName, err := provider.FindZoneAndRecordName(test.fqdn, test.domain)
assert.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "bar.com", zone) assert.Equal(t, test.expected.zone, zone)
assert.Equal(t, "_acme-challenge.foo", recordName) assert.Equal(t, test.expected.recordName, recordName)
})
}
} }
func TestLiveExoscalePresent(t *testing.T) { func TestLiveExoscalePresent(t *testing.T) {
@ -98,14 +123,14 @@ func TestLiveExoscalePresent(t *testing.T) {
config.APISecret = exoscaleAPISecret config.APISecret = exoscaleAPISecret
provider, err := NewDNSProviderConfig(config) provider, err := NewDNSProviderConfig(config)
assert.NoError(t, err) require.NoError(t, err)
err = provider.Present(exoscaleDomain, "", "123d==") err = provider.Present(exoscaleDomain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
// Present Twice to handle create / update // Present Twice to handle create / update
err = provider.Present(exoscaleDomain, "", "123d==") err = provider.Present(exoscaleDomain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }
func TestLiveExoscaleCleanUp(t *testing.T) { func TestLiveExoscaleCleanUp(t *testing.T) {
@ -120,8 +145,8 @@ func TestLiveExoscaleCleanUp(t *testing.T) {
config.APISecret = exoscaleAPISecret config.APISecret = exoscaleAPISecret
provider, err := NewDNSProviderConfig(config) provider, err := NewDNSProviderConfig(config)
assert.NoError(t, err) require.NoError(t, err)
err = provider.CleanUp(exoscaleDomain, "", "123d==") err = provider.CleanUp(exoscaleDomain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }

View file

@ -99,10 +99,10 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
} }
record := configdns.NewTxtRecord() record := configdns.NewTxtRecord()
record.SetField("name", recordName) _ = record.SetField("name", recordName)
record.SetField("ttl", d.config.TTL) _ = record.SetField("ttl", d.config.TTL)
record.SetField("target", value) _ = record.SetField("target", value)
record.SetField("active", true) _ = record.SetField("active", true)
existingRecord := d.findExistingRecord(zone, recordName) existingRecord := d.findExistingRecord(zone, recordName)
@ -110,8 +110,10 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
if reflect.DeepEqual(existingRecord.ToMap(), record.ToMap()) { if reflect.DeepEqual(existingRecord.ToMap(), record.ToMap()) {
return nil return nil
} }
zone.RemoveRecord(existingRecord) err = zone.RemoveRecord(existingRecord)
return d.createRecord(zone, record) if err != nil {
return fmt.Errorf("fastdns: %v", err)
}
} }
return d.createRecord(zone, record) return d.createRecord(zone, record)

View file

@ -6,6 +6,7 @@ import (
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
var ( var (
@ -50,7 +51,7 @@ func TestNewDNSProviderValid(t *testing.T) {
config.AccessToken = "someaccesstoken" config.AccessToken = "someaccesstoken"
_, err := NewDNSProviderConfig(config) _, err := NewDNSProviderConfig(config)
assert.NoError(t, err) require.NoError(t, err)
} }
func TestNewDNSProviderValidEnv(t *testing.T) { func TestNewDNSProviderValidEnv(t *testing.T) {
@ -61,7 +62,7 @@ func TestNewDNSProviderValidEnv(t *testing.T) {
os.Setenv("AKAMAI_ACCESS_TOKEN", "someaccesstoken") os.Setenv("AKAMAI_ACCESS_TOKEN", "someaccesstoken")
_, err := NewDNSProvider() _, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
} }
func TestNewDNSProviderMissingCredErr(t *testing.T) { func TestNewDNSProviderMissingCredErr(t *testing.T) {
@ -87,17 +88,17 @@ func TestLiveFastdnsPresent(t *testing.T) {
config.AccessToken = accessToken config.AccessToken = accessToken
provider, err := NewDNSProviderConfig(config) provider, err := NewDNSProviderConfig(config)
assert.NoError(t, err) require.NoError(t, err)
err = provider.Present(testDomain, "", "123d==") err = provider.Present(testDomain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
// Present Twice to handle create / update // Present Twice to handle create / update
err = provider.Present(testDomain, "", "123d==") err = provider.Present(testDomain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }
func TestExtractRootRecordName(t *testing.T) { func TestDNSProvider_findZoneAndRecordName(t *testing.T) {
config := NewDefaultConfig() config := NewDefaultConfig()
config.Host = "somehost" config.Host = "somehost"
config.ClientToken = "someclienttoken" config.ClientToken = "someclienttoken"
@ -105,28 +106,50 @@ func TestExtractRootRecordName(t *testing.T) {
config.AccessToken = "someaccesstoken" config.AccessToken = "someaccesstoken"
provider, err := NewDNSProviderConfig(config) provider, err := NewDNSProviderConfig(config)
assert.NoError(t, err) require.NoError(t, err)
zone, recordName, err := provider.findZoneAndRecordName("_acme-challenge.bar.com.", "bar.com") type expected struct {
assert.NoError(t, err) zone string
assert.Equal(t, "bar.com", zone) recordName string
assert.Equal(t, "_acme-challenge", recordName) }
}
func TestExtractSubRecordName(t *testing.T) { testCases := []struct {
config := NewDefaultConfig() desc string
config.Host = "somehost" fqdn string
config.ClientToken = "someclienttoken" domain string
config.ClientSecret = "someclientsecret" expected expected
config.AccessToken = "someaccesstoken" }{
{
desc: "Extract root record name",
fqdn: "_acme-challenge.bar.com.",
domain: "bar.com",
expected: expected{
zone: "bar.com",
recordName: "_acme-challenge",
},
},
{
desc: "Extract sub record name",
fqdn: "_acme-challenge.foo.bar.com.",
domain: "foo.bar.com",
expected: expected{
zone: "bar.com",
recordName: "_acme-challenge.foo",
},
},
}
provider, err := NewDNSProviderConfig(config) for _, test := range testCases {
assert.NoError(t, err) test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
zone, recordName, err := provider.findZoneAndRecordName("_acme-challenge.foo.bar.com.", "foo.bar.com") zone, recordName, err := provider.findZoneAndRecordName(test.fqdn, test.domain)
assert.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "bar.com", zone) assert.Equal(t, test.expected.zone, zone)
assert.Equal(t, "_acme-challenge.foo", recordName) assert.Equal(t, test.expected.recordName, recordName)
})
}
} }
func TestLiveFastdnsCleanUp(t *testing.T) { func TestLiveFastdnsCleanUp(t *testing.T) {
@ -143,8 +166,8 @@ func TestLiveFastdnsCleanUp(t *testing.T) {
config.AccessToken = accessToken config.AccessToken = accessToken
provider, err := NewDNSProviderConfig(config) provider, err := NewDNSProviderConfig(config)
assert.NoError(t, err) require.NoError(t, err)
err = provider.CleanUp(testDomain, "", "123d==") err = provider.CleanUp(testDomain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }

View file

@ -82,8 +82,6 @@ type responseBool struct {
Value bool `xml:"params>param>value>boolean"` Value bool `xml:"params>param>value>boolean"`
} }
// POSTing/Marshalling/Unmarshalling
type rpcError struct { type rpcError struct {
faultCode int faultCode int
faultString string faultString string

View file

@ -230,9 +230,9 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
} }
// rpcCall makes an XML-RPC call to Gandi's RPC endpoint by // rpcCall makes an XML-RPC call to Gandi's RPC endpoint by
// marshalling the data given in the call argument to XML and sending // marshaling the data given in the call argument to XML and sending
// that via HTTP Post to Gandi. The response is then unmarshalled into // that via HTTP Post to Gandi.
// the resp argument. // The response is then unmarshalled into the resp argument.
func (d *DNSProvider) rpcCall(call *methodCall, resp response) error { func (d *DNSProvider) rpcCall(call *methodCall, resp response) error {
// marshal // marshal
b, err := xml.MarshalIndent(call, "", " ") b, err := xml.MarshalIndent(call, "", " ")

View file

@ -24,15 +24,15 @@ func TestDNSProvider(t *testing.T) {
fakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "text/xml", r.Header.Get("Content-Type"), "invalid content type") require.Equal(t, "text/xml", r.Header.Get("Content-Type"), "invalid content type")
req, err := ioutil.ReadAll(r.Body) req, errS := ioutil.ReadAll(r.Body)
require.NoError(t, err) require.NoError(t, errS)
req = regexpDate.ReplaceAllLiteral(req, []byte(`[ACME Challenge 01 Jan 16 00:00 +0000]`)) req = regexpDate.ReplaceAllLiteral(req, []byte(`[ACME Challenge 01 Jan 16 00:00 +0000]`))
resp, ok := serverResponses[string(req)] resp, ok := serverResponses[string(req)]
require.True(t, ok, "Server response for request not found") require.True(t, ok, "Server response for request not found")
_, err = io.Copy(w, strings.NewReader(resp)) _, errS = io.Copy(w, strings.NewReader(resp))
require.NoError(t, err) require.NoError(t, errS)
})) }))
defer fakeServer.Close() defer fakeServer.Close()

View file

@ -24,16 +24,16 @@ func TestDNSProvider(t *testing.T) {
fakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "application/json", r.Header.Get("Content-Type"), "invalid content type") require.Equal(t, "application/json", r.Header.Get("Content-Type"), "invalid content type")
req, err := ioutil.ReadAll(r.Body) req, errS := ioutil.ReadAll(r.Body)
require.NoError(t, err) require.NoError(t, errS)
req = regexpToken.ReplaceAllLiteral(req, []byte(`"rrset_values":["TOKEN"]`)) req = regexpToken.ReplaceAllLiteral(req, []byte(`"rrset_values":["TOKEN"]`))
resp, ok := serverResponses[string(req)] resp, ok := serverResponses[string(req)]
require.True(t, ok, "Server response for request not found") require.True(t, ok, "Server response for request not found")
_, err = io.Copy(w, strings.NewReader(resp)) _, errS = io.Copy(w, strings.NewReader(resp))
require.NoError(t, err) require.NoError(t, errS)
})) }))
defer fakeServer.Close() defer fakeServer.Close()

View file

@ -122,7 +122,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return &DNSProvider{config: config, client: svc}, nil return &DNSProvider{config: config, client: svc}, nil
} }
// Present creates a TXT record to fulfil the dns-01 challenge. // Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, _ := acme.DNS01Record(domain, keyAuth) fqdn, value, _ := acme.DNS01Record(domain, keyAuth)

View file

@ -6,6 +6,7 @@ import (
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/net/context" "golang.org/x/net/context"
"golang.org/x/oauth2/google" "golang.org/x/oauth2/google"
"google.golang.org/api/dns/v1" "google.golang.org/api/dns/v1"
@ -39,7 +40,7 @@ func TestNewDNSProviderValid(t *testing.T) {
os.Setenv("GCE_PROJECT", "") os.Setenv("GCE_PROJECT", "")
_, err := NewDNSProviderCredentials("my-project") _, err := NewDNSProviderCredentials("my-project")
assert.NoError(t, err) require.NoError(t, err)
} }
func TestNewDNSProviderValidEnv(t *testing.T) { func TestNewDNSProviderValidEnv(t *testing.T) {
@ -51,7 +52,7 @@ func TestNewDNSProviderValidEnv(t *testing.T) {
os.Setenv("GCE_PROJECT", "my-project") os.Setenv("GCE_PROJECT", "my-project")
_, err := NewDNSProvider() _, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
} }
func TestNewDNSProviderMissingCredErr(t *testing.T) { func TestNewDNSProviderMissingCredErr(t *testing.T) {
@ -68,10 +69,10 @@ func TestLiveGoogleCloudPresent(t *testing.T) {
} }
provider, err := NewDNSProviderCredentials(gcloudProject) provider, err := NewDNSProviderCredentials(gcloudProject)
assert.NoError(t, err) require.NoError(t, err)
err = provider.Present(gcloudDomain, "", "123d==") err = provider.Present(gcloudDomain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }
func TestLiveGoogleCloudPresentMultiple(t *testing.T) { func TestLiveGoogleCloudPresentMultiple(t *testing.T) {
@ -80,13 +81,13 @@ func TestLiveGoogleCloudPresentMultiple(t *testing.T) {
} }
provider, err := NewDNSProviderCredentials(gcloudProject) provider, err := NewDNSProviderCredentials(gcloudProject)
assert.NoError(t, err) require.NoError(t, err)
// Check that we're able to create multiple entries // Check that we're able to create multiple entries
err = provider.Present(gcloudDomain, "1", "123d==") err = provider.Present(gcloudDomain, "1", "123d==")
assert.NoError(t, err) require.NoError(t, err)
err = provider.Present(gcloudDomain, "2", "123d==") err = provider.Present(gcloudDomain, "2", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }
func TestLiveGoogleCloudCleanUp(t *testing.T) { func TestLiveGoogleCloudCleanUp(t *testing.T) {
@ -97,8 +98,8 @@ func TestLiveGoogleCloudCleanUp(t *testing.T) {
time.Sleep(time.Second * 1) time.Sleep(time.Second * 1)
provider, err := NewDNSProviderCredentials(gcloudProject) provider, err := NewDNSProviderCredentials(gcloudProject)
assert.NoError(t, err) require.NoError(t, err)
err = provider.CleanUp(gcloudDomain, "", "123d==") err = provider.CleanUp(gcloudDomain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }

View file

@ -160,8 +160,6 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
return d.config.PropagationTimeout, d.config.PollingInterval return d.config.PropagationTimeout, d.config.PollingInterval
} }
// POSTing/Marshalling/Unmarshalling
func (d *DNSProvider) sendRequest(method string, resource string, payload interface{}) (*responseStruct, error) { func (d *DNSProvider) sendRequest(method string, resource string, payload interface{}) (*responseStruct, error) {
url := fmt.Sprintf("%s/%s", defaultBaseURL, resource) url := fmt.Sprintf("%s/%s", defaultBaseURL, resource)

View file

@ -5,6 +5,7 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
var ( var (
@ -41,10 +42,10 @@ func TestDNSProvider_Present(t *testing.T) {
} }
provider, err := NewDNSProvider() provider, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
err = provider.Present(glesysDomain, "", "123d==") err = provider.Present(glesysDomain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }
func TestDNSProvider_CleanUp(t *testing.T) { func TestDNSProvider_CleanUp(t *testing.T) {
@ -53,8 +54,8 @@ func TestDNSProvider_CleanUp(t *testing.T) {
} }
provider, err := NewDNSProvider() provider, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
err = provider.CleanUp(glesysDomain, "", "123d==") err = provider.CleanUp(glesysDomain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }

View file

@ -103,7 +103,7 @@ func (d *DNSProvider) extractRecordName(fqdn, domain string) string {
return name return name
} }
// Present creates a TXT record to fulfil the dns-01 challenge // Present creates a TXT record to fulfill the dns-01 challenge
func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, _ := acme.DNS01Record(domain, keyAuth) fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
domainZone, err := d.getZone(fqdn) domainZone, err := d.getZone(fqdn)

View file

@ -89,7 +89,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
return d.config.PropagationTimeout, d.config.PollingInterval return d.config.PropagationTimeout, d.config.PollingInterval
} }
// Present creates a TXT record to fulfil the dns-01 challenge // Present creates a TXT record to fulfill the dns-01 challenge
func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, _ := acme.DNS01Record(domain, keyAuth) fqdn, value, _ := acme.DNS01Record(domain, keyAuth)

View file

@ -108,7 +108,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, _ := acme.DNS01Record(domain, keyAuth) fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
err := d.newTxtRecord(domain, fqdn, `"`+value+`"`) err := d.newTxtRecord(fqdn, `"`+value+`"`)
if err != nil { if err != nil {
return fmt.Errorf("lightsail: %v", err) return fmt.Errorf("lightsail: %v", err)
} }
@ -141,7 +141,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
return d.config.PropagationTimeout, d.config.PollingInterval return d.config.PropagationTimeout, d.config.PollingInterval
} }
func (d *DNSProvider) newTxtRecord(domain string, fqdn string, value string) error { func (d *DNSProvider) newTxtRecord(fqdn string, value string) error {
params := &lightsail.CreateDomainEntryInput{ params := &lightsail.CreateDomainEntryInput{
DomainName: aws.String(d.config.DNSZone), DomainName: aws.String(d.config.DNSZone),
DomainEntry: &lightsail.DomainEntry{ DomainEntry: &lightsail.DomainEntry{

View file

@ -20,41 +20,42 @@ func TestLightsailTTL(t *testing.T) {
provider, err := NewDNSProvider() provider, err := NewDNSProvider()
require.NoError(t, err) require.NoError(t, err)
err = provider.Present(m["lightsailDomain"], "foo", "bar") lightsailDomain := m["lightsailDomain"]
err = provider.Present(lightsailDomain, "foo", "bar")
require.NoError(t, err) require.NoError(t, err)
// we need a separate Lightshail client here as the one in the DNS provider is // we need a separate Lightshail client here as the one in the DNS provider is
// unexported. // unexported.
fqdn := "_acme-challenge." + m["lightsailDomain"] fqdn := "_acme-challenge." + lightsailDomain
sess, err := session.NewSession() sess, err := session.NewSession()
require.NoError(t, err) require.NoError(t, err)
svc := lightsail.New(sess) svc := lightsail.New(sess)
if err != nil { require.NoError(t, err)
provider.CleanUp(m["lightsailDomain"], "foo", "bar")
t.Fatal(err) defer func() {
} errC := provider.CleanUp(lightsailDomain, "foo", "bar")
if errC != nil {
t.Log(errC)
}
}()
params := &lightsail.GetDomainInput{ params := &lightsail.GetDomainInput{
DomainName: aws.String(m["lightsailDomain"]), DomainName: aws.String(lightsailDomain),
} }
resp, err := svc.GetDomain(params) resp, err := svc.GetDomain(params)
if err != nil { require.NoError(t, err)
provider.CleanUp(m["lightsailDomain"], "foo", "bar")
t.Fatal(err)
}
entries := resp.Domain.DomainEntries entries := resp.Domain.DomainEntries
for _, entry := range entries { for _, entry := range entries {
if *entry.Type == "TXT" && *entry.Name == fqdn { if *entry.Type == "TXT" && *entry.Name == fqdn {
provider.CleanUp(m["lightsailDomain"], "foo", "bar")
return return
} }
} }
provider.CleanUp(m["lightsailDomain"], "foo", "bar") t.Fatalf("Could not find a TXT record for _acme-challenge.%s", lightsailDomain)
t.Fatalf("Could not find a TXT record for _acme-challenge.%s", m["lightsailDomain"])
} }
func testGetAndPreCheck() (map[string]string, error) { func testGetAndPreCheck() (map[string]string, error) {

View file

@ -27,7 +27,11 @@ func newMockServer(t *testing.T, responses map[string]MockResponse) *httptest.Se
w.Header().Set("Content-Type", "application/xml") w.Header().Set("Content-Type", "application/xml")
w.WriteHeader(resp.StatusCode) w.WriteHeader(resp.StatusCode)
w.Write([]byte(resp.Body)) _, err := w.Write([]byte(resp.Body))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
})) }))
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)

View file

@ -48,7 +48,7 @@ func newMockServer(t *testing.T, responses MockResponseMap) *httptest.Server {
action := r.URL.Query().Get("api_action") action := r.URL.Query().Get("api_action")
resp, ok := responses[action] resp, ok := responses[action]
if !ok { if !ok {
require.FailNowf(t, "Unsupported mock action: %s", action) require.FailNowf(t, "Unsupported mock action: %q", action)
} }
// Build the response that the server will return. // Build the response that the server will return.
@ -66,7 +66,11 @@ func newMockServer(t *testing.T, responses MockResponseMap) *httptest.Server {
// Send the response. // Send the response.
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
w.Write(rawResponse) _, err = w.Write(rawResponse)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
})) }))
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
@ -78,7 +82,7 @@ func TestNewDNSProviderWithEnv(t *testing.T) {
os.Setenv("LINODE_API_KEY", "testing") os.Setenv("LINODE_API_KEY", "testing")
_, err := NewDNSProvider() _, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
} }
func TestNewDNSProviderWithoutEnv(t *testing.T) { func TestNewDNSProviderWithoutEnv(t *testing.T) {
@ -89,15 +93,15 @@ func TestNewDNSProviderWithoutEnv(t *testing.T) {
assert.EqualError(t, err, "linode: some credentials information are missing: LINODE_API_KEY") assert.EqualError(t, err, "linode: some credentials information are missing: LINODE_API_KEY")
} }
func TestNewDNSProviderCredentialsWithKey(t *testing.T) { func TestNewDNSProviderWithKey(t *testing.T) {
config := NewDefaultConfig() config := NewDefaultConfig()
config.APIKey = "testing" config.APIKey = "testing"
_, err := NewDNSProviderConfig(config) _, err := NewDNSProviderConfig(config)
assert.NoError(t, err) require.NoError(t, err)
} }
func TestNewDNSProviderCredentialsWithoutKey(t *testing.T) { func TestNewDNSProviderWithoutKey(t *testing.T) {
config := NewDefaultConfig() config := NewDefaultConfig()
_, err := NewDNSProviderConfig(config) _, err := NewDNSProviderConfig(config)
@ -109,105 +113,94 @@ func TestDNSProvider_Present(t *testing.T) {
os.Setenv("LINODE_API_KEY", "testing") os.Setenv("LINODE_API_KEY", "testing")
p, err := NewDNSProvider() p, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
domain := "example.com" domain := "example.com"
keyAuth := "dGVzdGluZw==" keyAuth := "dGVzdGluZw=="
mockResponses := MockResponseMap{
"domain.list": MockResponse{ testCases := []struct {
Response: []dns.Domain{ desc string
{ mockResponses MockResponseMap
Domain: domain, expectedError string
DomainID: 1234, }{
{
desc: "success",
mockResponses: MockResponseMap{
"domain.list": MockResponse{
Response: []dns.Domain{
{
Domain: domain,
DomainID: 1234,
},
},
},
"domain.resource.create": MockResponse{
Response: dns.ResourceResponse{
ResourceID: 1234,
},
}, },
}, },
}, },
"domain.resource.create": MockResponse{ {
Response: dns.ResourceResponse{ desc: "NoDomain",
ResourceID: 1234, mockResponses: MockResponseMap{
"domain.list": MockResponse{
Response: []dns.Domain{{
Domain: "foobar.com",
DomainID: 1234,
}},
},
}, },
expectedError: "dns: requested domain not found",
},
{
desc: "CreateFailed",
mockResponses: MockResponseMap{
"domain.list": MockResponse{
Response: []dns.Domain{
{
Domain: domain,
DomainID: 1234,
},
},
},
"domain.resource.create": MockResponse{
Response: nil,
Errors: []linode.ResponseError{
{
Code: 1234,
Message: "Failed to create domain resource",
},
},
},
},
expectedError: "Failed to create domain resource",
}, },
} }
mockSrv := newMockServer(t, mockResponses) for _, test := range testCases {
defer mockSrv.Close() t.Run(test.desc, func(t *testing.T) {
p.client.ToLinode().SetEndpoint(mockSrv.URL) mockSrv := newMockServer(t, test.mockResponses)
defer mockSrv.Close()
err = p.Present(domain, "", keyAuth) p.client.ToLinode().SetEndpoint(mockSrv.URL)
assert.NoError(t, err)
}
func TestDNSProvider_PresentNoDomain(t *testing.T) { err = p.Present(domain, "", keyAuth)
defer restoreEnv() if len(test.expectedError) == 0 {
os.Setenv("LINODE_API_KEY", "testing") assert.NoError(t, err)
} else {
p, err := NewDNSProvider() assert.EqualError(t, err, test.expectedError)
assert.NoError(t, err) }
})
domain := "example.com"
keyAuth := "dGVzdGluZw=="
mockResponses := MockResponseMap{
"domain.list": MockResponse{
Response: []dns.Domain{
{
Domain: "foobar.com",
DomainID: 1234,
},
},
},
} }
mockSrv := newMockServer(t, mockResponses)
defer mockSrv.Close()
p.client.ToLinode().SetEndpoint(mockSrv.URL)
err = p.Present(domain, "", keyAuth)
assert.EqualError(t, err, "dns: requested domain not found")
}
func TestDNSProvider_PresentCreateFailed(t *testing.T) {
defer restoreEnv()
os.Setenv("LINODE_API_KEY", "testing")
p, err := NewDNSProvider()
assert.NoError(t, err)
domain := "example.com"
keyAuth := "dGVzdGluZw=="
mockResponses := MockResponseMap{
"domain.list": MockResponse{
Response: []dns.Domain{
{
Domain: domain,
DomainID: 1234,
},
},
},
"domain.resource.create": MockResponse{
Response: nil,
Errors: []linode.ResponseError{
{
Code: 1234,
Message: "Failed to create domain resource",
},
},
},
}
mockSrv := newMockServer(t, mockResponses)
defer mockSrv.Close()
p.client.ToLinode().SetEndpoint(mockSrv.URL)
err = p.Present(domain, "", keyAuth)
assert.EqualError(t, err, "Failed to create domain resource")
} }
func TestDNSProvider_PresentLive(t *testing.T) { func TestDNSProvider_PresentLive(t *testing.T) {
if !isTestLive { if !isTestLive {
t.Skip("Skipping live test") t.Skip("Skipping live test")
} }
// TODO implement this test
} }
func TestDNSProvider_CleanUp(t *testing.T) { func TestDNSProvider_CleanUp(t *testing.T) {
@ -215,120 +208,108 @@ func TestDNSProvider_CleanUp(t *testing.T) {
os.Setenv("LINODE_API_KEY", "testing") os.Setenv("LINODE_API_KEY", "testing")
p, err := NewDNSProvider() p, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
domain := "example.com" domain := "example.com"
keyAuth := "dGVzdGluZw==" keyAuth := "dGVzdGluZw=="
mockResponses := MockResponseMap{
"domain.list": MockResponse{ testCases := []struct {
Response: []dns.Domain{ desc string
{ mockResponses MockResponseMap
Domain: domain, expectedError string
DomainID: 1234, }{
{
desc: "success",
mockResponses: MockResponseMap{
"domain.list": MockResponse{
Response: []dns.Domain{
{
Domain: domain,
DomainID: 1234,
},
},
},
"domain.resource.list": MockResponse{
Response: []dns.Resource{
{
DomainID: 1234,
Name: "_acme-challenge",
ResourceID: 1234,
Target: "ElbOJKOkFWiZLQeoxf-wb3IpOsQCdvoM0y_wn0TEkxM",
Type: "TXT",
},
},
},
"domain.resource.delete": MockResponse{
Response: dns.ResourceResponse{
ResourceID: 1234,
},
}, },
}, },
}, },
"domain.resource.list": MockResponse{ {
Response: []dns.Resource{ desc: "NoDomain",
{ mockResponses: MockResponseMap{
DomainID: 1234, "domain.list": MockResponse{
Name: "_acme-challenge", Response: []dns.Domain{
ResourceID: 1234, {
Target: "ElbOJKOkFWiZLQeoxf-wb3IpOsQCdvoM0y_wn0TEkxM", Domain: "foobar.com",
Type: "TXT", DomainID: 1234,
},
},
}, },
}, },
expectedError: "dns: requested domain not found",
}, },
"domain.resource.delete": MockResponse{ {
Response: dns.ResourceResponse{ desc: "DeleteFailed",
ResourceID: 1234, mockResponses: MockResponseMap{
"domain.list": MockResponse{
Response: []dns.Domain{
{
Domain: domain,
DomainID: 1234,
},
},
},
"domain.resource.list": MockResponse{
Response: []dns.Resource{
{
DomainID: 1234,
Name: "_acme-challenge",
ResourceID: 1234,
Target: "ElbOJKOkFWiZLQeoxf-wb3IpOsQCdvoM0y_wn0TEkxM",
Type: "TXT",
},
},
},
"domain.resource.delete": MockResponse{
Response: nil,
Errors: []linode.ResponseError{
{
Code: 1234,
Message: "Failed to delete domain resource",
},
},
},
}, },
expectedError: "Failed to delete domain resource",
}, },
} }
mockSrv := newMockServer(t, mockResponses) for _, test := range testCases {
defer mockSrv.Close() t.Run(test.desc, func(t *testing.T) {
mockSrv := newMockServer(t, test.mockResponses)
defer mockSrv.Close()
p.client.ToLinode().SetEndpoint(mockSrv.URL) p.client.ToLinode().SetEndpoint(mockSrv.URL)
err = p.CleanUp(domain, "", keyAuth) err = p.CleanUp(domain, "", keyAuth)
assert.NoError(t, err) if len(test.expectedError) == 0 {
} assert.NoError(t, err)
} else {
func TestDNSProvider_CleanUpNoDomain(t *testing.T) { assert.EqualError(t, err, test.expectedError)
defer restoreEnv() }
os.Setenv("LINODE_API_KEY", "testing") })
p, err := NewDNSProvider()
assert.NoError(t, err)
domain := "example.com"
keyAuth := "dGVzdGluZw=="
mockResponses := MockResponseMap{
"domain.list": MockResponse{
Response: []dns.Domain{
{
Domain: "foobar.com",
DomainID: 1234,
},
},
},
} }
mockSrv := newMockServer(t, mockResponses)
defer mockSrv.Close()
p.client.ToLinode().SetEndpoint(mockSrv.URL)
err = p.CleanUp(domain, "", keyAuth)
assert.EqualError(t, err, "dns: requested domain not found")
}
func TestDNSProvider_CleanUpDeleteFailed(t *testing.T) {
defer restoreEnv()
os.Setenv("LINODE_API_KEY", "testing")
p, err := NewDNSProvider()
assert.NoError(t, err)
domain := "example.com"
keyAuth := "dGVzdGluZw=="
mockResponses := MockResponseMap{
"domain.list": MockResponse{
Response: []dns.Domain{
{
Domain: domain,
DomainID: 1234,
},
},
},
"domain.resource.list": MockResponse{
Response: []dns.Resource{
{
DomainID: 1234,
Name: "_acme-challenge",
ResourceID: 1234,
Target: "ElbOJKOkFWiZLQeoxf-wb3IpOsQCdvoM0y_wn0TEkxM",
Type: "TXT",
},
},
},
"domain.resource.delete": MockResponse{
Response: nil,
Errors: []linode.ResponseError{
{
Code: 1234,
Message: "Failed to delete domain resource",
},
},
},
}
mockSrv := newMockServer(t, mockResponses)
defer mockSrv.Close()
p.client.ToLinode().SetEndpoint(mockSrv.URL)
err = p.CleanUp(domain, "", keyAuth)
assert.EqualError(t, err, "Failed to delete domain resource")
} }

View file

@ -83,12 +83,12 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
}, },
} }
linodeClient := linodego.NewClient(oauth2Client) client := linodego.NewClient(oauth2Client)
linodeClient.SetUserAgent(fmt.Sprintf("lego-dns linodego/%s", linodego.Version)) client.SetUserAgent(fmt.Sprintf("lego-dns linodego/%s", linodego.Version))
return &DNSProvider{ return &DNSProvider{
config: config, config: config,
client: &linodeClient, client: &client,
}, nil }, nil
} }

View file

@ -58,7 +58,11 @@ func newMockServer(t *testing.T, responses MockResponseMap) *httptest.Server {
} else { } else {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
w.Write(rawResponse)
_, err = w.Write(rawResponse)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})) }))
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
@ -81,7 +85,7 @@ func TestNewDNSProviderWithoutEnv(t *testing.T) {
assert.EqualError(t, err, "linodev4: some credentials information are missing: LINODE_TOKEN") assert.EqualError(t, err, "linodev4: some credentials information are missing: LINODE_TOKEN")
} }
func TestNewDNSProviderCredentialsWithKey(t *testing.T) { func TestNewDNSProviderWithKey(t *testing.T) {
config := NewDefaultConfig() config := NewDefaultConfig()
config.Token = "testing" config.Token = "testing"
@ -89,7 +93,7 @@ func TestNewDNSProviderCredentialsWithKey(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
} }
func TestNewDNSProviderCredentialsWithoutKey(t *testing.T) { func TestNewDNSProviderWithoutKey(t *testing.T) {
config := NewDefaultConfig() config := NewDefaultConfig()
config.Token = "" config.Token = ""
@ -102,104 +106,96 @@ func TestDNSProvider_Present(t *testing.T) {
os.Setenv("LINODE_TOKEN", "testing") os.Setenv("LINODE_TOKEN", "testing")
p, err := NewDNSProvider() p, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
require.NotNil(t, p)
domain := "example.com" domain := "example.com"
keyAuth := "dGVzdGluZw==" keyAuth := "dGVzdGluZw=="
mockResponses := MockResponseMap{ testCases := []struct {
"GET:/domains": linodego.DomainsPagedResponse{ desc string
PageOptions: &linodego.PageOptions{ mockResponses MockResponseMap
Pages: 1, expectedError string
Results: 1, }{
Page: 1, {
desc: "Success",
mockResponses: MockResponseMap{
"GET:/domains": linodego.DomainsPagedResponse{
PageOptions: &linodego.PageOptions{
Pages: 1,
Results: 1,
Page: 1,
},
Data: []linodego.Domain{{
Domain: domain,
ID: 1234,
}},
},
"POST:/domains/1234/records": linodego.DomainRecord{
ID: 1234,
},
}, },
Data: []linodego.Domain{{
Domain: domain,
ID: 1234,
}},
}, },
"POST:/domains/1234/records": linodego.DomainRecord{ {
ID: 1234, desc: "NoDomain",
}, mockResponses: MockResponseMap{
} "GET:/domains": linodego.APIError{
Errors: []linodego.APIErrorReason{{
mockSrv := newMockServer(t, mockResponses) Reason: "Not found",
defer mockSrv.Close() }},
},
p.client.SetBaseURL(mockSrv.URL)
err = p.Present(domain, "", keyAuth)
assert.NoError(t, err)
}
func TestDNSProvider_PresentNoDomain(t *testing.T) {
defer restoreEnv()
os.Setenv("LINODE_TOKEN", "testing")
p, err := NewDNSProvider()
assert.NoError(t, err)
domain := "example.com"
keyAuth := "dGVzdGluZw=="
mockResponses := MockResponseMap{
"GET:/domains": linodego.APIError{
Errors: []linodego.APIErrorReason{{
Reason: "Not found",
}},
},
}
mockSrv := newMockServer(t, mockResponses)
defer mockSrv.Close()
p.client.SetBaseURL(mockSrv.URL)
err = p.Present(domain, "", keyAuth)
assert.EqualError(t, err, "[404] Not found")
}
func TestDNSProvider_PresentCreateFailed(t *testing.T) {
defer restoreEnv()
os.Setenv("LINODE_TOKEN", "testing")
p, err := NewDNSProvider()
assert.NoError(t, err)
domain := "example.com"
keyAuth := "dGVzdGluZw=="
mockResponses := MockResponseMap{
"GET:/domains": &linodego.DomainsPagedResponse{
PageOptions: &linodego.PageOptions{
Pages: 1,
Results: 1,
Page: 1,
}, },
Data: []linodego.Domain{{ expectedError: "[404] Not found",
Domain: "foobar.com",
ID: 1234,
}},
}, },
"POST:/domains/1234/records": linodego.APIError{ {
Errors: []linodego.APIErrorReason{{ desc: "CreateFailed",
Reason: "Failed to create domain resource", mockResponses: MockResponseMap{
Field: "somefield", "GET:/domains": &linodego.DomainsPagedResponse{
}}, PageOptions: &linodego.PageOptions{
Pages: 1,
Results: 1,
Page: 1,
},
Data: []linodego.Domain{{
Domain: "foobar.com",
ID: 1234,
}},
},
"POST:/domains/1234/records": linodego.APIError{
Errors: []linodego.APIErrorReason{{
Reason: "Failed to create domain resource",
Field: "somefield",
}},
},
},
expectedError: "[400] [somefield] Failed to create domain resource",
}, },
} }
mockSrv := newMockServer(t, mockResponses)
defer mockSrv.Close()
p.client.SetBaseURL(mockSrv.URL) for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
err = p.Present(domain, "", keyAuth) mockSrv := newMockServer(t, test.mockResponses)
assert.EqualError(t, err, "[400] [somefield] Failed to create domain resource") defer mockSrv.Close()
assert.NotNil(t, p.client)
p.client.SetBaseURL(mockSrv.URL)
err = p.Present(domain, "", keyAuth)
if len(test.expectedError) == 0 {
assert.NoError(t, err)
} else {
assert.EqualError(t, err, test.expectedError)
}
})
}
} }
func TestDNSProvider_PresentLive(t *testing.T) { func TestDNSProvider_PresentLive(t *testing.T) {
if !isTestLive { if !isTestLive {
t.Skip("Skipping live test") t.Skip("Skipping live test")
} }
// TODO implement this test
} }
func TestDNSProvider_CleanUp(t *testing.T) { func TestDNSProvider_CleanUp(t *testing.T) {
@ -207,124 +203,112 @@ func TestDNSProvider_CleanUp(t *testing.T) {
os.Setenv("LINODE_TOKEN", "testing") os.Setenv("LINODE_TOKEN", "testing")
p, err := NewDNSProvider() p, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
domain := "example.com" domain := "example.com"
keyAuth := "dGVzdGluZw==" keyAuth := "dGVzdGluZw=="
mockResponses := MockResponseMap{
"GET:/domains": &linodego.DomainsPagedResponse{ testCases := []struct {
PageOptions: &linodego.PageOptions{ desc string
Pages: 1, mockResponses MockResponseMap
Results: 1, expectedError string
Page: 1, }{
{
desc: "Success",
mockResponses: MockResponseMap{
"GET:/domains": &linodego.DomainsPagedResponse{
PageOptions: &linodego.PageOptions{
Pages: 1,
Results: 1,
Page: 1,
},
Data: []linodego.Domain{{
Domain: "foobar.com",
ID: 1234,
}},
},
"GET:/domains/1234/records": &linodego.DomainRecordsPagedResponse{
PageOptions: &linodego.PageOptions{
Pages: 1,
Results: 1,
Page: 1,
},
Data: []linodego.DomainRecord{{
ID: 1234,
Name: "_acme-challenge",
Target: "ElbOJKOkFWiZLQeoxf-wb3IpOsQCdvoM0y_wn0TEkxM",
Type: "TXT",
}},
},
"DELETE:/domains/1234/records/1234": struct{}{},
}, },
Data: []linodego.Domain{{
Domain: "foobar.com",
ID: 1234,
}},
}, },
"GET:/domains/1234/records": &linodego.DomainRecordsPagedResponse{ {
PageOptions: &linodego.PageOptions{ desc: "NoDomain",
Pages: 1, mockResponses: MockResponseMap{
Results: 1, "GET:/domains": linodego.APIError{
Page: 1, Errors: []linodego.APIErrorReason{{
Reason: "Not found",
}},
},
"GET:/domains/1234/records": linodego.APIError{
Errors: []linodego.APIErrorReason{{
Reason: "Not found",
}},
},
}, },
Data: []linodego.DomainRecord{{ expectedError: "[404] Not found",
ID: 1234,
Name: "_acme-challenge",
Target: "ElbOJKOkFWiZLQeoxf-wb3IpOsQCdvoM0y_wn0TEkxM",
Type: "TXT",
}},
}, },
"DELETE:/domains/1234/records/1234": struct{}{}, {
} desc: "DeleteFailed",
mockResponses: MockResponseMap{
mockSrv := newMockServer(t, mockResponses) "GET:/domains": linodego.DomainsPagedResponse{
defer mockSrv.Close() PageOptions: &linodego.PageOptions{
Pages: 1,
p.client.SetBaseURL(mockSrv.URL) Results: 1,
Page: 1,
err = p.CleanUp(domain, "", keyAuth) },
assert.NoError(t, err) Data: []linodego.Domain{{
} ID: 1234,
Domain: "example.com",
func TestDNSProvider_CleanUpNoDomain(t *testing.T) { }},
defer restoreEnv() },
os.Setenv("LINODE_TOKEN", "testing") "GET:/domains/1234/records": linodego.DomainRecordsPagedResponse{
PageOptions: &linodego.PageOptions{
p, err := NewDNSProvider() Pages: 1,
assert.NoError(t, err) Results: 1,
Page: 1,
domain := "example.com" },
keyAuth := "dGVzdGluZw==" Data: []linodego.DomainRecord{{
mockResponses := MockResponseMap{ ID: 1234,
"GET:/domains": linodego.APIError{ Name: "_acme-challenge",
Errors: []linodego.APIErrorReason{{ Target: "ElbOJKOkFWiZLQeoxf-wb3IpOsQCdvoM0y_wn0TEkxM",
Reason: "Not found", Type: "TXT",
}}, }},
}, },
"GET:/domains/1234/records": linodego.APIError{ "DELETE:/domains/1234/records/1234": linodego.APIError{
Errors: []linodego.APIErrorReason{{ Errors: []linodego.APIErrorReason{{
Reason: "Not found", Reason: "Failed to delete domain resource",
}}, }},
},
},
expectedError: "[400] Failed to delete domain resource",
}, },
} }
mockSrv := newMockServer(t, mockResponses) for _, test := range testCases {
defer mockSrv.Close() t.Run(test.desc, func(t *testing.T) {
mockSrv := newMockServer(t, test.mockResponses)
defer mockSrv.Close()
p.client.SetBaseURL(mockSrv.URL) p.client.SetBaseURL(mockSrv.URL)
err = p.CleanUp(domain, "", keyAuth) err = p.CleanUp(domain, "", keyAuth)
assert.EqualError(t, err, "[404] Not found") if len(test.expectedError) == 0 {
} assert.NoError(t, err)
} else {
func TestDNSProvider_CleanUpDeleteFailed(t *testing.T) { assert.EqualError(t, err, test.expectedError)
defer restoreEnv() }
os.Setenv("LINODE_TOKEN", "testing") })
p, err := NewDNSProvider()
assert.NoError(t, err)
domain := "example.com"
keyAuth := "dGVzdGluZw=="
mockResponses := MockResponseMap{
"GET:/domains": linodego.DomainsPagedResponse{
PageOptions: &linodego.PageOptions{
Pages: 1,
Results: 1,
Page: 1,
},
Data: []linodego.Domain{{
ID: 1234,
Domain: "example.com",
}},
},
"GET:/domains/1234/records": linodego.DomainRecordsPagedResponse{
PageOptions: &linodego.PageOptions{
Pages: 1,
Results: 1,
Page: 1,
},
Data: []linodego.DomainRecord{{
ID: 1234,
Name: "_acme-challenge",
Target: "ElbOJKOkFWiZLQeoxf-wb3IpOsQCdvoM0y_wn0TEkxM",
Type: "TXT",
}},
},
"DELETE:/domains/1234/records/1234": linodego.APIError{
Errors: []linodego.APIErrorReason{{
Reason: "Failed to delete domain resource",
}},
},
} }
mockSrv := newMockServer(t, mockResponses)
defer mockSrv.Close()
p.client.SetBaseURL(mockSrv.URL)
err = p.CleanUp(domain, "", keyAuth)
assert.EqualError(t, err, "[400] Failed to delete domain resource")
} }

View file

@ -2,10 +2,10 @@ package namecheap
import "encoding/xml" import "encoding/xml"
// host describes a DNS record returned by the Namecheap DNS gethosts API. // record describes a DNS record returned by the Namecheap DNS gethosts API.
// Namecheap uses the term "host" to refer to all DNS records that include // Namecheap uses the term "host" to refer to all DNS records that include
// a host field (A, AAAA, CNAME, NS, TXT, URL). // a host field (A, AAAA, CNAME, NS, TXT, URL).
type host struct { type record struct {
Type string `xml:",attr"` Type string `xml:",attr"`
Name string `xml:",attr"` Name string `xml:",attr"`
Address string `xml:",attr"` Address string `xml:",attr"`
@ -32,7 +32,7 @@ type getHostsResponse struct {
XMLName xml.Name `xml:"ApiResponse"` XMLName xml.Name `xml:"ApiResponse"`
Status string `xml:"Status,attr"` Status string `xml:"Status,attr"`
Errors []apierror `xml:"Errors>Error"` Errors []apierror `xml:"Errors>Error"`
Hosts []host `xml:"CommandResponse>DomainDNSGetHostsResult>host"` Hosts []record `xml:"CommandResponse>DomainDNSGetHostsResult>host"`
} }
type getTldsResponse struct { type getTldsResponse struct {

View file

@ -308,7 +308,7 @@ func (d *DNSProvider) getTLDs() (tlds map[string]string, err error) {
} }
// getHosts reads the full list of DNS host records using the Namecheap API. // getHosts reads the full list of DNS host records using the Namecheap API.
func (d *DNSProvider) getHosts(ch *challenge) (hosts []host, err error) { func (d *DNSProvider) getHosts(ch *challenge) (hosts []record, err error) {
values := make(url.Values) values := make(url.Values)
d.setGlobalParams(&values, "namecheap.domains.dns.getHosts") d.setGlobalParams(&values, "namecheap.domains.dns.getHosts")
@ -348,7 +348,7 @@ func (d *DNSProvider) getHosts(ch *challenge) (hosts []host, err error) {
} }
// setHosts writes the full list of DNS host records using the Namecheap API. // setHosts writes the full list of DNS host records using the Namecheap API.
func (d *DNSProvider) setHosts(ch *challenge, hosts []host) error { func (d *DNSProvider) setHosts(ch *challenge, hosts []record) error {
values := make(url.Values) values := make(url.Values)
d.setGlobalParams(&values, "namecheap.domains.dns.setHosts") d.setGlobalParams(&values, "namecheap.domains.dns.setHosts")
@ -395,8 +395,8 @@ func (d *DNSProvider) setHosts(ch *challenge, hosts []host) error {
// addChallengeRecord adds a DNS challenge TXT record to a list of namecheap // addChallengeRecord adds a DNS challenge TXT record to a list of namecheap
// host records. // host records.
func (d *DNSProvider) addChallengeRecord(ch *challenge, hosts *[]host) { func (d *DNSProvider) addChallengeRecord(ch *challenge, hosts *[]record) {
host := host{ host := record{
Name: ch.key, Name: ch.key,
Type: "TXT", Type: "TXT",
Address: ch.keyValue, Address: ch.keyValue,
@ -418,7 +418,7 @@ func (d *DNSProvider) addChallengeRecord(ch *challenge, hosts *[]host) {
// removeChallengeRecord removes a DNS challenge TXT record from a list of // removeChallengeRecord removes a DNS challenge TXT record from a list of
// namecheap host records. Return true if a record was removed. // namecheap host records. Return true if a record was removed.
func (d *DNSProvider) removeChallengeRecord(ch *challenge, hosts *[]host) bool { func (d *DNSProvider) removeChallengeRecord(ch *challenge, hosts *[]record) bool {
// Find the challenge TXT record and remove it if found. // Find the challenge TXT record and remove it if found.
for i, h := range *hosts { for i, h := range *hosts {
if h.Name == ch.key && h.Type == "TXT" { if h.Name == ch.key && h.Type == "TXT" {

View file

@ -93,14 +93,14 @@ func TestSetHosts(t *testing.T) {
if test.errString != "" { if test.errString != "" {
assert.EqualError(t, err, test.errString) assert.EqualError(t, err, test.errString)
} else { } else {
assert.NoError(t, err) require.NoError(t, err)
} }
if err != nil { if err != nil {
return return
} }
err = prov.setHosts(ch, hosts) err = prov.setHosts(ch, hosts)
assert.NoError(t, err) require.NoError(t, err)
}) })
} }
} }
@ -232,7 +232,11 @@ func mockServer(tc *testcase, t *testing.T, w http.ResponseWriter, r *http.Reque
} }
case http.MethodPost: case http.MethodPost:
r.ParseForm() err := r.ParseForm()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
values := r.Form values := r.Form
cmd := values.Get("Command") cmd := values.Get("Command")
switch cmd { switch cmd {
@ -246,7 +250,6 @@ func mockServer(tc *testcase, t *testing.T, w http.ResponseWriter, r *http.Reque
default: default:
t.Errorf("Unexpected http method: %s", r.Method) t.Errorf("Unexpected http method: %s", r.Method)
} }
} }
@ -265,7 +268,7 @@ func mockDNSProvider(url string) *DNSProvider {
type testcase struct { type testcase struct {
name string name string
domain string domain string
hosts []host hosts []record
errString string errString string
getHostsResponse string getHostsResponse string
setHostsResponse string setHostsResponse string
@ -275,7 +278,7 @@ var testcases = []testcase{
{ {
name: "Test:Success:1", name: "Test:Success:1",
domain: "test.example.com", domain: "test.example.com",
hosts: []host{ hosts: []record{
{Type: "A", Name: "home", Address: "10.0.0.1", MXPref: "10", TTL: "1799"}, {Type: "A", Name: "home", Address: "10.0.0.1", MXPref: "10", TTL: "1799"},
{Type: "A", Name: "www", Address: "10.0.0.2", MXPref: "10", TTL: "1200"}, {Type: "A", Name: "www", Address: "10.0.0.2", MXPref: "10", TTL: "1200"},
{Type: "AAAA", Name: "a", Address: "::0", MXPref: "10", TTL: "1799"}, {Type: "AAAA", Name: "a", Address: "::0", MXPref: "10", TTL: "1799"},
@ -289,7 +292,7 @@ var testcases = []testcase{
{ {
name: "Test:Success:2", name: "Test:Success:2",
domain: "example.com", domain: "example.com",
hosts: []host{ hosts: []record{
{Type: "A", Name: "@", Address: "10.0.0.2", MXPref: "10", TTL: "1200"}, {Type: "A", Name: "@", Address: "10.0.0.2", MXPref: "10", TTL: "1200"},
{Type: "A", Name: "www", Address: "10.0.0.3", MXPref: "10", TTL: "60"}, {Type: "A", Name: "www", Address: "10.0.0.3", MXPref: "10", TTL: "60"},
}, },

View file

@ -97,7 +97,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return &DNSProvider{client: client, config: config}, nil return &DNSProvider{client: client, config: config}, nil
} }
// Present creates a TXT record to fulfil the dns-01 challenge. // Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, _ := acme.DNS01Record(domain, keyAuth) fqdn, value, _ := acme.DNS01Record(domain, keyAuth)

View file

@ -5,7 +5,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/require"
) )
var ( var (
@ -38,10 +38,10 @@ func TestLiveNamedotcomPresent(t *testing.T) {
config.Server = namedotcomServer config.Server = namedotcomServer
provider, err := NewDNSProviderConfig(config) provider, err := NewDNSProviderConfig(config)
assert.NoError(t, err) require.NoError(t, err)
err = provider.Present(namedotcomDomain, "", "123d==") err = provider.Present(namedotcomDomain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }
// //
@ -61,8 +61,8 @@ func TestLiveNamedotcomCleanUp(t *testing.T) {
config.Server = namedotcomServer config.Server = namedotcomServer
provider, err := NewDNSProviderConfig(config) provider, err := NewDNSProviderConfig(config)
assert.NoError(t, err) require.NoError(t, err)
err = provider.CleanUp(namedotcomDomain, "", "123d==") err = provider.CleanUp(namedotcomDomain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }

View file

@ -5,7 +5,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/require"
) )
var ( var (
@ -31,10 +31,10 @@ func TestLivenifcloudPresent(t *testing.T) {
} }
provider, err := NewDNSProvider() provider, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
err = provider.Present(nifcloudDomain, "", "123d==") err = provider.Present(nifcloudDomain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }
func TestLivenifcloudCleanUp(t *testing.T) { func TestLivenifcloudCleanUp(t *testing.T) {
@ -45,8 +45,8 @@ func TestLivenifcloudCleanUp(t *testing.T) {
time.Sleep(time.Second * 1) time.Sleep(time.Second * 1)
provider, err := NewDNSProvider() provider, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
err = provider.CleanUp(nifcloudDomain, "", "123d==") err = provider.CleanUp(nifcloudDomain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }

View file

@ -81,7 +81,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return &DNSProvider{client: client, config: config}, nil return &DNSProvider{client: client, config: config}, nil
} }
// Present creates a TXT record to fulfil the dns-01 challenge. // Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, _ := acme.DNS01Record(domain, keyAuth) fqdn, value, _ := acme.DNS01Record(domain, keyAuth)

View file

@ -86,7 +86,7 @@ func TestNewDNSProviderValid(t *testing.T) {
config.APIKey = "123" config.APIKey = "123"
_, err := NewDNSProviderConfig(config) _, err := NewDNSProviderConfig(config)
assert.NoError(t, err) require.NoError(t, err)
} }
func TestNewDNSProviderMissingCredErr(t *testing.T) { func TestNewDNSProviderMissingCredErr(t *testing.T) {
@ -106,10 +106,10 @@ func TestLivePresent(t *testing.T) {
config.APIKey = apiKey config.APIKey = apiKey
provider, err := NewDNSProviderConfig(config) provider, err := NewDNSProviderConfig(config)
assert.NoError(t, err) require.NoError(t, err)
err = provider.Present(domain, "", "123d==") err = provider.Present(domain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }
func TestLiveCleanUp(t *testing.T) { func TestLiveCleanUp(t *testing.T) {
@ -123,8 +123,8 @@ func TestLiveCleanUp(t *testing.T) {
config.APIKey = apiKey config.APIKey = apiKey
provider, err := NewDNSProviderConfig(config) provider, err := NewDNSProviderConfig(config)
assert.NoError(t, err) require.NoError(t, err)
err = provider.CleanUp(domain, "", "123d==") err = provider.CleanUp(domain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }

View file

@ -114,7 +114,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
}, nil }, nil
} }
// Present creates a TXT record to fulfil the dns-01 challenge. // Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, _ := acme.DNS01Record(domain, keyAuth) fqdn, value, _ := acme.DNS01Record(domain, keyAuth)

View file

@ -6,6 +6,7 @@ import (
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
var ( var (
@ -40,7 +41,7 @@ func TestNewDNSProviderValidEnv(t *testing.T) {
os.Setenv("OVH_CONSUMER_KEY", "abcde") os.Setenv("OVH_CONSUMER_KEY", "abcde")
_, err := NewDNSProvider() _, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
} }
func TestNewDNSProviderMissingCredErr(t *testing.T) { func TestNewDNSProviderMissingCredErr(t *testing.T) {
@ -123,10 +124,10 @@ func TestLivePresent(t *testing.T) {
} }
provider, err := NewDNSProvider() provider, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
err = provider.Present(domain, "", "123d==") err = provider.Present(domain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }
func TestLiveCleanUp(t *testing.T) { func TestLiveCleanUp(t *testing.T) {
@ -137,8 +138,8 @@ func TestLiveCleanUp(t *testing.T) {
time.Sleep(time.Second * 1) time.Sleep(time.Second * 1)
provider, err := NewDNSProvider() provider, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
err = provider.CleanUp(domain, "", "123d==") err = provider.CleanUp(domain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }

View file

@ -110,7 +110,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
return d.config.PropagationTimeout, d.config.PollingInterval return d.config.PropagationTimeout, d.config.PollingInterval
} }
// Present creates a TXT record to fulfil the dns-01 challenge // Present creates a TXT record to fulfill the dns-01 challenge
func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, _ := acme.DNS01Record(domain, keyAuth) fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
zone, err := d.getHostedZone(fqdn) zone, err := d.getHostedZone(fqdn)

View file

@ -6,6 +6,7 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
var ( var (
@ -43,7 +44,7 @@ func TestNewDNSProviderValid(t *testing.T) {
config.APIKey = "123" config.APIKey = "123"
_, err := NewDNSProviderConfig(config) _, err := NewDNSProviderConfig(config)
assert.NoError(t, err) require.NoError(t, err)
} }
func TestNewDNSProviderValidEnv(t *testing.T) { func TestNewDNSProviderValidEnv(t *testing.T) {
@ -52,7 +53,7 @@ func TestNewDNSProviderValidEnv(t *testing.T) {
os.Setenv("PDNS_API_KEY", "123") os.Setenv("PDNS_API_KEY", "123")
_, err := NewDNSProvider() _, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
} }
func TestNewDNSProviderMissingHostErr(t *testing.T) { func TestNewDNSProviderMissingHostErr(t *testing.T) {
@ -83,11 +84,11 @@ func TestPdnsPresentAndCleanup(t *testing.T) {
config.APIKey = pdnsAPIKey config.APIKey = pdnsAPIKey
provider, err := NewDNSProviderConfig(config) provider, err := NewDNSProviderConfig(config)
assert.NoError(t, err) require.NoError(t, err)
err = provider.Present(pdnsDomain, "", "123d==") err = provider.Present(pdnsDomain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
err = provider.CleanUp(pdnsDomain, "", "123d==") err = provider.CleanUp(pdnsDomain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }

View file

@ -146,7 +146,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
} }
// Present creates a TXT record to fulfil the dns-01 challenge // Present creates a TXT record to fulfill the dns-01 challenge
func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, _ := acme.DNS01Record(domain, keyAuth) fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
zoneID, err := d.getHostedZoneID(fqdn) zoneID, err := d.getHostedZoneID(fqdn)

View file

@ -180,7 +180,7 @@ func TestOfflineRackspaceCleanUp(t *testing.T) {
if assert.NoError(t, err) { if assert.NoError(t, err) {
err = provider.CleanUp("example.com", "token", "keyAuth") err = provider.CleanUp("example.com", "token", "keyAuth")
assert.NoError(t, err) require.NoError(t, err)
} }
} }
@ -191,7 +191,7 @@ func TestNewDNSProviderValidEnv(t *testing.T) {
liveRackspaceEnv() liveRackspaceEnv()
provider, err := NewDNSProvider() provider, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
assert.Contains(t, provider.cloudDNSEndpoint, "https://dns.api.rackspacecloud.com/v1.0/", "The endpoint URL should contain the base") assert.Contains(t, provider.cloudDNSEndpoint, "https://dns.api.rackspacecloud.com/v1.0/", "The endpoint URL should contain the base")
} }
@ -202,10 +202,10 @@ func TestRackspacePresent(t *testing.T) {
liveRackspaceEnv() liveRackspaceEnv()
provider, err := NewDNSProvider() provider, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
err = provider.Present(rackspaceDomain, "", "112233445566==") err = provider.Present(rackspaceDomain, "", "112233445566==")
assert.NoError(t, err) require.NoError(t, err)
} }
func TestRackspaceCleanUp(t *testing.T) { func TestRackspaceCleanUp(t *testing.T) {
@ -217,10 +217,10 @@ func TestRackspaceCleanUp(t *testing.T) {
liveRackspaceEnv() liveRackspaceEnv()
provider, err := NewDNSProvider() provider, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
err = provider.CleanUp(rackspaceDomain, "", "112233445566==") err = provider.CleanUp(rackspaceDomain, "", "112233445566==")
assert.NoError(t, err) require.NoError(t, err)
} }
func TestMain(m *testing.M) { func TestMain(m *testing.M) {

View file

@ -33,9 +33,14 @@ func TestRFC2136CanaryLocalTestServer(t *testing.T) {
dns.HandleFunc("example.com.", serverHandlerHello) dns.HandleFunc("example.com.", serverHandlerHello)
defer dns.HandleRemove("example.com.") defer dns.HandleRemove("example.com.")
server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", false) server, addrstr, err := runLocalDNSTestServer(false)
require.NoError(t, err, "Failed to start test server") require.NoError(t, err, "Failed to start test server")
defer server.Shutdown() defer func() {
errS := server.Shutdown()
if errS != nil {
t.Log(errS)
}
}()
c := new(dns.Client) c := new(dns.Client)
m := new(dns.Msg) m := new(dns.Msg)
@ -55,9 +60,14 @@ func TestRFC2136ServerSuccess(t *testing.T) {
dns.HandleFunc(rfc2136TestZone, serverHandlerReturnSuccess) dns.HandleFunc(rfc2136TestZone, serverHandlerReturnSuccess)
defer dns.HandleRemove(rfc2136TestZone) defer dns.HandleRemove(rfc2136TestZone)
server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", false) server, addrstr, err := runLocalDNSTestServer(false)
require.NoError(t, err, "Failed to start test server") require.NoError(t, err, "Failed to start test server")
defer server.Shutdown() defer func() {
errS := server.Shutdown()
if errS != nil {
t.Log(errS)
}
}()
config := NewDefaultConfig() config := NewDefaultConfig()
config.Nameserver = addrstr config.Nameserver = addrstr
@ -74,9 +84,14 @@ func TestRFC2136ServerError(t *testing.T) {
dns.HandleFunc(rfc2136TestZone, serverHandlerReturnErr) dns.HandleFunc(rfc2136TestZone, serverHandlerReturnErr)
defer dns.HandleRemove(rfc2136TestZone) defer dns.HandleRemove(rfc2136TestZone)
server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", false) server, addrstr, err := runLocalDNSTestServer(false)
require.NoError(t, err, "Failed to start test server") require.NoError(t, err, "Failed to start test server")
defer server.Shutdown() defer func() {
errS := server.Shutdown()
if errS != nil {
t.Log(errS)
}
}()
config := NewDefaultConfig() config := NewDefaultConfig()
config.Nameserver = addrstr config.Nameserver = addrstr
@ -96,9 +111,14 @@ func TestRFC2136TsigClient(t *testing.T) {
dns.HandleFunc(rfc2136TestZone, serverHandlerReturnSuccess) dns.HandleFunc(rfc2136TestZone, serverHandlerReturnSuccess)
defer dns.HandleRemove(rfc2136TestZone) defer dns.HandleRemove(rfc2136TestZone)
server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", true) server, addrstr, err := runLocalDNSTestServer(true)
require.NoError(t, err, "Failed to start test server") require.NoError(t, err, "Failed to start test server")
defer server.Shutdown() defer func() {
errS := server.Shutdown()
if errS != nil {
t.Log(errS)
}
}()
config := NewDefaultConfig() config := NewDefaultConfig()
config.Nameserver = addrstr config.Nameserver = addrstr
@ -117,9 +137,14 @@ func TestRFC2136ValidUpdatePacket(t *testing.T) {
dns.HandleFunc(rfc2136TestZone, serverHandlerPassBackRequest) dns.HandleFunc(rfc2136TestZone, serverHandlerPassBackRequest)
defer dns.HandleRemove(rfc2136TestZone) defer dns.HandleRemove(rfc2136TestZone)
server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", false) server, addrstr, err := runLocalDNSTestServer(false)
require.NoError(t, err, "Failed to start test server") require.NoError(t, err, "Failed to start test server")
defer server.Shutdown() defer func() {
errS := server.Shutdown()
if errS != nil {
t.Log(errS)
}
}()
txtRR, _ := dns.NewRR(fmt.Sprintf("%s %d IN TXT %s", rfc2136TestFqdn, rfc2136TestTTL, rfc2136TestValue)) txtRR, _ := dns.NewRR(fmt.Sprintf("%s %d IN TXT %s", rfc2136TestFqdn, rfc2136TestTTL, rfc2136TestValue))
rrs := []dns.RR{txtRR} rrs := []dns.RR{txtRR}
@ -157,8 +182,8 @@ func TestRFC2136ValidUpdatePacket(t *testing.T) {
} }
} }
func runLocalDNSTestServer(listenAddr string, tsig bool) (*dns.Server, string, error) { func runLocalDNSTestServer(tsig bool) (*dns.Server, string, error) {
pc, err := net.ListenPacket("udp", listenAddr) pc, err := net.ListenPacket("udp", "127.0.0.1:0")
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
@ -172,7 +197,7 @@ func runLocalDNSTestServer(listenAddr string, tsig bool) (*dns.Server, string, e
server.NotifyStartedFunc = waitLock.Unlock server.NotifyStartedFunc = waitLock.Unlock
go func() { go func() {
server.ActivateAndServe() _ = server.ActivateAndServe()
pc.Close() pc.Close()
}() }()
@ -188,7 +213,7 @@ func serverHandlerHello(w dns.ResponseWriter, req *dns.Msg) {
Hdr: dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0}, Hdr: dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0},
Txt: []string{"Hello world"}, Txt: []string{"Hello world"},
} }
w.WriteMsg(m) _ = w.WriteMsg(m)
} }
func serverHandlerReturnSuccess(w dns.ResponseWriter, req *dns.Msg) { func serverHandlerReturnSuccess(w dns.ResponseWriter, req *dns.Msg) {
@ -207,13 +232,13 @@ func serverHandlerReturnSuccess(w dns.ResponseWriter, req *dns.Msg) {
} }
} }
w.WriteMsg(m) _ = w.WriteMsg(m)
} }
func serverHandlerReturnErr(w dns.ResponseWriter, req *dns.Msg) { func serverHandlerReturnErr(w dns.ResponseWriter, req *dns.Msg) {
m := new(dns.Msg) m := new(dns.Msg)
m.SetRcode(req, dns.RcodeNotZone) m.SetRcode(req, dns.RcodeNotZone)
w.WriteMsg(m) _ = w.WriteMsg(m)
} }
func serverHandlerPassBackRequest(w dns.ResponseWriter, req *dns.Msg) { func serverHandlerPassBackRequest(w dns.ResponseWriter, req *dns.Msg) {
@ -232,7 +257,7 @@ func serverHandlerPassBackRequest(w dns.ResponseWriter, req *dns.Msg) {
} }
} }
w.WriteMsg(m) _ = w.WriteMsg(m)
if req.Opcode != dns.OpcodeQuery || req.Question[0].Qtype != dns.TypeSOA || req.Question[0].Qclass != dns.ClassINET { if req.Opcode != dns.OpcodeQuery || req.Question[0].Qtype != dns.TypeSOA || req.Question[0].Qclass != dns.ClassINET {
// Only talk back when it is not the SOA RR. // Only talk back when it is not the SOA RR.
reqChan <- req reqChan <- req

View file

@ -19,35 +19,36 @@ func TestRoute53TTL(t *testing.T) {
provider, err := NewDNSProvider() provider, err := NewDNSProvider()
require.NoError(t, err) require.NoError(t, err)
err = provider.Present(config["R53_DOMAIN"], "foo", "bar") r53Domain := config["R53_DOMAIN"]
err = provider.Present(r53Domain, "foo", "bar")
require.NoError(t, err) require.NoError(t, err)
// we need a separate R53 client here as the one in the DNS provider is // we need a separate R53 client here as the one in the DNS provider is unexported.
// unexported. fqdn := "_acme-challenge." + r53Domain + "."
fqdn := "_acme-challenge." + config["R53_DOMAIN"] + "."
svc := route53.New(session.New()) svc := route53.New(session.New())
defer func() {
errC := provider.CleanUp(r53Domain, "foo", "bar")
if errC != nil {
t.Log(errC)
}
}()
zoneID, err := provider.getHostedZoneID(fqdn) zoneID, err := provider.getHostedZoneID(fqdn)
if err != nil { require.NoError(t, err)
provider.CleanUp(config["R53_DOMAIN"], "foo", "bar")
t.Fatal(err)
}
params := &route53.ListResourceRecordSetsInput{ params := &route53.ListResourceRecordSetsInput{
HostedZoneId: aws.String(zoneID), HostedZoneId: aws.String(zoneID),
} }
resp, err := svc.ListResourceRecordSets(params) resp, err := svc.ListResourceRecordSets(params)
if err != nil { require.NoError(t, err)
provider.CleanUp(config["R53_DOMAIN"], "foo", "bar")
t.Fatal(err)
}
for _, v := range resp.ResourceRecordSets { for _, v := range resp.ResourceRecordSets {
if aws.StringValue(v.Name) == fqdn && aws.StringValue(v.Type) == "TXT" && aws.Int64Value(v.TTL) == 10 { if aws.StringValue(v.Name) == fqdn && aws.StringValue(v.Type) == "TXT" && aws.Int64Value(v.TTL) == 10 {
provider.CleanUp(config["R53_DOMAIN"], "foo", "bar")
return return
} }
} }
provider.CleanUp(config["R53_DOMAIN"], "foo", "bar") t.Fatalf("Could not find a TXT record for _acme-challenge.%s with a TTL of 10", r53Domain)
t.Fatalf("Could not find a TXT record for _acme-challenge.%s with a TTL of 10", config["R53_DOMAIN"])
} }

View file

@ -30,7 +30,11 @@ func newMockServer(t *testing.T, responses MockResponseMap) *httptest.Server {
w.Header().Set("Content-Type", "application/xml") w.Header().Set("Content-Type", "application/xml")
w.WriteHeader(resp.StatusCode) w.WriteHeader(resp.StatusCode)
w.Write([]byte(resp.Body)) _, err := w.Write([]byte(resp.Body))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
})) }))
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)

View file

@ -85,7 +85,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return &DNSProvider{client: client}, nil return &DNSProvider{client: client}, nil
} }
// Present creates a TXT record to fulfil the dns-01 challenge. // Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, _ := acme.DNS01Record(domain, keyAuth) fqdn, value, _ := acme.DNS01Record(domain, keyAuth)

View file

@ -45,7 +45,7 @@ func TestNewDNSProviderValid(t *testing.T) {
assert.NotNil(t, provider) assert.NotNil(t, provider)
assert.Equal(t, acme.UserAgent, provider.client.UserAgent) assert.Equal(t, acme.UserAgent, provider.client.UserAgent)
assert.NoError(t, err) require.NoError(t, err)
} }
func TestNewDNSProviderInvalidWithMissingAccessToken(t *testing.T) { func TestNewDNSProviderInvalidWithMissingAccessToken(t *testing.T) {
@ -96,10 +96,10 @@ func TestLiveSakuraCloudPresent(t *testing.T) {
config.Secret = sakuracloudAccessSecret config.Secret = sakuracloudAccessSecret
provider, err := NewDNSProviderConfig(config) provider, err := NewDNSProviderConfig(config)
assert.NoError(t, err) require.NoError(t, err)
err = provider.Present(sakuracloudDomain, "", "123d==") err = provider.Present(sakuracloudDomain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }
// //
@ -118,8 +118,8 @@ func TestLiveSakuraCloudCleanUp(t *testing.T) {
config.Secret = sakuracloudAccessSecret config.Secret = sakuracloudAccessSecret
provider, err := NewDNSProviderConfig(config) provider, err := NewDNSProviderConfig(config)
assert.NoError(t, err) require.NoError(t, err)
err = provider.CleanUp(sakuracloudDomain, "", "123d==") err = provider.CleanUp(sakuracloudDomain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }

View file

@ -87,7 +87,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
return d.config.PropagationTimeout, d.config.PollingInterval return d.config.PropagationTimeout, d.config.PollingInterval
} }
// Present creates a TXT record to fulfil the dns-01 challenge // Present creates a TXT record to fulfill the dns-01 challenge
func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, _ := acme.DNS01Record(domain, keyAuth) fqdn, value, _ := acme.DNS01Record(domain, keyAuth)

View file

@ -15,6 +15,8 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
const testDomain = "example.com"
var ipPort = "127.0.0.1:2112" var ipPort = "127.0.0.1:2112"
var jsonMap = map[string]string{ var jsonMap = map[string]string{
@ -122,88 +124,90 @@ func TestVegaDNSTimeoutSuccess(t *testing.T) {
assert.Equal(t, interval, time.Duration(60000000000)) assert.Equal(t, interval, time.Duration(60000000000))
} }
func TestVegaDNSPresentSuccess(t *testing.T) { func TestDNSProvider_Present(t *testing.T) {
ts, err := startTestServer(vegaDNSMuxSuccess) testCases := []struct {
require.NoError(t, err) desc string
callback muxCallback
expectedError string
}{
{
desc: "Success",
callback: vegaDNSMuxSuccess,
},
{
desc: "FailToFindZone",
callback: vegaDNSMuxFailToFindZone,
expectedError: "vegadns: can't find Authoritative Zone for _acme-challenge.example.com. in Present: Unable to find auth zone for fqdn _acme-challenge.example.com",
},
{
desc: "FailToCreateTXT",
callback: vegaDNSMuxFailToCreateTXT,
expectedError: "vegadns: Got bad answer from VegaDNS on CreateTXT. Code: 400. Message: ",
},
}
defer ts.Close() for _, test := range testCases {
defer os.Clearenv() t.Run(test.desc, func(t *testing.T) {
ts, err := startTestServer(test.callback)
require.NoError(t, err)
provider, err := NewDNSProvider() defer ts.Close()
require.NoError(t, err) defer os.Clearenv()
err = provider.Present("example.com", "token", "keyAuth") provider, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
err = provider.Present(testDomain, "token", "keyAuth")
if len(test.expectedError) == 0 {
assert.NoError(t, err)
} else {
assert.EqualError(t, err, test.expectedError)
}
})
}
} }
func TestVegaDNSPresentFailToFindZone(t *testing.T) { func TestDNSProvider_CleanUp(t *testing.T) {
ts, err := startTestServer(vegaDNSMuxFailToFindZone) testCases := []struct {
require.NoError(t, err) desc string
callback muxCallback
expectedError string
}{
{
desc: "Success",
callback: vegaDNSMuxSuccess,
},
{
desc: "FailToFindZone",
callback: vegaDNSMuxFailToFindZone,
expectedError: "vegadns: can't find Authoritative Zone for _acme-challenge.example.com. in CleanUp: Unable to find auth zone for fqdn _acme-challenge.example.com",
},
{
desc: "FailToGetRecordID",
callback: vegaDNSMuxFailToGetRecordID,
expectedError: "vegadns: couldn't get Record ID in CleanUp: Got bad answer from VegaDNS on GetRecordID. Code: 404. Message: ",
},
}
defer ts.Close() for _, test := range testCases {
defer os.Clearenv() t.Run(test.desc, func(t *testing.T) {
ts, err := startTestServer(test.callback)
require.NoError(t, err)
provider, err := NewDNSProvider() defer ts.Close()
require.NoError(t, err) defer os.Clearenv()
err = provider.Present("example.com", "token", "keyAuth") provider, err := NewDNSProvider()
assert.EqualError(t, err, "vegadns: can't find Authoritative Zone for _acme-challenge.example.com. in Present: Unable to find auth zone for fqdn _acme-challenge.example.com") require.NoError(t, err)
}
func TestVegaDNSPresentFailToCreateTXT(t *testing.T) { err = provider.CleanUp(testDomain, "token", "keyAuth")
ts, err := startTestServer(vegaDNSMuxFailToCreateTXT) if len(test.expectedError) == 0 {
require.NoError(t, err) assert.NoError(t, err)
} else {
defer ts.Close() assert.EqualError(t, err, test.expectedError)
defer os.Clearenv() }
})
provider, err := NewDNSProvider() }
require.NoError(t, err)
err = provider.Present("example.com", "token", "keyAuth")
assert.EqualError(t, err, "vegadns: Got bad answer from VegaDNS on CreateTXT. Code: 400. Message: ")
}
func TestVegaDNSCleanUpSuccess(t *testing.T) {
ts, err := startTestServer(vegaDNSMuxSuccess)
require.NoError(t, err)
defer ts.Close()
defer os.Clearenv()
provider, err := NewDNSProvider()
require.NoError(t, err)
err = provider.CleanUp("example.com", "token", "keyAuth")
assert.NoError(t, err)
}
func TestVegaDNSCleanUpFailToFindZone(t *testing.T) {
ts, err := startTestServer(vegaDNSMuxFailToFindZone)
require.NoError(t, err)
defer ts.Close()
defer os.Clearenv()
provider, err := NewDNSProvider()
require.NoError(t, err)
err = provider.CleanUp("example.com", "token", "keyAuth")
assert.EqualError(t, err, "vegadns: can't find Authoritative Zone for _acme-challenge.example.com. in CleanUp: Unable to find auth zone for fqdn _acme-challenge.example.com")
}
func TestVegaDNSCleanUpFailToGetRecordID(t *testing.T) {
ts, err := startTestServer(vegaDNSMuxFailToGetRecordID)
require.NoError(t, err)
defer ts.Close()
defer os.Clearenv()
provider, err := NewDNSProvider()
require.NoError(t, err)
err = provider.CleanUp("example.com", "token", "keyAuth")
assert.EqualError(t, err, "vegadns: couldn't get Record ID in CleanUp: Got bad answer from VegaDNS on GetRecordID. Code: 404. Message: ")
} }
func vegaDNSMuxSuccess() *http.ServeMux { func vegaDNSMuxSuccess() *http.ServeMux {
@ -298,7 +302,7 @@ func vegaDNSMuxFailToCreateTXT() *http.ServeMux {
}) })
mux.HandleFunc("/1.0/domains", func(w http.ResponseWriter, r *http.Request) { mux.HandleFunc("/1.0/domains", func(w http.ResponseWriter, r *http.Request) {
if r.URL.Query().Get("search") == "example.com" { if r.URL.Query().Get("search") == testDomain {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, jsonMap["domains"]) fmt.Fprintf(w, jsonMap["domains"])
return return
@ -340,7 +344,7 @@ func vegaDNSMuxFailToGetRecordID() *http.ServeMux {
}) })
mux.HandleFunc("/1.0/domains", func(w http.ResponseWriter, r *http.Request) { mux.HandleFunc("/1.0/domains", func(w http.ResponseWriter, r *http.Request) {
if r.URL.Query().Get("search") == "example.com" { if r.URL.Query().Get("search") == testDomain {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, jsonMap["domains"]) fmt.Fprintf(w, jsonMap["domains"])
return return

View file

@ -90,7 +90,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return &DNSProvider{client: client, config: config}, nil return &DNSProvider{client: client, config: config}, nil
} }
// Present creates a TXT record to fulfil the DNS-01 challenge. // Present creates a TXT record to fulfill the DNS-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, _ := acme.DNS01Record(domain, keyAuth) fqdn, value, _ := acme.DNS01Record(domain, keyAuth)

View file

@ -6,6 +6,7 @@ import (
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
var ( var (
@ -29,7 +30,7 @@ func TestNewDNSProviderValidEnv(t *testing.T) {
os.Setenv("VULTR_API_KEY", "123") os.Setenv("VULTR_API_KEY", "123")
_, err := NewDNSProvider() _, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
} }
func TestNewDNSProviderMissingCredErr(t *testing.T) { func TestNewDNSProviderMissingCredErr(t *testing.T) {
@ -46,10 +47,10 @@ func TestLivePresent(t *testing.T) {
} }
provider, err := NewDNSProvider() provider, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
err = provider.Present(domain, "", "123d==") err = provider.Present(domain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }
func TestLiveCleanUp(t *testing.T) { func TestLiveCleanUp(t *testing.T) {
@ -60,8 +61,8 @@ func TestLiveCleanUp(t *testing.T) {
time.Sleep(time.Second * 1) time.Sleep(time.Second * 1)
provider, err := NewDNSProvider() provider, err := NewDNSProvider()
assert.NoError(t, err) require.NoError(t, err)
err = provider.CleanUp(domain, "", "123d==") err = provider.CleanUp(domain, "", "123d==")
assert.NoError(t, err) require.NoError(t, err)
} }

View file

@ -8,6 +8,7 @@ import (
"github.com/rainycape/memcache" "github.com/rainycape/memcache"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/xenolf/lego/acme" "github.com/xenolf/lego/acme"
) )
@ -39,7 +40,7 @@ func TestNewMemcachedProviderValid(t *testing.T) {
t.Skip("Skipping memcached tests") t.Skip("Skipping memcached tests")
} }
_, err := NewMemcachedProvider(memcachedHosts) _, err := NewMemcachedProvider(memcachedHosts)
assert.NoError(t, err) require.NoError(t, err)
} }
func TestMemcachedPresentSingleHost(t *testing.T) { func TestMemcachedPresentSingleHost(t *testing.T) {
@ -47,16 +48,16 @@ func TestMemcachedPresentSingleHost(t *testing.T) {
t.Skip("Skipping memcached tests") t.Skip("Skipping memcached tests")
} }
p, err := NewMemcachedProvider(memcachedHosts[0:1]) p, err := NewMemcachedProvider(memcachedHosts[0:1])
assert.NoError(t, err) require.NoError(t, err)
challengePath := path.Join("/", acme.HTTP01ChallengePath(token)) challengePath := path.Join("/", acme.HTTP01ChallengePath(token))
err = p.Present(domain, token, keyAuth) err = p.Present(domain, token, keyAuth)
assert.NoError(t, err) require.NoError(t, err)
mc, err := memcache.New(memcachedHosts[0]) mc, err := memcache.New(memcachedHosts[0])
assert.NoError(t, err) require.NoError(t, err)
i, err := mc.Get(challengePath) i, err := mc.Get(challengePath)
assert.NoError(t, err) require.NoError(t, err)
assert.Equal(t, i.Value, []byte(keyAuth)) assert.Equal(t, i.Value, []byte(keyAuth))
} }
@ -65,17 +66,17 @@ func TestMemcachedPresentMultiHost(t *testing.T) {
t.Skip("Skipping memcached multi-host tests") t.Skip("Skipping memcached multi-host tests")
} }
p, err := NewMemcachedProvider(memcachedHosts) p, err := NewMemcachedProvider(memcachedHosts)
assert.NoError(t, err) require.NoError(t, err)
challengePath := path.Join("/", acme.HTTP01ChallengePath(token)) challengePath := path.Join("/", acme.HTTP01ChallengePath(token))
err = p.Present(domain, token, keyAuth) err = p.Present(domain, token, keyAuth)
assert.NoError(t, err) require.NoError(t, err)
for _, host := range memcachedHosts { for _, host := range memcachedHosts {
mc, err := memcache.New(host) mc, err := memcache.New(host)
assert.NoError(t, err) require.NoError(t, err)
i, err := mc.Get(challengePath) i, err := mc.Get(challengePath)
assert.NoError(t, err) require.NoError(t, err)
assert.Equal(t, i.Value, []byte(keyAuth)) assert.Equal(t, i.Value, []byte(keyAuth))
} }
} }
@ -86,17 +87,17 @@ func TestMemcachedPresentPartialFailureMultiHost(t *testing.T) {
} }
hosts := append(memcachedHosts, "5.5.5.5:11211") hosts := append(memcachedHosts, "5.5.5.5:11211")
p, err := NewMemcachedProvider(hosts) p, err := NewMemcachedProvider(hosts)
assert.NoError(t, err) require.NoError(t, err)
challengePath := path.Join("/", acme.HTTP01ChallengePath(token)) challengePath := path.Join("/", acme.HTTP01ChallengePath(token))
err = p.Present(domain, token, keyAuth) err = p.Present(domain, token, keyAuth)
assert.NoError(t, err) require.NoError(t, err)
for _, host := range memcachedHosts { for _, host := range memcachedHosts {
mc, err := memcache.New(host) mc, err := memcache.New(host)
assert.NoError(t, err) require.NoError(t, err)
i, err := mc.Get(challengePath) i, err := mc.Get(challengePath)
assert.NoError(t, err) require.NoError(t, err)
assert.Equal(t, i.Value, []byte(keyAuth)) assert.Equal(t, i.Value, []byte(keyAuth))
} }
} }
@ -106,6 +107,6 @@ func TestMemcachedCleanup(t *testing.T) {
t.Skip("Skipping memcached tests") t.Skip("Skipping memcached tests")
} }
p, err := NewMemcachedProvider(memcachedHosts) p, err := NewMemcachedProvider(memcachedHosts)
assert.NoError(t, err) require.NoError(t, err)
assert.NoError(t, p.CleanUp(domain, token, keyAuth)) require.NoError(t, p.CleanUp(domain, token, keyAuth))
} }

View file

@ -18,14 +18,10 @@ type HTTPProvider struct {
// NewHTTPProvider returns a HTTPProvider instance with a configured webroot path // NewHTTPProvider returns a HTTPProvider instance with a configured webroot path
func NewHTTPProvider(path string) (*HTTPProvider, error) { func NewHTTPProvider(path string) (*HTTPProvider, error) {
if _, err := os.Stat(path); os.IsNotExist(err) { if _, err := os.Stat(path); os.IsNotExist(err) {
return nil, fmt.Errorf("Webroot path does not exist") return nil, fmt.Errorf("webroot path does not exist")
} }
c := &HTTPProvider{ return &HTTPProvider{path: path}, nil
path: path,
}
return c, nil
} }
// Present makes the token available at `HTTP01ChallengePath(token)` by creating a file in the given webroot path // Present makes the token available at `HTTP01ChallengePath(token)` by creating a file in the given webroot path

View file

@ -4,6 +4,9 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestHTTPProvider(t *testing.T) { func TestHTTPProvider(t *testing.T) {
@ -13,34 +16,26 @@ func TestHTTPProvider(t *testing.T) {
keyAuth := "keyAuth" keyAuth := "keyAuth"
challengeFilePath := webroot + "/.well-known/acme-challenge/" + token challengeFilePath := webroot + "/.well-known/acme-challenge/" + token
os.MkdirAll(webroot+"/.well-known/acme-challenge", 0777) require.NoError(t, os.MkdirAll(webroot+"/.well-known/acme-challenge", 0777))
defer os.RemoveAll(webroot) defer os.RemoveAll(webroot)
provider, err := NewHTTPProvider(webroot) provider, err := NewHTTPProvider(webroot)
if err != nil { require.NoError(t, err)
t.Errorf("Webroot provider error: got %v, want nil", err)
}
err = provider.Present(domain, token, keyAuth) err = provider.Present(domain, token, keyAuth)
if err != nil { require.NoError(t, err)
t.Errorf("Webroot provider present() error: got %v, want nil", err)
}
if _, err := os.Stat(challengeFilePath); os.IsNotExist(err) { if _, err = os.Stat(challengeFilePath); os.IsNotExist(err) {
t.Error("Challenge file was not created in webroot") t.Error("Challenge file was not created in webroot")
} }
data, err := ioutil.ReadFile(challengeFilePath) var data []byte
if err != nil { data, err = ioutil.ReadFile(challengeFilePath)
t.Errorf("Webroot provider ReadFile() error: got %v, want nil", err) require.NoError(t, err)
}
dataStr := string(data) dataStr := string(data)
if dataStr != keyAuth { assert.Equal(t, keyAuth, dataStr)
t.Errorf("Challenge file content: got %q, want %q", dataStr, keyAuth)
}
err = provider.CleanUp(domain, token, keyAuth) err = provider.CleanUp(domain, token, keyAuth)
if err != nil { require.NoError(t, err)
t.Errorf("Webroot provider CleanUp() error: got %v, want nil", err)
}
} }