Add example server that passes the test fixtures
Signed-off-by: Jake Sanders <i@am.so-aweso.me>
This commit is contained in:
parent
9b61d24773
commit
4f51af7d86
@ -1 +1,59 @@
|
||||
package example
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func (e *exampleSolver) handleDNSRequest(w dns.ResponseWriter, req *dns.Msg) {
|
||||
msg := new(dns.Msg)
|
||||
msg.SetReply(req)
|
||||
switch req.Opcode {
|
||||
case dns.OpcodeQuery:
|
||||
for _, q := range msg.Question {
|
||||
switch q.Qtype {
|
||||
case dns.TypeA:
|
||||
rr, err := dns.NewRR(fmt.Sprintf("%s 5 IN A 127.0.0.1", q.Name))
|
||||
if err != nil {
|
||||
msg.SetRcode(req, dns.RcodeNameError)
|
||||
} else {
|
||||
msg.Answer = append(msg.Answer, rr)
|
||||
}
|
||||
case dns.TypeTXT:
|
||||
// get record
|
||||
e.RLock()
|
||||
record, found := e.txtRecords[q.Name]
|
||||
e.RUnlock()
|
||||
if !found {
|
||||
msg.SetRcode(req, dns.RcodeNameError)
|
||||
} else {
|
||||
rr, err := dns.NewRR(fmt.Sprintf("%s 5 IN TXT %s", q.Name, record))
|
||||
if err != nil {
|
||||
msg.SetRcode(req, dns.RcodeServerFailure)
|
||||
break
|
||||
}
|
||||
msg.Answer = append(msg.Answer, rr)
|
||||
}
|
||||
case dns.TypeNS:
|
||||
rr, err := dns.NewRR(fmt.Sprintf("%s 5 IN NS ns.example-acme-webook.invalid.", q.Name))
|
||||
if err != nil {
|
||||
msg.SetRcode(req, dns.RcodeServerFailure)
|
||||
break
|
||||
} else {
|
||||
msg.Answer = append(msg.Answer, rr)
|
||||
}
|
||||
case dns.TypeSOA:
|
||||
rr, err := dns.NewRR(fmt.Sprintf("%s 5 IN SOA %s 20 5 5 5 5", "ns.example-acme-webook.invalid.", "ns.example-acme-webook.invalid."))
|
||||
if err != nil {
|
||||
msg.SetRcode(req, dns.RcodeServerFailure)
|
||||
break
|
||||
}
|
||||
msg.Answer = append(msg.Answer, rr)
|
||||
default:
|
||||
msg.SetRcode(req, dns.RcodeServerFailure)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
w.WriteMsg(msg)
|
||||
}
|
||||
|
@ -1 +1,61 @@
|
||||
// package example contains a self-contained example of a webhook that passes the cert-manager
|
||||
// DNS conformance tests
|
||||
package example
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/jetstack/cert-manager/pkg/acme/webhook"
|
||||
acme "github.com/jetstack/cert-manager/pkg/acme/webhook/apis/acme/v1alpha1"
|
||||
"github.com/miekg/dns"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type exampleSolver struct {
|
||||
name string
|
||||
server *dns.Server
|
||||
txtRecords map[string]string
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func (e exampleSolver) Name() string {
|
||||
return e.name
|
||||
}
|
||||
|
||||
func (e exampleSolver) Present(ch *acme.ChallengeRequest) error {
|
||||
e.Lock()
|
||||
e.txtRecords[ch.ResolvedFQDN] = ch.Key
|
||||
e.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e exampleSolver) CleanUp(ch *acme.ChallengeRequest) error {
|
||||
e.Lock()
|
||||
delete(e.txtRecords, ch.ResolvedFQDN)
|
||||
e.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e exampleSolver) Initialize(kubeClientConfig *rest.Config, stopCh <-chan struct{}) error {
|
||||
go func(done <-chan struct{}) {
|
||||
<-done
|
||||
e.server.Shutdown()
|
||||
}(stopCh)
|
||||
go func() {
|
||||
e.server.ListenAndServe()
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func New(port string) webhook.Solver {
|
||||
e := &exampleSolver{
|
||||
name: "example",
|
||||
txtRecords: make(map[string]string),
|
||||
}
|
||||
e.server = &dns.Server{
|
||||
Addr: ":" + port,
|
||||
Net: "udp",
|
||||
Handler: dns.HandlerFunc(e.handleDNSRequest),
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
@ -1 +1,95 @@
|
||||
package example
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
acme "github.com/jetstack/cert-manager/pkg/acme/webhook/apis/acme/v1alpha1"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"math/big"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestExampleSolver_Name(t *testing.T) {
|
||||
port, _ := rand.Int(rand.Reader, big.NewInt(50000))
|
||||
port = port.Add(port, big.NewInt(15534))
|
||||
solver := New(port.String())
|
||||
assert.Equal(t, "example", solver.Name())
|
||||
}
|
||||
|
||||
func TestExampleSolver_Initialize(t *testing.T) {
|
||||
port, _ := rand.Int(rand.Reader, big.NewInt(50000))
|
||||
port = port.Add(port, big.NewInt(15534))
|
||||
solver := New(port.String())
|
||||
done := make(chan struct{})
|
||||
err := solver.Initialize(nil, done)
|
||||
assert.NoError(t, err, "Expected Initialize not to error")
|
||||
close(done)
|
||||
}
|
||||
|
||||
func TestExampleSolver_Present_Cleanup(t *testing.T) {
|
||||
port, _ := rand.Int(rand.Reader, big.NewInt(50000))
|
||||
port = port.Add(port, big.NewInt(15534))
|
||||
solver := New(port.String())
|
||||
done := make(chan struct{})
|
||||
err := solver.Initialize(nil, done)
|
||||
assert.NoError(t, err, "Expected Initialize not to error")
|
||||
|
||||
validTestData := []struct {
|
||||
hostname string
|
||||
record string
|
||||
}{
|
||||
{"test1.example.com.", "testkey1"},
|
||||
{"test2.example.com.", "testkey2"},
|
||||
{"test3.example.com.", "testkey3"},
|
||||
}
|
||||
for _, test := range validTestData {
|
||||
err := solver.Present(&acme.ChallengeRequest{
|
||||
Action: acme.ChallengeActionPresent,
|
||||
Type: "dns-01",
|
||||
ResolvedFQDN: test.hostname,
|
||||
Key: test.record,
|
||||
})
|
||||
assert.NoError(t, err, "Unexpected error while presenting %v", t)
|
||||
}
|
||||
|
||||
// Resolve test data
|
||||
for _, test := range validTestData {
|
||||
msg := new(dns.Msg)
|
||||
msg.Id = dns.Id()
|
||||
msg.RecursionDesired = true
|
||||
msg.Question = make([]dns.Question, 1)
|
||||
msg.Question[0] = dns.Question{dns.Fqdn(test.hostname), dns.TypeTXT, dns.ClassINET}
|
||||
in, err := dns.Exchange(msg, "127.0.0.1:"+port.String())
|
||||
|
||||
assert.NoError(t, err, "Presented record %s not resolvable", test.hostname)
|
||||
assert.Len(t, in.Answer, 1, "RR response is of incorrect length")
|
||||
assert.Equal(t, []string{test.record}, in.Answer[0].(*dns.TXT).Txt, "TXT record returned did not match presented record")
|
||||
}
|
||||
|
||||
// Cleanup test data
|
||||
for _, test := range validTestData {
|
||||
err := solver.CleanUp(&acme.ChallengeRequest{
|
||||
Action: acme.ChallengeActionCleanUp,
|
||||
Type: "dns-01",
|
||||
ResolvedFQDN: test.hostname,
|
||||
Key: test.record,
|
||||
})
|
||||
assert.NoError(t, err, "Unexpected error while cleaning up %v", t)
|
||||
}
|
||||
|
||||
// Resolve test data
|
||||
for _, test := range validTestData {
|
||||
msg := new(dns.Msg)
|
||||
msg.Id = dns.Id()
|
||||
msg.RecursionDesired = true
|
||||
msg.Question = make([]dns.Question, 1)
|
||||
msg.Question[0] = dns.Question{dns.Fqdn(test.hostname), dns.TypeTXT, dns.ClassINET}
|
||||
in, err := dns.Exchange(msg, "127.0.0.1:"+port.String())
|
||||
|
||||
assert.NoError(t, err, "Presented record %s not resolvable", test.hostname)
|
||||
assert.Len(t, in.Answer, 0, "RR response is of incorrect length")
|
||||
assert.Equal(t, dns.RcodeNameError, in.Rcode, "Expexted NXDOMAIN")
|
||||
}
|
||||
|
||||
close(done)
|
||||
}
|
||||
|
20
main_test.go
20
main_test.go
@ -5,6 +5,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/jetstack/cert-manager/test/acme/dns"
|
||||
|
||||
"github.com/jetstack/cert-manager-webhook-example/example"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -15,11 +17,23 @@ func TestRunsSuite(t *testing.T) {
|
||||
// The manifest path should contain a file named config.json that is a
|
||||
// snippet of valid configuration that should be included on the
|
||||
// ChallengeRequest passed as part of the test cases.
|
||||
//
|
||||
|
||||
fixture := dns.NewFixture(&customDNSProviderSolver{},
|
||||
dns.SetResolvedZone(zone),
|
||||
dns.SetAllowAmbientCredentials(false),
|
||||
// Uncomment the below fixture when implementing your custom DNS provider
|
||||
//fixture := dns.NewFixture(&customDNSProviderSolver{},
|
||||
// dns.SetResolvedZone(zone),
|
||||
// dns.SetAllowAmbientCredentials(false),
|
||||
// dns.SetManifestPath("testdata/my-custom-solver"),
|
||||
// dns.SetBinariesPath("_test/kubebuilder/bin"),
|
||||
//)
|
||||
|
||||
solver := example.New("59351")
|
||||
fixture := dns.NewFixture(solver,
|
||||
dns.SetResolvedZone("example.com."),
|
||||
dns.SetManifestPath("testdata/my-custom-solver"),
|
||||
dns.SetBinariesPath("_test/kubebuilder/bin"),
|
||||
dns.SetDNSServer("127.0.0.1:59351"),
|
||||
dns.SetUseAuthoritative(false),
|
||||
)
|
||||
|
||||
fixture.RunConformance(t)
|
||||
|
Loading…
Reference in New Issue
Block a user