-
Notifications
You must be signed in to change notification settings - Fork 123
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add implementation of ordindary DNS provider for query plain old DNS …
…records
- Loading branch information
Showing
5 changed files
with
267 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
cmd/discover/discover | ||
.terraform/ | ||
.terraform.tfstate.lock.info | ||
terraform.tfstate | ||
terraform.tfstate.backup | ||
terraform.tfvars | ||
*~ | ||
*.bak | ||
terraform.* | ||
.terraform.* | ||
|
||
/discover | ||
/cmd/discover/discover |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
// Package dns provides node discovery via DNS. | ||
package dns | ||
|
||
import ( | ||
"fmt" | ||
"io/ioutil" | ||
"log" | ||
"net" | ||
"strconv" | ||
"time" | ||
|
||
"github.com/miekg/dns" | ||
) | ||
|
||
// Provider implements the Provider interface. | ||
type Provider struct{} | ||
|
||
// Help returns help information for the DNS package. | ||
func (p *Provider) Help() string { | ||
return `DNS: | ||
provider: "dns" | ||
query: The DNS query to lookup. Required. | ||
server: The DNS server to query. Default "8.8.8.8" (Google DNS). | ||
port: The DNS port to use. Default: "53" (standard DNS port). | ||
timeout: The mDNS lookup timeout. Default "5s" (five seconds). | ||
` | ||
} | ||
|
||
// Addrs returns discovered addresses for the mDNS package. | ||
func (p *Provider) Addrs(args map[string]string, l *log.Logger) ([]string, error) { | ||
var err error | ||
|
||
// default to null logger | ||
if l == nil { | ||
l = log.New(ioutil.Discard, "", 0) | ||
} | ||
|
||
// validate and set service record | ||
if args["query"] == "" { | ||
return nil, fmt.Errorf("discover-dns: Query not provided." + | ||
" Please specify a valid dns query for the DNS lookup.") | ||
} | ||
|
||
var server string | ||
// validate and set server | ||
if args["server"] != "" { | ||
server = args["server"] | ||
} else { | ||
server = "8.8.8.8" | ||
} | ||
|
||
var port int | ||
// validate and set port | ||
if args["port"] != "" { | ||
if port, err = strconv.Atoi(args["port"]); err != nil { | ||
return nil, fmt.Errorf("discover-dns: Failed to parse port: %s", err) | ||
} | ||
} else { | ||
port = 53 | ||
} | ||
|
||
var timeout time.Duration | ||
// validate and set timeout | ||
if args["timeout"] != "" { | ||
if timeout, err = time.ParseDuration(args["timeout"]); err != nil { | ||
return nil, fmt.Errorf("discover-dns: Failed to parse timeout: %s", err) | ||
} | ||
} else { | ||
timeout = 5 * time.Second | ||
} | ||
|
||
var addrs []string | ||
|
||
// lookup and return | ||
m1 := new(dns.Msg) | ||
m1.Id = dns.Id() | ||
m1.RecursionDesired = true | ||
m1.Question = make([]dns.Question, 1) | ||
m1.Question[0] = dns.Question{args["query"], dns.TypeA, dns.ClassINET} | ||
|
||
c := new(dns.Client) | ||
|
||
laddr := net.UDPAddr{ | ||
IP: net.ParseIP("[::1]"), | ||
Port: 0, | ||
Zone: "", | ||
} | ||
c.Dialer = &net.Dialer{ | ||
Timeout: timeout, | ||
LocalAddr: &laddr, | ||
} | ||
raddr := fmt.Sprintf("%s:%d", server, port) | ||
in, _, err := c.Exchange(m1, raddr) | ||
if err != nil { | ||
return nil, fmt.Errorf("discover-mdns: Failed to process query: %s", err) | ||
} | ||
|
||
for _, answer := range in.Answer { | ||
if t, ok := answer.(*dns.A); ok { | ||
addrs = append(addrs, t.A.String()) | ||
} | ||
} | ||
|
||
return addrs, err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
package dns_test | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"os" | ||
"testing" | ||
|
||
"github.com/miekg/dns" | ||
|
||
discover "github.com/hashicorp/go-discover" | ||
provider "github.com/hashicorp/go-discover/provider/dns" | ||
) | ||
|
||
const ( | ||
testService = "test-service" | ||
) | ||
|
||
var ( | ||
testAddresses = []string{"127.0.0.1"} | ||
) | ||
|
||
func newTestServer() (*dns.Server, error) { | ||
var rr []dns.RR | ||
|
||
for _, testAddress := range testAddresses { | ||
a, _ := dns.NewRR(fmt.Sprintf("tasks.%s. IN A %s", testService, testAddress)) | ||
rr = append(rr, a) | ||
} | ||
|
||
server := &dns.Server{Addr: ":5300", Net: "udp"} | ||
go server.ListenAndServe() | ||
dns.HandleFunc(fmt.Sprintf("tasks.%s.", testService), func(w dns.ResponseWriter, r *dns.Msg) { | ||
m := new(dns.Msg) | ||
m.SetReply(r) | ||
m.Insert(rr) | ||
w.WriteMsg(m) | ||
}) | ||
|
||
return server, nil | ||
} | ||
|
||
func TestDiscover(t *testing.T) { | ||
type testCases []struct { | ||
desc string | ||
args discover.Config | ||
fail bool | ||
addrs int | ||
} | ||
|
||
cases := testCases{ | ||
{ | ||
"valid config - no addresses", | ||
discover.Config{ | ||
"provider": "dns", | ||
"query": "tasks.fake-service", | ||
"timeout": "1s", | ||
"v6": "false", | ||
"v4": "false", | ||
}, | ||
false, | ||
0, | ||
}, | ||
{ | ||
"valid config - one address", | ||
discover.Config{ | ||
"provider": "dns", | ||
"query": "tasks.test-service", | ||
"timeout": "10s", | ||
"v6": "true", | ||
"v4": "true", | ||
}, | ||
false, | ||
1, | ||
}, | ||
{ | ||
"invalid config - missing query option", | ||
discover.Config{ | ||
"provider": "dns", | ||
"query": "", | ||
"timeout": "1s", | ||
"v6": "false", | ||
"v4": "false", | ||
}, | ||
true, | ||
0, | ||
}, | ||
{ | ||
"invalid config - bad timeout option", | ||
discover.Config{ | ||
"provider": "dns", | ||
"query": "tasks.fake-service", | ||
"timeout": "1z", | ||
"v6": "false", | ||
"v4": "false", | ||
}, | ||
true, | ||
0, | ||
}, | ||
{ | ||
"invalid config - bad v6 option", | ||
discover.Config{ | ||
"provider": "dns", | ||
"service": "tasks.fake-service", | ||
"timeout": "1s", | ||
"v6": "xxxx", | ||
"v4": "false", | ||
}, | ||
true, | ||
0, | ||
}, | ||
{ | ||
"invalid config - bad v4 option", | ||
discover.Config{ | ||
"provider": "dns", | ||
"service": "tasks.fake-service", | ||
"timeout": "1s", | ||
"v6": "false", | ||
"v4": "xxxx", | ||
}, | ||
true, | ||
0, | ||
}, | ||
} | ||
|
||
p := &provider.Provider{} | ||
l := log.New(os.Stderr, "", log.LstdFlags) | ||
|
||
svr, err := newTestServer() | ||
if err != nil { | ||
t.Fatalf("Failed to start test server: %s", err.Error()) | ||
return | ||
} | ||
defer svr.Shutdown() | ||
|
||
for idx, tc := range cases { | ||
addrs, err := p.Addrs(tc.args, l) | ||
|
||
if !tc.fail && err != nil { | ||
t.Fatalf("FAIL [%d/%d] %s -> %s", | ||
idx, len(cases), tc.desc, err) | ||
} | ||
|
||
if len(addrs) != tc.addrs { | ||
t.Fatalf("FAIL [%d/%d] %s -> wrong addr count: expected %d / got %d", | ||
idx, len(cases), tc.desc, tc.addrs, len(addrs)) | ||
} | ||
|
||
t.Logf("PASS [%d/%d] %s", idx, len(cases), tc.desc) | ||
} | ||
} |