Cleanup and fixes (#223)
* Set version to 001 * Remove k8stest, test fails is k8s is not there: touch luck * Remove server directory: not used anymore * Disable k8s test (for now) * gometalinter changes
This commit is contained in:
parent
9ac3cab1b7
commit
416603383d
17 changed files with 33 additions and 1071 deletions
|
@ -6,21 +6,19 @@ import (
|
|||
|
||||
// plug in the standard directives
|
||||
_ "github.com/miekg/coredns/middleware/bind"
|
||||
_ "github.com/miekg/coredns/middleware/health"
|
||||
_ "github.com/miekg/coredns/middleware/pprof"
|
||||
|
||||
_ "github.com/miekg/coredns/middleware/errors"
|
||||
_ "github.com/miekg/coredns/middleware/loadbalance"
|
||||
_ "github.com/miekg/coredns/middleware/log"
|
||||
_ "github.com/miekg/coredns/middleware/metrics"
|
||||
_ "github.com/miekg/coredns/middleware/rewrite"
|
||||
|
||||
_ "github.com/miekg/coredns/middleware/cache"
|
||||
_ "github.com/miekg/coredns/middleware/chaos"
|
||||
_ "github.com/miekg/coredns/middleware/dnssec"
|
||||
_ "github.com/miekg/coredns/middleware/errors"
|
||||
_ "github.com/miekg/coredns/middleware/etcd"
|
||||
_ "github.com/miekg/coredns/middleware/file"
|
||||
_ "github.com/miekg/coredns/middleware/health"
|
||||
_ "github.com/miekg/coredns/middleware/kubernetes"
|
||||
_ "github.com/miekg/coredns/middleware/loadbalance"
|
||||
_ "github.com/miekg/coredns/middleware/log"
|
||||
_ "github.com/miekg/coredns/middleware/metrics"
|
||||
_ "github.com/miekg/coredns/middleware/pprof"
|
||||
_ "github.com/miekg/coredns/middleware/proxy"
|
||||
_ "github.com/miekg/coredns/middleware/rewrite"
|
||||
_ "github.com/miekg/coredns/middleware/secondary"
|
||||
)
|
||||
|
|
|
@ -9,7 +9,7 @@ package dnsserver
|
|||
// feel the effects of all other middleware below
|
||||
// (after) them during a request, but they must not
|
||||
// care what middleware above them are doing.
|
||||
var Directives = []string{
|
||||
var directives = []string{
|
||||
"bind",
|
||||
"health",
|
||||
"pprof",
|
||||
|
|
|
@ -13,7 +13,7 @@ const serverType = "dns"
|
|||
|
||||
func init() {
|
||||
caddy.RegisterServerType(serverType, caddy.ServerType{
|
||||
Directives: Directives,
|
||||
Directives: directives,
|
||||
DefaultInput: func() caddy.Input {
|
||||
if Port == DefaultPort && Zone != "" {
|
||||
return caddy.CaddyfileInput{
|
||||
|
@ -32,8 +32,6 @@ func init() {
|
|||
})
|
||||
}
|
||||
|
||||
var TestNewContext = newContext
|
||||
|
||||
func newContext() caddy.Context {
|
||||
return &dnsContext{keysToConfigs: make(map[string]*Config)}
|
||||
}
|
||||
|
@ -103,8 +101,8 @@ func (h *dnsContext) MakeServers() ([]caddy.Server, error) {
|
|||
}
|
||||
|
||||
// AddMiddleware adds a middleware to a site's middleware stack.
|
||||
func (sc *Config) AddMiddleware(m Middleware) {
|
||||
sc.Middleware = append(sc.Middleware, m)
|
||||
func (c *Config) AddMiddleware(m Middleware) {
|
||||
c.Middleware = append(c.Middleware, m)
|
||||
}
|
||||
|
||||
// groupSiteConfigsByListenAddr groups site configs by their listen
|
||||
|
|
|
@ -32,6 +32,7 @@ type Server struct {
|
|||
connTimeout time.Duration // the maximum duration of a graceful shutdown
|
||||
}
|
||||
|
||||
// NewServer returns a new CoreDNS server and compiles all middleware in to it.
|
||||
func NewServer(addr string, group []*Config) (*Server, error) {
|
||||
|
||||
s := &Server{
|
||||
|
@ -65,20 +66,6 @@ func NewServer(addr string, group []*Config) (*Server, error) {
|
|||
return s, nil
|
||||
}
|
||||
|
||||
// LocalAddr return the addresses where the server is bound to.
|
||||
func (s *Server) LocalAddr() net.Addr {
|
||||
s.m.Lock()
|
||||
defer s.m.Unlock()
|
||||
return s.l.Addr()
|
||||
}
|
||||
|
||||
// LocalAddrPacket return the net.PacketConn address where the server is bound to.
|
||||
func (s *Server) LocalAddrPacket() net.Addr {
|
||||
s.m.Lock()
|
||||
defer s.m.Unlock()
|
||||
return s.p.LocalAddr()
|
||||
}
|
||||
|
||||
// Serve starts the server with an existing listener. It blocks until the server stops.
|
||||
func (s *Server) Serve(l net.Listener) error {
|
||||
s.m.Lock()
|
||||
|
@ -97,6 +84,7 @@ func (s *Server) ServePacket(p net.PacketConn) error {
|
|||
return s.server[udp].ActivateAndServe()
|
||||
}
|
||||
|
||||
// Listen implements caddy.TCPServer interface.
|
||||
func (s *Server) Listen() (net.Listener, error) {
|
||||
l, err := net.Listen("tcp", s.Addr)
|
||||
if err != nil {
|
||||
|
@ -108,6 +96,7 @@ func (s *Server) Listen() (net.Listener, error) {
|
|||
return l, nil
|
||||
}
|
||||
|
||||
// ListenPacket implements caddy.UDPServer interface.
|
||||
func (s *Server) ListenPacket() (net.PacketConn, error) {
|
||||
p, err := net.ListenPacket("udp", s.Addr)
|
||||
if err != nil {
|
||||
|
@ -197,7 +186,7 @@ func (s *Server) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
|||
if h, ok := s.zones[string(b[:l])]; ok {
|
||||
if r.Question[0].Qtype != dns.TypeDS {
|
||||
rcode, _ := h.middlewareChain.ServeDNS(ctx, w, r)
|
||||
if RcodeNoClientWrite(rcode) {
|
||||
if rcodeNoClientWrite(rcode) {
|
||||
DefaultErrorFunc(w, r, rcode)
|
||||
}
|
||||
return
|
||||
|
@ -211,7 +200,7 @@ func (s *Server) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
|||
// Wildcard match, if we have found nothing try the root zone as a last resort.
|
||||
if h, ok := s.zones["."]; ok {
|
||||
rcode, _ := h.middlewareChain.ServeDNS(ctx, w, r)
|
||||
if RcodeNoClientWrite(rcode) {
|
||||
if rcodeNoClientWrite(rcode) {
|
||||
DefaultErrorFunc(w, r, rcode)
|
||||
}
|
||||
return
|
||||
|
@ -234,7 +223,7 @@ func DefaultErrorFunc(w dns.ResponseWriter, r *dns.Msg, rcode int) {
|
|||
w.WriteMsg(answer)
|
||||
}
|
||||
|
||||
func RcodeNoClientWrite(rcode int) bool {
|
||||
func rcodeNoClientWrite(rcode int) bool {
|
||||
switch rcode {
|
||||
case dns.RcodeServerFailure:
|
||||
fallthrough
|
||||
|
|
|
@ -10,9 +10,15 @@ import (
|
|||
//go:generate go run plugin_generate.go
|
||||
|
||||
func main() {
|
||||
// Set some flags/options specific for CoreDNS.
|
||||
// Default values for flags for CoreDNS.
|
||||
flag.Set("type", "dns")
|
||||
|
||||
// Values specific for CoreDNS.
|
||||
caddy.DefaultConfigFile = "Corefile"
|
||||
caddy.AppName = "coredns"
|
||||
caddy.AppVersion = version
|
||||
|
||||
caddymain.Run()
|
||||
}
|
||||
|
||||
const version = "001"
|
||||
|
|
|
@ -56,4 +56,4 @@ func doDDD(b []byte) {
|
|||
}
|
||||
|
||||
func isDigit(b byte) bool { return b >= '0' && b <= '9' }
|
||||
func dddToByte(s []byte) byte { return byte((s[1]-'0')*100 + (s[2]-'0')*10 + (s[3] - '0')) }
|
||||
func dddToByte(s []byte) byte { return (s[1]-'0')*100 + (s[2]-'0')*10 + (s[3] - '0') }
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
"unicode"
|
||||
|
||||
"github.com/flynn/go-shlex"
|
||||
)
|
||||
|
||||
var runtimeGoos = runtime.GOOS
|
||||
|
||||
// SplitCommandAndArgs takes a command string and parses it
|
||||
// shell-style into the command and its separate arguments.
|
||||
func SplitCommandAndArgs(command string) (cmd string, args []string, err error) {
|
||||
var parts []string
|
||||
|
||||
if runtimeGoos == "windows" {
|
||||
parts = parseWindowsCommand(command) // parse it Windows-style
|
||||
} else {
|
||||
parts, err = parseUnixCommand(command) // parse it Unix-style
|
||||
if err != nil {
|
||||
err = errors.New("error parsing command: " + err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(parts) == 0 {
|
||||
err = errors.New("no command contained in '" + command + "'")
|
||||
return
|
||||
}
|
||||
|
||||
cmd = parts[0]
|
||||
if len(parts) > 1 {
|
||||
args = parts[1:]
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// parseUnixCommand parses a unix style command line and returns the
|
||||
// command and its arguments or an error
|
||||
func parseUnixCommand(cmd string) ([]string, error) {
|
||||
return shlex.Split(cmd)
|
||||
}
|
||||
|
||||
// parseWindowsCommand parses windows command lines and
|
||||
// returns the command and the arguments as an array. It
|
||||
// should be able to parse commonly used command lines.
|
||||
// Only basic syntax is supported:
|
||||
// - spaces in double quotes are not token delimiters
|
||||
// - double quotes are escaped by either backspace or another double quote
|
||||
// - except for the above case backspaces are path separators (not special)
|
||||
//
|
||||
// Many sources point out that escaping quotes using backslash can be unsafe.
|
||||
// Use two double quotes when possible. (Source: http://stackoverflow.com/a/31413730/2616179 )
|
||||
//
|
||||
// This function has to be used on Windows instead
|
||||
// of the shlex package because this function treats backslash
|
||||
// characters properly.
|
||||
func parseWindowsCommand(cmd string) []string {
|
||||
const backslash = '\\'
|
||||
const quote = '"'
|
||||
|
||||
var parts []string
|
||||
var part string
|
||||
var inQuotes bool
|
||||
var lastRune rune
|
||||
|
||||
for i, ch := range cmd {
|
||||
|
||||
if i != 0 {
|
||||
lastRune = rune(cmd[i-1])
|
||||
}
|
||||
|
||||
if ch == backslash {
|
||||
// put it in the part - for now we don't know if it's an
|
||||
// escaping char or path separator
|
||||
part += string(ch)
|
||||
continue
|
||||
}
|
||||
|
||||
if ch == quote {
|
||||
if lastRune == backslash {
|
||||
// remove the backslash from the part and add the escaped quote instead
|
||||
part = part[:len(part)-1]
|
||||
part += string(ch)
|
||||
continue
|
||||
}
|
||||
|
||||
if lastRune == quote {
|
||||
// revert the last change of the inQuotes state
|
||||
// it was an escaping quote
|
||||
inQuotes = !inQuotes
|
||||
part += string(ch)
|
||||
continue
|
||||
}
|
||||
|
||||
// normal escaping quotes
|
||||
inQuotes = !inQuotes
|
||||
continue
|
||||
|
||||
}
|
||||
|
||||
if unicode.IsSpace(ch) && !inQuotes && len(part) > 0 {
|
||||
parts = append(parts, part)
|
||||
part = ""
|
||||
continue
|
||||
}
|
||||
|
||||
part += string(ch)
|
||||
}
|
||||
|
||||
if len(part) > 0 {
|
||||
parts = append(parts, part)
|
||||
part = ""
|
||||
}
|
||||
|
||||
return parts
|
||||
}
|
|
@ -1,291 +0,0 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseUnixCommand(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expected []string
|
||||
}{
|
||||
// 0 - emtpy command
|
||||
{
|
||||
input: ``,
|
||||
expected: []string{},
|
||||
},
|
||||
// 1 - command without arguments
|
||||
{
|
||||
input: `command`,
|
||||
expected: []string{`command`},
|
||||
},
|
||||
// 2 - command with single argument
|
||||
{
|
||||
input: `command arg1`,
|
||||
expected: []string{`command`, `arg1`},
|
||||
},
|
||||
// 3 - command with multiple arguments
|
||||
{
|
||||
input: `command arg1 arg2`,
|
||||
expected: []string{`command`, `arg1`, `arg2`},
|
||||
},
|
||||
// 4 - command with single argument with space character - in quotes
|
||||
{
|
||||
input: `command "arg1 arg1"`,
|
||||
expected: []string{`command`, `arg1 arg1`},
|
||||
},
|
||||
// 5 - command with multiple spaces and tab character
|
||||
{
|
||||
input: "command arg1 arg2\targ3",
|
||||
expected: []string{`command`, `arg1`, `arg2`, `arg3`},
|
||||
},
|
||||
// 6 - command with single argument with space character - escaped with backspace
|
||||
{
|
||||
input: `command arg1\ arg2`,
|
||||
expected: []string{`command`, `arg1 arg2`},
|
||||
},
|
||||
// 7 - single quotes should escape special chars
|
||||
{
|
||||
input: `command 'arg1\ arg2'`,
|
||||
expected: []string{`command`, `arg1\ arg2`},
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
errorPrefix := fmt.Sprintf("Test [%d]: ", i)
|
||||
errorSuffix := fmt.Sprintf(" Command to parse: [%s]", test.input)
|
||||
actual, _ := parseUnixCommand(test.input)
|
||||
if len(actual) != len(test.expected) {
|
||||
t.Errorf(errorPrefix+"Expected %d parts, got %d: %#v."+errorSuffix, len(test.expected), len(actual), actual)
|
||||
continue
|
||||
}
|
||||
for j := 0; j < len(actual); j++ {
|
||||
if expectedPart, actualPart := test.expected[j], actual[j]; expectedPart != actualPart {
|
||||
t.Errorf(errorPrefix+"Expected: %v Actual: %v (index %d)."+errorSuffix, expectedPart, actualPart, j)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseWindowsCommand(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expected []string
|
||||
}{
|
||||
{ // 0 - empty command - do not fail
|
||||
input: ``,
|
||||
expected: []string{},
|
||||
},
|
||||
{ // 1 - cmd without args
|
||||
input: `cmd`,
|
||||
expected: []string{`cmd`},
|
||||
},
|
||||
{ // 2 - multiple args
|
||||
input: `cmd arg1 arg2`,
|
||||
expected: []string{`cmd`, `arg1`, `arg2`},
|
||||
},
|
||||
{ // 3 - multiple args with space
|
||||
input: `cmd "combined arg" arg2`,
|
||||
expected: []string{`cmd`, `combined arg`, `arg2`},
|
||||
},
|
||||
{ // 4 - path without spaces
|
||||
input: `mkdir C:\Windows\foo\bar`,
|
||||
expected: []string{`mkdir`, `C:\Windows\foo\bar`},
|
||||
},
|
||||
{ // 5 - command with space in quotes
|
||||
input: `"command here"`,
|
||||
expected: []string{`command here`},
|
||||
},
|
||||
{ // 6 - argument with escaped quotes (two quotes)
|
||||
input: `cmd ""arg""`,
|
||||
expected: []string{`cmd`, `"arg"`},
|
||||
},
|
||||
{ // 7 - argument with escaped quotes (backslash)
|
||||
input: `cmd \"arg\"`,
|
||||
expected: []string{`cmd`, `"arg"`},
|
||||
},
|
||||
{ // 8 - two quotes (escaped) inside an inQuote element
|
||||
input: `cmd "a ""quoted value"`,
|
||||
expected: []string{`cmd`, `a "quoted value`},
|
||||
},
|
||||
// TODO - see how many quotes are dislayed if we use "", """, """""""
|
||||
{ // 9 - two quotes outside an inQuote element
|
||||
input: `cmd a ""quoted value`,
|
||||
expected: []string{`cmd`, `a`, `"quoted`, `value`},
|
||||
},
|
||||
{ // 10 - path with space in quotes
|
||||
input: `mkdir "C:\directory name\foobar"`,
|
||||
expected: []string{`mkdir`, `C:\directory name\foobar`},
|
||||
},
|
||||
{ // 11 - space without quotes
|
||||
input: `mkdir C:\ space`,
|
||||
expected: []string{`mkdir`, `C:\`, `space`},
|
||||
},
|
||||
{ // 12 - space in quotes
|
||||
input: `mkdir "C:\ space"`,
|
||||
expected: []string{`mkdir`, `C:\ space`},
|
||||
},
|
||||
{ // 13 - UNC
|
||||
input: `mkdir \\?\C:\Users`,
|
||||
expected: []string{`mkdir`, `\\?\C:\Users`},
|
||||
},
|
||||
{ // 14 - UNC with space
|
||||
input: `mkdir "\\?\C:\Program Files"`,
|
||||
expected: []string{`mkdir`, `\\?\C:\Program Files`},
|
||||
},
|
||||
|
||||
{ // 15 - unclosed quotes - treat as if the path ends with quote
|
||||
input: `mkdir "c:\Program files`,
|
||||
expected: []string{`mkdir`, `c:\Program files`},
|
||||
},
|
||||
{ // 16 - quotes used inside the argument
|
||||
input: `mkdir "c:\P"rogra"m f"iles`,
|
||||
expected: []string{`mkdir`, `c:\Program files`},
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
errorPrefix := fmt.Sprintf("Test [%d]: ", i)
|
||||
errorSuffix := fmt.Sprintf(" Command to parse: [%s]", test.input)
|
||||
|
||||
actual := parseWindowsCommand(test.input)
|
||||
if len(actual) != len(test.expected) {
|
||||
t.Errorf(errorPrefix+"Expected %d parts, got %d: %#v."+errorSuffix, len(test.expected), len(actual), actual)
|
||||
continue
|
||||
}
|
||||
for j := 0; j < len(actual); j++ {
|
||||
if expectedPart, actualPart := test.expected[j], actual[j]; expectedPart != actualPart {
|
||||
t.Errorf(errorPrefix+"Expected: %v Actual: %v (index %d)."+errorSuffix, expectedPart, actualPart, j)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitCommandAndArgs(t *testing.T) {
|
||||
|
||||
// force linux parsing. It's more robust and covers error cases
|
||||
runtimeGoos = "linux"
|
||||
defer func() {
|
||||
runtimeGoos = runtime.GOOS
|
||||
}()
|
||||
|
||||
var parseErrorContent = "error parsing command:"
|
||||
var noCommandErrContent = "no command contained in"
|
||||
|
||||
tests := []struct {
|
||||
input string
|
||||
expectedCommand string
|
||||
expectedArgs []string
|
||||
expectedErrContent string
|
||||
}{
|
||||
// 0 - emtpy command
|
||||
{
|
||||
input: ``,
|
||||
expectedCommand: ``,
|
||||
expectedArgs: nil,
|
||||
expectedErrContent: noCommandErrContent,
|
||||
},
|
||||
// 1 - command without arguments
|
||||
{
|
||||
input: `command`,
|
||||
expectedCommand: `command`,
|
||||
expectedArgs: nil,
|
||||
expectedErrContent: ``,
|
||||
},
|
||||
// 2 - command with single argument
|
||||
{
|
||||
input: `command arg1`,
|
||||
expectedCommand: `command`,
|
||||
expectedArgs: []string{`arg1`},
|
||||
expectedErrContent: ``,
|
||||
},
|
||||
// 3 - command with multiple arguments
|
||||
{
|
||||
input: `command arg1 arg2`,
|
||||
expectedCommand: `command`,
|
||||
expectedArgs: []string{`arg1`, `arg2`},
|
||||
expectedErrContent: ``,
|
||||
},
|
||||
// 4 - command with unclosed quotes
|
||||
{
|
||||
input: `command "arg1 arg2`,
|
||||
expectedCommand: "",
|
||||
expectedArgs: nil,
|
||||
expectedErrContent: parseErrorContent,
|
||||
},
|
||||
// 5 - command with unclosed quotes
|
||||
{
|
||||
input: `command 'arg1 arg2"`,
|
||||
expectedCommand: "",
|
||||
expectedArgs: nil,
|
||||
expectedErrContent: parseErrorContent,
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
errorPrefix := fmt.Sprintf("Test [%d]: ", i)
|
||||
errorSuffix := fmt.Sprintf(" Command to parse: [%s]", test.input)
|
||||
actualCommand, actualArgs, actualErr := SplitCommandAndArgs(test.input)
|
||||
|
||||
// test if error matches expectation
|
||||
if test.expectedErrContent != "" {
|
||||
if actualErr == nil {
|
||||
t.Errorf(errorPrefix+"Expected error with content [%s], found no error."+errorSuffix, test.expectedErrContent)
|
||||
} else if !strings.Contains(actualErr.Error(), test.expectedErrContent) {
|
||||
t.Errorf(errorPrefix+"Expected error with content [%s], found [%v]."+errorSuffix, test.expectedErrContent, actualErr)
|
||||
}
|
||||
} else if actualErr != nil {
|
||||
t.Errorf(errorPrefix+"Expected no error, found [%v]."+errorSuffix, actualErr)
|
||||
}
|
||||
|
||||
// test if command matches
|
||||
if test.expectedCommand != actualCommand {
|
||||
t.Errorf(errorPrefix+"Expected command: [%s], actual: [%s]."+errorSuffix, test.expectedCommand, actualCommand)
|
||||
}
|
||||
|
||||
// test if arguments match
|
||||
if len(test.expectedArgs) != len(actualArgs) {
|
||||
t.Errorf(errorPrefix+"Wrong number of arguments! Expected [%v], actual [%v]."+errorSuffix, test.expectedArgs, actualArgs)
|
||||
} else {
|
||||
// test args only if the count matches.
|
||||
for j, actualArg := range actualArgs {
|
||||
expectedArg := test.expectedArgs[j]
|
||||
if actualArg != expectedArg {
|
||||
t.Errorf(errorPrefix+"Argument at position [%d] differ! Expected [%s], actual [%s]"+errorSuffix, j, expectedArg, actualArg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleSplitCommandAndArgs() {
|
||||
var commandLine string
|
||||
var command string
|
||||
var args []string
|
||||
|
||||
// just for the test - change GOOS and reset it at the end of the test
|
||||
runtimeGoos = "windows"
|
||||
defer func() {
|
||||
runtimeGoos = runtime.GOOS
|
||||
}()
|
||||
|
||||
commandLine = `mkdir /P "C:\Program Files"`
|
||||
command, args, _ = SplitCommandAndArgs(commandLine)
|
||||
|
||||
fmt.Printf("Windows: %s: %s [%s]\n", commandLine, command, strings.Join(args, ","))
|
||||
|
||||
// set GOOS to linux
|
||||
runtimeGoos = "linux"
|
||||
|
||||
commandLine = `mkdir -p /path/with\ space`
|
||||
command, args, _ = SplitCommandAndArgs(commandLine)
|
||||
|
||||
fmt.Printf("Linux: %s: %s [%s]\n", commandLine, command, strings.Join(args, ","))
|
||||
|
||||
// Output:
|
||||
// Windows: mkdir /P "C:\Program Files": mkdir [/P,C:\Program Files]
|
||||
// Linux: mkdir -p /path/with\ space: mkdir [-p,/path/with space]
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package k8stest
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// checkKubernetesRunning performs a basic
|
||||
func CheckKubernetesRunning() bool {
|
||||
_, err := http.Get("http://localhost:8080/api/v1")
|
||||
return err == nil
|
||||
}
|
|
@ -7,7 +7,6 @@ import (
|
|||
|
||||
"github.com/miekg/coredns/core/dnsserver"
|
||||
"github.com/miekg/coredns/middleware"
|
||||
"github.com/miekg/coredns/server"
|
||||
|
||||
"github.com/hashicorp/go-syslog"
|
||||
"github.com/mholt/caddy"
|
||||
|
@ -64,7 +63,7 @@ func setup(c *caddy.Controller) error {
|
|||
})
|
||||
|
||||
dnsserver.GetConfig(c).AddMiddleware(func(next dnsserver.Handler) dnsserver.Handler {
|
||||
return Logger{Next: next, Rules: rules, ErrorFunc: server.DefaultErrorFunc}
|
||||
return Logger{Next: next, Rules: rules, ErrorFunc: dnsserver.DefaultErrorFunc}
|
||||
})
|
||||
|
||||
return nil
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/miekg/coredns/middleware"
|
||||
)
|
||||
|
||||
// Config configuration for a single server.
|
||||
type Config struct {
|
||||
// The hostname or IP on which to serve
|
||||
Host string
|
||||
|
||||
// The host address to bind on - defaults to (virtual) Host if empty
|
||||
BindHost string
|
||||
|
||||
// The port to listen on
|
||||
Port string
|
||||
|
||||
// The directory from which to parse db files
|
||||
Root string
|
||||
|
||||
// HTTPS configuration
|
||||
TLS TLSConfig
|
||||
|
||||
// Middleware stack
|
||||
Middleware []middleware.Middleware
|
||||
|
||||
// Startup is a list of functions (or methods) to execute at
|
||||
// server startup and restart; these are executed before any
|
||||
// parts of the server are configured, and the functions are
|
||||
// blocking. These are good for setting up middlewares and
|
||||
// starting goroutines.
|
||||
Startup []func() error
|
||||
|
||||
// FirstStartup is like Startup but these functions only execute
|
||||
// during the initial startup, not on subsequent restarts.
|
||||
//
|
||||
// (Note: The server does not ever run these on its own; it is up
|
||||
// to the calling application to do so, and do so only once, as the
|
||||
// server itself has no notion whether it's a restart or not.)
|
||||
FirstStartup []func() error
|
||||
|
||||
// Functions (or methods) to execute when the server quits;
|
||||
// these are executed in response to SIGINT and are blocking. These
|
||||
// function are *also* called when we are restarting.
|
||||
Shutdown []func() error
|
||||
|
||||
// The path to the configuration file from which this was loaded
|
||||
ConfigFile string
|
||||
|
||||
// The name of the application
|
||||
AppName string
|
||||
|
||||
// The application's version
|
||||
AppVersion string
|
||||
}
|
||||
|
||||
// Address returns the host:port of c as a string.
|
||||
func (c Config) Address() string {
|
||||
return net.JoinHostPort(c.Host, c.Port)
|
||||
}
|
||||
|
||||
// TLSConfig describes how TLS should be configured and used.
|
||||
type TLSConfig struct {
|
||||
Enabled bool // will be set to true if TLS is enabled
|
||||
LetsEncryptEmail string
|
||||
Manual bool // will be set to true if user provides own certs and keys
|
||||
Managed bool // will be set to true if config qualifies for implicit automatic/managed HTTPS
|
||||
OnDemand bool // will be set to true if user enables on-demand TLS (obtain certs during handshakes)
|
||||
Ciphers []uint16
|
||||
ProtocolMinVersion uint16
|
||||
ProtocolMaxVersion uint16
|
||||
PreferServerCipherSuites bool
|
||||
ClientCerts []string
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package server
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestConfigAddress(t *testing.T) {
|
||||
cfg := Config{Host: "foobar", Port: "1234"}
|
||||
if actual, expected := cfg.Address(), "foobar:1234"; expected != actual {
|
||||
t.Errorf("Expected '%s' but got '%s'", expected, actual)
|
||||
}
|
||||
|
||||
cfg = Config{Host: "", Port: "1234"}
|
||||
if actual, expected := cfg.Address(), ":1234"; expected != actual {
|
||||
t.Errorf("Expected '%s' but got '%s'", expected, actual)
|
||||
}
|
||||
|
||||
cfg = Config{Host: "foobar", Port: ""}
|
||||
if actual, expected := cfg.Address(), "foobar:"; expected != actual {
|
||||
t.Errorf("Expected '%s' but got '%s'", expected, actual)
|
||||
}
|
||||
|
||||
cfg = Config{Host: "::1", Port: "443"}
|
||||
if actual, expected := cfg.Address(), "[::1]:443"; expected != actual {
|
||||
t.Errorf("Expected '%s' but got '%s'", expected, actual)
|
||||
}
|
||||
}
|
467
server/server.go
467
server/server.go
|
@ -1,467 +0,0 @@
|
|||
// Package server implements a configurable, general-purpose web server.
|
||||
// It relies on configurations obtained from the adjacent config package
|
||||
// and can execute middleware as defined by the adjacent middleware package.
|
||||
package server
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/coredns/middleware"
|
||||
"github.com/miekg/coredns/middleware/metrics"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Server represents an instance of a server, which serves
|
||||
// DNS requests at a particular address (host and port). A
|
||||
// server is capable of serving numerous zones on
|
||||
// the same address and the listener may be stopped for
|
||||
// graceful termination (POSIX only).
|
||||
type Server struct {
|
||||
Addr string // Address we listen on
|
||||
mux *dns.ServeMux
|
||||
server [2]*dns.Server // by convention 0 is tcp and 1 is udp
|
||||
listenerMu sync.Mutex // protects listener and packetconn inside server
|
||||
|
||||
tls bool // whether this server is serving all HTTPS hosts or not
|
||||
TLSConfig *tls.Config
|
||||
OnDemandTLS bool // whether this server supports on-demand TLS (load certs at handshake-time)
|
||||
zones map[string]zone // zones keyed by their address
|
||||
dnsWg sync.WaitGroup // used to wait on outstanding connections
|
||||
startChan chan struct{} // used to block until server is finished starting
|
||||
connTimeout time.Duration // the maximum duration of a graceful shutdown
|
||||
ReqCallback OptionalCallback // if non-nil, is executed at the beginning of every request
|
||||
SNICallback func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error)
|
||||
}
|
||||
|
||||
// OptionalCallback is a function that may or may not handle a request.
|
||||
// It returns whether or not it handled the request. If it handled the
|
||||
// request, it is presumed that no further request handling should occur.
|
||||
type OptionalCallback func(dns.ResponseWriter, *dns.Msg) bool
|
||||
|
||||
// New creates a new Server which will bind to addr and serve
|
||||
// the sites/hosts configured in configs. Its listener will
|
||||
// gracefully close when the server is stopped which will take
|
||||
// no longer than gracefulTimeout.
|
||||
//
|
||||
// This function does not start serving.
|
||||
//
|
||||
// Do not re-use a server (start, stop, then start again). We
|
||||
// could probably add more locking to make this possible, but
|
||||
// as it stands, you should dispose of a server after stopping it.
|
||||
// The behavior of serving with a spent server is undefined.
|
||||
func New(addr string, configs []Config, gracefulTimeout time.Duration) (*Server, error) {
|
||||
var useTLS, useOnDemandTLS bool
|
||||
if len(configs) > 0 {
|
||||
useTLS = configs[0].TLS.Enabled
|
||||
useOnDemandTLS = configs[0].TLS.OnDemand
|
||||
}
|
||||
|
||||
s := &Server{
|
||||
Addr: addr,
|
||||
TLSConfig: new(tls.Config),
|
||||
// TODO: Make these values configurable?
|
||||
// ReadTimeout: 2 * time.Minute,
|
||||
// WriteTimeout: 2 * time.Minute,
|
||||
// MaxHeaderBytes: 1 << 16,
|
||||
tls: useTLS,
|
||||
OnDemandTLS: useOnDemandTLS,
|
||||
zones: make(map[string]zone),
|
||||
startChan: make(chan struct{}),
|
||||
connTimeout: gracefulTimeout,
|
||||
}
|
||||
mux := dns.NewServeMux()
|
||||
mux.Handle(".", s) // wildcard handler, everything will go through here
|
||||
s.mux = mux
|
||||
|
||||
// We have to bound our wg with one increment
|
||||
// to prevent a "race condition" that is hard-coded
|
||||
// into sync.WaitGroup.Wait() - basically, an add
|
||||
// with a positive delta must be guaranteed to
|
||||
// occur before Wait() is called on the wg.
|
||||
// In a way, this kind of acts as a safety barrier.
|
||||
s.dnsWg.Add(1)
|
||||
|
||||
// Set up each zone
|
||||
for _, conf := range configs {
|
||||
if _, exists := s.zones[conf.Host]; exists {
|
||||
return nil, fmt.Errorf("cannot serve %s - host already defined for address %s", conf.Address(), s.Addr)
|
||||
}
|
||||
|
||||
z := zone{config: conf}
|
||||
|
||||
// Build middleware stack
|
||||
err := z.buildStack()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.zones[conf.Host] = z
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Serve starts the server with an existing listener. It blocks until the server stops.
|
||||
func (s *Server) Serve(ln net.Listener, pc net.PacketConn) error {
|
||||
err := s.setup()
|
||||
if err != nil {
|
||||
close(s.startChan) // MUST defer so error is properly reported, same with all cases in this file
|
||||
return err
|
||||
}
|
||||
s.listenerMu.Lock()
|
||||
s.server[0] = &dns.Server{Listener: ln, Net: "tcp", Handler: s.mux}
|
||||
s.server[1] = &dns.Server{PacketConn: pc, Net: "udp", Handler: s.mux}
|
||||
s.listenerMu.Unlock()
|
||||
|
||||
go func() {
|
||||
s.server[0].ActivateAndServe()
|
||||
}()
|
||||
close(s.startChan)
|
||||
return s.server[1].ActivateAndServe()
|
||||
}
|
||||
|
||||
// ListenAndServe starts the server with a new listener. It blocks until the server stops.
|
||||
func (s *Server) ListenAndServe() error {
|
||||
err := s.setup()
|
||||
// defer close(s.startChan) // Don't understand why defer wouldn't actually work in this method (prolly cause the last ActivateAndServe does not actually return?
|
||||
if err != nil {
|
||||
close(s.startChan)
|
||||
return err
|
||||
}
|
||||
|
||||
l, err := net.Listen("tcp", s.Addr)
|
||||
if err != nil {
|
||||
close(s.startChan)
|
||||
return err
|
||||
}
|
||||
pc, err := net.ListenPacket("udp", s.Addr)
|
||||
if err != nil {
|
||||
close(s.startChan)
|
||||
return err
|
||||
}
|
||||
|
||||
s.listenerMu.Lock()
|
||||
s.server[0] = &dns.Server{Listener: l, Net: "tcp", Handler: s.mux}
|
||||
s.server[1] = &dns.Server{PacketConn: pc, Net: "udp", Handler: s.mux}
|
||||
s.listenerMu.Unlock()
|
||||
|
||||
go func() {
|
||||
s.server[0].ActivateAndServe()
|
||||
}()
|
||||
close(s.startChan)
|
||||
return s.server[1].ActivateAndServe()
|
||||
}
|
||||
|
||||
// setup prepares the server s to begin listening; it should be
|
||||
// called just before the listener announces itself on the network
|
||||
// and should only be called when the server is just starting up.
|
||||
func (s *Server) setup() error {
|
||||
// Execute startup functions now
|
||||
for _, z := range s.zones {
|
||||
for _, startupFunc := range z.config.Startup {
|
||||
err := startupFunc()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
TODO(miek): no such thing in the glorious Go DNS.
|
||||
// serveTLS serves TLS with SNI and client auth support if s has them enabled. It
|
||||
// blocks until s quits.
|
||||
func serveTLS(s *Server, ln net.Listener, tlsConfigs []TLSConfig) error {
|
||||
// Customize our TLS configuration
|
||||
s.TLSConfig.MinVersion = tlsConfigs[0].ProtocolMinVersion
|
||||
s.TLSConfig.MaxVersion = tlsConfigs[0].ProtocolMaxVersion
|
||||
s.TLSConfig.CipherSuites = tlsConfigs[0].Ciphers
|
||||
s.TLSConfig.PreferServerCipherSuites = tlsConfigs[0].PreferServerCipherSuites
|
||||
|
||||
// TLS client authentication, if user enabled it
|
||||
err := setupClientAuth(tlsConfigs, s.TLSConfig)
|
||||
if err != nil {
|
||||
defer close(s.startChan)
|
||||
return err
|
||||
}
|
||||
|
||||
// Create TLS listener - note that we do not replace s.listener
|
||||
// with this TLS listener; tls.listener is unexported and does
|
||||
// not implement the File() method we need for graceful restarts
|
||||
// on POSIX systems.
|
||||
ln = tls.NewListener(ln, s.TLSConfig)
|
||||
|
||||
close(s.startChan) // unblock anyone waiting for this to start listening
|
||||
return s.Serve(ln)
|
||||
}
|
||||
*/
|
||||
|
||||
// Stop stops the server. It blocks until the server is
|
||||
// totally stopped. On POSIX systems, it will wait for
|
||||
// connections to close (up to a max timeout of a few
|
||||
// seconds); on Windows it will close the listener
|
||||
// immediately.
|
||||
func (s *Server) Stop() (err error) {
|
||||
|
||||
if runtime.GOOS != "windows" {
|
||||
// force connections to close after timeout
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
s.dnsWg.Done() // decrement our initial increment used as a barrier
|
||||
s.dnsWg.Wait()
|
||||
close(done)
|
||||
}()
|
||||
|
||||
// Wait for remaining connections to finish or
|
||||
// force them all to close after timeout
|
||||
select {
|
||||
case <-time.After(s.connTimeout):
|
||||
case <-done:
|
||||
}
|
||||
}
|
||||
|
||||
// Close the listener now; this stops the server without delay
|
||||
s.listenerMu.Lock()
|
||||
defer s.listenerMu.Unlock()
|
||||
|
||||
for _, s1 := range s.server {
|
||||
if s1.Listener != nil {
|
||||
err = s1.Listener.Close()
|
||||
}
|
||||
if s1.PacketConn != nil {
|
||||
err = s1.PacketConn.Close()
|
||||
}
|
||||
err = s1.Shutdown()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// WaitUntilStarted blocks until the server s is started, meaning
|
||||
// that practically the next instruction is to start the server loop.
|
||||
// It also unblocks if the server encounters an error during startup.
|
||||
func (s *Server) WaitUntilStarted() {
|
||||
<-s.startChan
|
||||
}
|
||||
|
||||
// ListenerFd gets a dup'ed file of the listener. If there
|
||||
// is no underlying file, the return value will be nil. It
|
||||
// is the caller's responsibility to close the file.
|
||||
func (s *Server) ListenerFd() *os.File {
|
||||
s.listenerMu.Lock()
|
||||
defer s.listenerMu.Unlock()
|
||||
if s.server[0].Listener != nil {
|
||||
file, _ := s.server[0].Listener.(*net.TCPListener).File()
|
||||
return file
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PacketConnFd gets a dup'ed file of the packetconn. If there
|
||||
// is no underlying file, the return value will be nil. It
|
||||
// is the caller's responsibility to close the file.
|
||||
func (s *Server) PacketConnFd() *os.File {
|
||||
s.listenerMu.Lock()
|
||||
defer s.listenerMu.Unlock()
|
||||
if s.server[1].PacketConn != nil {
|
||||
file, _ := s.server[1].PacketConn.(*net.UDPConn).File()
|
||||
return file
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ServeDNS is the entry point for every request to the address that s
|
||||
// is bound to. It acts as a multiplexer for the requests zonename as
|
||||
// defined in the request so that the correct zone
|
||||
// (configuration and middleware stack) will handle the request.
|
||||
func (s *Server) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
||||
defer func() {
|
||||
// In case the user doesn't enable error middleware, we still
|
||||
// need to make sure that we stay alive up here
|
||||
if rec := recover(); rec != nil {
|
||||
DefaultErrorFunc(w, r, dns.RcodeServerFailure)
|
||||
}
|
||||
}()
|
||||
|
||||
if m, err := middleware.Edns0Version(r); err != nil { // Wrong EDNS version, return at once.
|
||||
rc := middleware.RcodeToString(dns.RcodeBadVers)
|
||||
state := middleware.State{W: w, Req: r}
|
||||
|
||||
metrics.Report(state, metrics.Dropped, rc, m.Len(), time.Now())
|
||||
w.WriteMsg(m)
|
||||
return
|
||||
}
|
||||
|
||||
// Execute the optional request callback if it exists
|
||||
if s.ReqCallback != nil && s.ReqCallback(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
q := r.Question[0].Name
|
||||
b := make([]byte, len(q))
|
||||
off, end := 0, false
|
||||
ctx := context.Background()
|
||||
|
||||
for {
|
||||
l := len(q[off:])
|
||||
for i := 0; i < l; i++ {
|
||||
b[i] = q[off+i]
|
||||
// normalize the name for the lookup
|
||||
if b[i] >= 'A' && b[i] <= 'Z' {
|
||||
b[i] |= ('a' - 'A')
|
||||
}
|
||||
}
|
||||
|
||||
if h, ok := s.zones[string(b[:l])]; ok {
|
||||
if r.Question[0].Qtype != dns.TypeDS {
|
||||
rcode, _ := h.stack.ServeDNS(ctx, w, r)
|
||||
if RcodeNoClientWrite(rcode) {
|
||||
DefaultErrorFunc(w, r, rcode)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
off, end = dns.NextLabel(q, off)
|
||||
if end {
|
||||
break
|
||||
}
|
||||
}
|
||||
// Wildcard match, if we have found nothing try the root zone as a last resort.
|
||||
if h, ok := s.zones["."]; ok {
|
||||
rcode, _ := h.stack.ServeDNS(ctx, w, r)
|
||||
if RcodeNoClientWrite(rcode) {
|
||||
DefaultErrorFunc(w, r, rcode)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Still here? Error out with REFUSED and some logging
|
||||
remoteHost := w.RemoteAddr().String()
|
||||
DefaultErrorFunc(w, r, dns.RcodeRefused)
|
||||
log.Printf("[INFO] \"%s %s %s\" - No such zone at %s (Remote: %s)", dns.Type(r.Question[0].Qtype), dns.Class(r.Question[0].Qclass), q, s.Addr, remoteHost)
|
||||
}
|
||||
|
||||
// DefaultErrorFunc responds to an DNS request with an error.
|
||||
func DefaultErrorFunc(w dns.ResponseWriter, r *dns.Msg, rcode int) {
|
||||
state := middleware.State{W: w, Req: r}
|
||||
rc := middleware.RcodeToString(rcode)
|
||||
|
||||
answer := new(dns.Msg)
|
||||
answer.SetRcode(r, rcode)
|
||||
state.SizeAndDo(answer)
|
||||
|
||||
metrics.Report(state, metrics.Dropped, rc, answer.Len(), time.Now())
|
||||
w.WriteMsg(answer)
|
||||
}
|
||||
|
||||
// setupClientAuth sets up TLS client authentication only if
|
||||
// any of the TLS configs specified at least one cert file.
|
||||
func setupClientAuth(tlsConfigs []TLSConfig, config *tls.Config) error {
|
||||
var clientAuth bool
|
||||
for _, cfg := range tlsConfigs {
|
||||
if len(cfg.ClientCerts) > 0 {
|
||||
clientAuth = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if clientAuth {
|
||||
pool := x509.NewCertPool()
|
||||
for _, cfg := range tlsConfigs {
|
||||
for _, caFile := range cfg.ClientCerts {
|
||||
caCrt, err := ioutil.ReadFile(caFile) // Anyone that gets a cert from this CA can connect
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !pool.AppendCertsFromPEM(caCrt) {
|
||||
return fmt.Errorf("error loading client certificate '%s': no certificates were successfully parsed", caFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
config.ClientCAs = pool
|
||||
config.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunFirstStartupFuncs runs all of the server's FirstStartup
|
||||
// callback functions unless one of them returns an error first.
|
||||
// It is the caller's responsibility to call this only once and
|
||||
// at the correct time. The functions here should not be executed
|
||||
// at restarts or where the user does not explicitly start a new
|
||||
// instance of the server.
|
||||
func (s *Server) RunFirstStartupFuncs() error {
|
||||
for _, z := range s.zones {
|
||||
for _, f := range z.config.FirstStartup {
|
||||
if err := f(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ShutdownCallbacks executes all the shutdown callbacks
|
||||
// for all the virtualhosts in servers, and returns all the
|
||||
// errors generated during their execution. In other words,
|
||||
// an error executing one shutdown callback does not stop
|
||||
// execution of others. Only one shutdown callback is executed
|
||||
// at a time. You must protect the servers that are passed in
|
||||
// if they are shared across threads.
|
||||
func ShutdownCallbacks(servers []*Server) []error {
|
||||
var errs []error
|
||||
for _, s := range servers {
|
||||
for _, zone := range s.zones {
|
||||
for _, shutdownFunc := range zone.config.Shutdown {
|
||||
err := shutdownFunc()
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
func StartupCallbacks(servers []*Server) []error {
|
||||
var errs []error
|
||||
for _, s := range servers {
|
||||
for _, zone := range s.zones {
|
||||
for _, startupFunc := range zone.config.Startup {
|
||||
err := startupFunc()
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
func RcodeNoClientWrite(rcode int) bool {
|
||||
switch rcode {
|
||||
case dns.RcodeServerFailure:
|
||||
fallthrough
|
||||
case dns.RcodeRefused:
|
||||
fallthrough
|
||||
case dns.RcodeFormatError:
|
||||
fallthrough
|
||||
case dns.RcodeNotImplemented:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package server
|
||||
|
||||
import "github.com/miekg/coredns/middleware"
|
||||
|
||||
// zone represents a DNS zone. While a Server
|
||||
// is what actually binds to the address, a user may want to serve
|
||||
// multiple zones on a single address, and this is what a
|
||||
// zone allows us to do.
|
||||
type zone struct {
|
||||
config Config
|
||||
stack middleware.Handler
|
||||
}
|
||||
|
||||
// buildStack builds the server's middleware stack based
|
||||
// on its config. This method should be called last before
|
||||
// ListenAndServe begins.
|
||||
func (z *zone) buildStack() error {
|
||||
z.compile(z.config.Middleware)
|
||||
return nil
|
||||
}
|
||||
|
||||
// compile is an elegant alternative to nesting middleware function
|
||||
// calls like handler1(handler2(handler3(finalHandler))).
|
||||
func (z *zone) compile(layers []middleware.Middleware) {
|
||||
for i := len(layers) - 1; i >= 0; i-- {
|
||||
z.stack = layers[i](z.stack)
|
||||
}
|
||||
}
|
|
@ -77,10 +77,10 @@ func TestEtcdStubAndProxyLookup(t *testing.T) {
|
|||
t.Error("Expected to at least one RR in the answer section, got none")
|
||||
}
|
||||
if resp.Answer[0].Header().Rrtype != dns.TypeA {
|
||||
t.Error("Expected RR to A, got: %d", resp.Answer[0].Header().Rrtype)
|
||||
t.Errorf("Expected RR to A, got: %d", resp.Answer[0].Header().Rrtype)
|
||||
}
|
||||
if resp.Answer[0].(*dns.A).A.String() != "93.184.216.34" {
|
||||
t.Error("Expected 93.184.216.34, got: %d", resp.Answer[0].(*dns.A).A.String())
|
||||
t.Errorf("Expected 93.184.216.34, got: %d", resp.Answer[0].(*dns.A).A.String())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@ import (
|
|||
"log"
|
||||
"testing"
|
||||
|
||||
"github.com/miekg/coredns/middleware/kubernetes/k8stest"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
|
@ -63,17 +61,13 @@ var testdataLookupSRV = []struct {
|
|||
{"*.*.coredns.local.", 1, 1}, // One SRV record, via namespace and service wildcard
|
||||
}
|
||||
|
||||
func TestK8sIntegration(t *testing.T) {
|
||||
func testK8sIntegration(t *testing.T) {
|
||||
// subtests here (Go 1.7 feature).
|
||||
testLookupA(t)
|
||||
testLookupSRV(t)
|
||||
}
|
||||
|
||||
func testLookupA(t *testing.T) {
|
||||
if !k8stest.CheckKubernetesRunning() {
|
||||
t.Skip("Skipping Kubernetes Integration tests. Kubernetes is not running")
|
||||
}
|
||||
|
||||
corefile :=
|
||||
`.:0 {
|
||||
kubernetes coredns.local {
|
||||
|
@ -104,7 +98,7 @@ func testLookupA(t *testing.T) {
|
|||
|
||||
res, _, err := dnsClient.Exchange(dnsMessage, udp)
|
||||
if err != nil {
|
||||
t.Fatal("Could not send query: %s", err)
|
||||
t.Fatalf("Could not send query: %s", err)
|
||||
}
|
||||
// Count A records in the answer section
|
||||
ARecordCount := 0
|
||||
|
@ -124,10 +118,6 @@ func testLookupA(t *testing.T) {
|
|||
}
|
||||
|
||||
func testLookupSRV(t *testing.T) {
|
||||
if !k8stest.CheckKubernetesRunning() {
|
||||
t.Skip("Skipping Kubernetes Integration tests. Kubernetes is not running")
|
||||
}
|
||||
|
||||
corefile :=
|
||||
`.:0 {
|
||||
kubernetes coredns.local {
|
||||
|
@ -159,7 +149,7 @@ func testLookupSRV(t *testing.T) {
|
|||
|
||||
res, _, err := dnsClient.Exchange(dnsMessage, udp)
|
||||
if err != nil {
|
||||
t.Fatal("Could not send query: %s", err)
|
||||
t.Fatalf("Could not send query: %s", err)
|
||||
}
|
||||
// Count SRV records in the answer section
|
||||
srvRecordCount := 0
|
||||
|
|
|
@ -56,9 +56,9 @@ func TestLookupProxy(t *testing.T) {
|
|||
t.Error("Expected to at least one RR in the answer section, got none")
|
||||
}
|
||||
if resp.Answer[0].Header().Rrtype != dns.TypeA {
|
||||
t.Error("Expected RR to A, got: %d", resp.Answer[0].Header().Rrtype)
|
||||
t.Errorf("Expected RR to A, got: %d", resp.Answer[0].Header().Rrtype)
|
||||
}
|
||||
if resp.Answer[0].(*dns.A).A.String() != "127.0.0.1" {
|
||||
t.Error("Expected 127.0.0.1, got: %d", resp.Answer[0].(*dns.A).A.String())
|
||||
t.Errorf("Expected 127.0.0.1, got: %d", resp.Answer[0].(*dns.A).A.String())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue