mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-05-11 05:55:12 +00:00
New DNS provider PowerDNS (#748)
* Added PowerDNS as dns provider * Remove unnecessary comments * Some tests * Implemented feedback
This commit is contained in:
committed by
GitHub
parent
5269540827
commit
ffd4e46dda
24
vendor/github.com/mittwald/go-powerdns/pdnshttp/auth.go
generated
vendored
Normal file
24
vendor/github.com/mittwald/go-powerdns/pdnshttp/auth.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
package pdnshttp
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type ClientAuthenticator interface {
|
||||
OnRequest(*http.Request) error
|
||||
OnConnect(*http.Client) error
|
||||
}
|
||||
|
||||
// NoopAuthenticator provides an "empty" implementation of the
|
||||
// ClientAuthenticator interface.
|
||||
type NoopAuthenticator struct{}
|
||||
|
||||
// OnRequest is applied each time a HTTP request is built.
|
||||
func (NoopAuthenticator) OnRequest(*http.Request) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnConnect is applied on the entire connection as soon as it is set up.
|
||||
func (NoopAuthenticator) OnConnect(*http.Client) error {
|
||||
return nil
|
||||
}
|
16
vendor/github.com/mittwald/go-powerdns/pdnshttp/auth_key.go
generated
vendored
Normal file
16
vendor/github.com/mittwald/go-powerdns/pdnshttp/auth_key.go
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
package pdnshttp
|
||||
|
||||
import "net/http"
|
||||
|
||||
type APIKeyAuthenticator struct {
|
||||
APIKey string
|
||||
}
|
||||
|
||||
func (a *APIKeyAuthenticator) OnRequest(r *http.Request) error {
|
||||
r.Header.Set("X-API-Key", a.APIKey)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *APIKeyAuthenticator) OnConnect(*http.Client) error {
|
||||
return nil
|
||||
}
|
55
vendor/github.com/mittwald/go-powerdns/pdnshttp/auth_tls.go
generated
vendored
Normal file
55
vendor/github.com/mittwald/go-powerdns/pdnshttp/auth_tls.go
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
package pdnshttp
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type TLSClientCertificateAuthenticator struct {
|
||||
CACerts []*x509.Certificate
|
||||
ClientCert tls.Certificate
|
||||
ClientKey crypto.PrivateKey
|
||||
}
|
||||
|
||||
func (a *TLSClientCertificateAuthenticator) OnRequest(r *http.Request) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *TLSClientCertificateAuthenticator) OnConnect(c *http.Client) error {
|
||||
if c.Transport == nil {
|
||||
c.Transport = http.DefaultTransport
|
||||
}
|
||||
|
||||
t, ok := c.Transport.(*http.Transport)
|
||||
if !ok {
|
||||
return fmt.Errorf("client.Transport is no *http.Transport, instead %t", c.Transport)
|
||||
}
|
||||
|
||||
if t.TLSClientConfig == nil {
|
||||
t.TLSClientConfig = &tls.Config{}
|
||||
}
|
||||
|
||||
if t.TLSClientConfig.Certificates == nil {
|
||||
t.TLSClientConfig.Certificates = make([]tls.Certificate, 0, 1)
|
||||
}
|
||||
|
||||
t.TLSClientConfig.Certificates = append(t.TLSClientConfig.Certificates, a.ClientCert)
|
||||
|
||||
if t.TLSClientConfig.RootCAs == nil {
|
||||
systemPool, err := x509.SystemCertPool()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.TLSClientConfig.RootCAs = systemPool
|
||||
}
|
||||
|
||||
for i := range a.CACerts {
|
||||
t.TLSClientConfig.RootCAs.AddCert(a.CACerts[i])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
119
vendor/github.com/mittwald/go-powerdns/pdnshttp/client.go
generated
vendored
Normal file
119
vendor/github.com/mittwald/go-powerdns/pdnshttp/client.go
generated
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
package pdnshttp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
baseURL string
|
||||
httpClient *http.Client
|
||||
authenticator ClientAuthenticator
|
||||
debugOutput io.Writer
|
||||
}
|
||||
|
||||
// NewClient returns a new PowerDNS HTTP client
|
||||
func NewClient(baseURL string, hc *http.Client, auth ClientAuthenticator, debugOutput io.Writer) *Client {
|
||||
c := Client{
|
||||
baseURL: baseURL,
|
||||
httpClient: hc,
|
||||
authenticator: auth,
|
||||
debugOutput: debugOutput,
|
||||
}
|
||||
|
||||
return &c
|
||||
}
|
||||
|
||||
// NewRequest builds a new request. Usually, this method should not be used;
|
||||
// prefer using the "Get", "Post", ... methods if possible.
|
||||
func (c *Client) NewRequest(method string, path string, body io.Reader) (*http.Request, error) {
|
||||
path = strings.TrimPrefix(path, "/")
|
||||
req, err := http.NewRequest(method, c.baseURL+"/"+path, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c.authenticator != nil {
|
||||
if err := c.authenticator.OnRequest(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return req, err
|
||||
}
|
||||
|
||||
// Get executes a GET request
|
||||
func (c *Client) Get(ctx context.Context, path string, out interface{}, opts ...RequestOption) error {
|
||||
return c.doRequest(ctx, http.MethodGet, path, out, opts...)
|
||||
}
|
||||
|
||||
// Post executes a POST request
|
||||
func (c *Client) Post(ctx context.Context, path string, out interface{}, opts ...RequestOption) error {
|
||||
return c.doRequest(ctx, http.MethodPost, path, out, opts...)
|
||||
}
|
||||
|
||||
// Put executes a PUT request
|
||||
func (c *Client) Put(ctx context.Context, path string, out interface{}, opts ...RequestOption) error {
|
||||
return c.doRequest(ctx, http.MethodPut, path, out, opts...)
|
||||
}
|
||||
|
||||
// Patch executes a PATCH request
|
||||
func (c *Client) Patch(ctx context.Context, path string, out interface{}, opts ...RequestOption) error {
|
||||
return c.doRequest(ctx, http.MethodPatch, path, out, opts...)
|
||||
}
|
||||
|
||||
// Delete executes a DELETE request
|
||||
func (c *Client) Delete(ctx context.Context, path string, out interface{}, opts ...RequestOption) error {
|
||||
return c.doRequest(ctx, http.MethodDelete, path, out, opts...)
|
||||
}
|
||||
|
||||
func (c *Client) doRequest(ctx context.Context, method string, path string, out interface{}, opts ...RequestOption) error {
|
||||
req, err := c.NewRequest(method, path, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range opts {
|
||||
if err := opts[i](req); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
req = req.WithContext(ctx)
|
||||
|
||||
reqDump, _ := httputil.DumpRequestOut(req, true)
|
||||
c.debugOutput.Write(reqDump)
|
||||
|
||||
res, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resDump, _ := httputil.DumpResponse(res, true)
|
||||
c.debugOutput.Write(resDump)
|
||||
|
||||
if res.StatusCode == http.StatusNotFound {
|
||||
return ErrNotFound{URL: req.URL.String()}
|
||||
} else if res.StatusCode >= 400 {
|
||||
return ErrUnexpectedStatus{URL: req.URL.String(), StatusCode: res.StatusCode}
|
||||
}
|
||||
|
||||
if out != nil {
|
||||
if w, ok := out.(io.Writer); ok {
|
||||
_, err := io.Copy(w, res.Body)
|
||||
return err
|
||||
}
|
||||
|
||||
dec := json.NewDecoder(res.Body)
|
||||
err = dec.Decode(out)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
31
vendor/github.com/mittwald/go-powerdns/pdnshttp/errors.go
generated
vendored
Normal file
31
vendor/github.com/mittwald/go-powerdns/pdnshttp/errors.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
package pdnshttp
|
||||
|
||||
import "fmt"
|
||||
|
||||
type ErrNotFound struct {
|
||||
URL string
|
||||
}
|
||||
|
||||
func (e ErrNotFound) Error() string {
|
||||
return fmt.Sprintf("not found: %s", e.URL)
|
||||
}
|
||||
|
||||
type ErrUnexpectedStatus struct {
|
||||
URL string
|
||||
StatusCode int
|
||||
}
|
||||
|
||||
func (e ErrUnexpectedStatus) Error() string {
|
||||
return fmt.Sprintf("unexpected status code %d: %s", e.StatusCode, e.URL)
|
||||
}
|
||||
|
||||
func IsNotFound(err error) bool {
|
||||
switch err.(type) {
|
||||
case ErrNotFound:
|
||||
return true
|
||||
case *ErrNotFound:
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
58
vendor/github.com/mittwald/go-powerdns/pdnshttp/req_opt.go
generated
vendored
Normal file
58
vendor/github.com/mittwald/go-powerdns/pdnshttp/req_opt.go
generated
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
package pdnshttp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// RequestOption is a special type of function that can be passed to most HTTP
|
||||
// request functions in this package; it is used to modify an HTTP request and
|
||||
// to implement special request logic.
|
||||
type RequestOption func(*http.Request) error
|
||||
|
||||
// WithJSONRequestBody adds a JSON body to a request. The input type can be
|
||||
// anything, as long as it can be marshaled by "json.Marshal". This method will
|
||||
// also automatically set the correct content type and content-length.
|
||||
func WithJSONRequestBody(in interface{}) RequestOption {
|
||||
return func(req *http.Request) error {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
enc := json.NewEncoder(&buf)
|
||||
err := enc.Encode(in)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rc := ioutil.NopCloser(&buf)
|
||||
|
||||
copyBuf := buf.Bytes()
|
||||
|
||||
req.Body = rc
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.ContentLength = int64(buf.Len())
|
||||
req.GetBody = func() (io.ReadCloser, error) {
|
||||
r := bytes.NewReader(copyBuf)
|
||||
return ioutil.NopCloser(r), nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithQueryValue adds a query parameter to a request's URL.
|
||||
func WithQueryValue(key, value string) RequestOption {
|
||||
return func(req *http.Request) error {
|
||||
q := req.URL.Query()
|
||||
q.Set(key, value)
|
||||
|
||||
req.URL.RawQuery = q.Encode()
|
||||
return nil
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user