-
Notifications
You must be signed in to change notification settings - Fork 4.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Query node_meta info using DNS TXT query API #3343
Conversation
switch { | ||
case ipv4 != nil && (qType == dns.TypeANY || qType == dns.TypeA): | ||
return []dns.RR{&dns.A{ | ||
records = append(records, &dns.A{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have to append in order to support ANY queries when the node also has metadata key-values
@@ -57,8 +57,9 @@ we can instead use `foo.node.consul.` This convention allows for terse | |||
syntax where appropriate while supporting queries of nodes in remote | |||
datacenters as necessary. | |||
|
|||
For a node lookup, the only records returned are A records containing | |||
the IP address of the node. | |||
For a node lookup, the only records returned are A and AAAA records |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added language for 'AAAA' records as well since it is in available in the code. Feel free to remove that in case it is not officially supported yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would you like your feedback on this PR when you get a chance.
I can have a look at this since I'm in that codepath right now. Please note that we will merge #3353 first. |
The changes were in more places than I thought, it will take some time to fix. |
@magiconair, In order to solve this conflict, I will likely need to change every call to formatNodeRecord to include Please advise if you are okay with that change. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Include justification for changing the formatNodeRecord signature back to 0.9.0 branch.
agent/dns.go
Outdated
@@ -320,7 +320,7 @@ func (d *DNSServer) nameservers(edns bool) (ns []dns.RR, extra []dns.RR) { | |||
ns = append(ns, nsrr) | |||
|
|||
// A or AAAA glue record | |||
glue := d.formatNodeRecord(ip.String(), name, dns.TypeANY, d.config.NodeTTL, edns) | |||
glue := d.formatNodeRecord(nil, ip.String(), name, dns.TypeANY, d.config.NodeTTL, edns) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Undo formatNodeRecord
change from commit 76319f7
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function signature is starting to get a bit out of hand but that's a story for another day.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed node from there in that commit because it was an unused param. why are we adding it back?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because he needs it to get to the meta data of the node. We might also just pass the map in.
@@ -509,45 +509,58 @@ RPC: | |||
n := out.NodeServices.Node | |||
edns := req.IsEdns0() != nil | |||
addr := d.agent.TranslateAddress(datacenter, n.Address, n.TaggedAddresses) | |||
records := d.formatNodeRecord(addr, req.Question[0].Name, qType, d.config.NodeTTL, edns) | |||
records := d.formatNodeRecord(out.NodeServices.Node, addr, req.Question[0].Name, qType, d.config.NodeTTL, edns) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Undo formatNodeRecord
change from commit 76319f7
agent/dns.go
Outdated
} | ||
|
||
// formatNodeRecord takes a Node and returns an A, AAAA, TXT or CNAME record | ||
func (d *DNSServer) formatNodeRecord(node *structs.Node, addr, qName string, qType uint16, ttl time.Duration, edns bool) (records []dns.RR) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Undo formatNodeRecord
change from commit 76319f7
agent/dns.go
Outdated
@@ -575,6 +588,21 @@ func (d *DNSServer) formatNodeRecord(addr, qName string, qType uint16, ttl time. | |||
} | |||
} | |||
} | |||
|
|||
if node != nil && len(node.Meta) > 0 && (qType == dns.TypeANY || qType == dns.TypeTXT) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add test in case we are called from line 323.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
len(node.Meta) > 0
is redundant
@@ -896,7 +924,7 @@ func (d *DNSServer) serviceNodeRecords(dc string, nodes structs.CheckServiceNode | |||
handled[addr] = struct{}{} | |||
|
|||
// Add the node record | |||
records := d.formatNodeRecord(addr, qName, qType, ttl, edns) | |||
records := d.formatNodeRecord(node.Node, addr, qName, qType, ttl, edns) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Undo formatNodeRecord
change from commit 76319f7
@@ -940,7 +968,7 @@ func (d *DNSServer) serviceSRVRecords(dc string, nodes structs.CheckServiceNodes | |||
} | |||
|
|||
// Add the extra record | |||
records := d.formatNodeRecord(addr, srvRec.Target, dns.TypeANY, ttl, edns) | |||
records := d.formatNodeRecord(node.Node, addr, srvRec.Target, dns.TypeANY, ttl, edns) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Undo formatNodeRecord
change from commit 76319f7
This is ready for review again. |
agent/dns.go
Outdated
if records != nil { | ||
resp.Answer = append(resp.Answer, records...) | ||
} | ||
} | ||
|
||
// formatNodeRecord takes a Node and returns an A, AAAA, or CNAME record | ||
func (d *DNSServer) formatNodeRecord(addr, qName string, qType uint16, ttl time.Duration, edns bool) (records []dns.RR) { | ||
// formatTxtRecords takes a kv-map and returns it as "[k=]v" for non-empty k not starting with rfc1035- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- I'd suggest that you describe what the function does and not how it does that, e.g.
formatTxtRecords encodes the map values according to RFC 1464.
-
formatTxtRecords
isn't a good name since it doesn't return records ([]*dns.RR
) but only the values ofTXT
records. Maybe name itencodeKVasRFC1464
or something similar. I didn't think this all the way through but you should get the drift. -
The comment does not match the code since
k
can be empty and you'd end up with=v
. -
RFC 1464 says that key names with special characters must be encoded:
https://www.ietf.org/rfc/rfc1464.txt
Attribute Names
Any printable ASCII character is permitted for the attribute name.
If an equals sign is embedded in the attribute name, it must be
quoted with a preceding grave accent (or backquote:"`"
). A
backquote must also be quoted with an additional"`"
.
also further down:
Leading and trailing whitespace (spaces and tabs) in the attribute
name are ignored unless they are quoted (with a ""). For example, "abc" matches " abc<tab>" but does not match ``"
abc"``.Note that most DNS server implementations require a backslash () or
double quote (") in a text string to be quoted with a preceding
backslash. Accent grave ("`"
) was chosen as a quoting character in
this syntax to avoid confusion with "" (and remove the need for
confusing strings that include sequences like "\\").
and
Attribute Values
All printable ASCII characters are permitted in the attribute value.
No characters need to be quoted with a "`". In other words, the
first unquoted equals sign in the TXT record is the name/value
delimiter. All subsequent characters are part of the value.Once again, note that in most implementations the backslash character
is an active quoting character (and must, itself, be quoted).
-
I'd prefer a
switch
statement overif/else
-
Please add a table driven test for this function especially the edge cases
-
When looking at Feature request: DNS TXT resource records #2709 I've noticed the use of
datacenter
in the example. Would that be the consul datacenter value and if yes how does this get in here? We may want to think about some expansion language like${DC}
or similar to fill in values from the other consul node data but that may be overkill.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR only closes the TXT lookup side for Nodes. I am open to suggestions on how to solve it at the datacenter level.
My initial thought was to use the KV system, but that looked like too much of a hack.
Are there any plans to make data-center level metadata values available?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was referring to a value containing the configured datacenter of consul. Lets consider this when it is requested and get this one done first.
agent/dns.go
Outdated
@@ -575,6 +588,21 @@ func (d *DNSServer) formatNodeRecord(addr, qName string, qType uint16, ttl time. | |||
} | |||
} | |||
} | |||
|
|||
if node != nil && len(node.Meta) > 0 && (qType == dns.TypeANY || qType == dns.TypeTXT) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
len(node.Meta) > 0
is redundant
t.Fatalf("err: %v", err) | ||
} | ||
|
||
// Should have the 1 TXT record reply |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pls use verify.Values
to compare full responses, if possible.
agent/dns_test.go
Outdated
} | ||
|
||
// Should have 1 A and 1 TXT record | ||
if len(in.Answer) != 2 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pls verify.Values
, if possible.
agent/dns_test.go
Outdated
@@ -334,8 +347,8 @@ func TestDNS_NodeLookup_CNAME(t *testing.T) { | |||
t.Fatalf("err: %v", err) | |||
} | |||
|
|||
// Should have the service record, CNAME record + A record | |||
if len(in.Answer) != 3 { | |||
// Should have the service record, CNAME record + A + TXT record |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should have the service, CNAME, A, and TXT records
agent/dns.go
Outdated
@@ -320,7 +320,7 @@ func (d *DNSServer) nameservers(edns bool) (ns []dns.RR, extra []dns.RR) { | |||
ns = append(ns, nsrr) | |||
|
|||
// A or AAAA glue record | |||
glue := d.formatNodeRecord(ip.String(), name, dns.TypeANY, d.config.NodeTTL, edns) | |||
glue := d.formatNodeRecord(nil, ip.String(), name, dns.TypeANY, d.config.NodeTTL, edns) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function signature is starting to get a bit out of hand but that's a story for another day.
agent/dns.go
Outdated
@@ -464,9 +464,9 @@ INVALID: | |||
|
|||
// nodeLookup is used to handle a node query | |||
func (d *DNSServer) nodeLookup(network, datacenter, node string, req, resp *dns.Msg) { | |||
// Only handle ANY, A and AAAA type requests | |||
// Only handle ANY, A, AAAA and TXT type requests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oxford comma?
- Add explanation to the difference between RFC1035 and RFC1464 queries.
- Lookup TXT records using recursive lookups - Expect TXT record equal to value if key starts with rfc1035- - Expect TXT record in rfc1464 otherwise, i.e. (k=v) ref #2709
- Move the logic of rfc1035 out of the encoding function - Left basic version of encodingKV as 'k=v'
I added the tests from RFC1464. |
@magiconair Thanks! |
@sodre I didn't get a chance to review your latest changes yet. I'll ping you when I'm done. If you want and there are no changes then I can do the re-order squash for you if you let me know what you want to do. |
@magiconair |
Hi @sodre, sorry for the delay. I was on vacation for a couple of weeks and have two large things I'm working on right now. That's why I'm avoiding to context switch ATM. I'll try to review it this week. |
I've rebased the code and fixed the tests but I'm not getting the result I thought:
I thought meta keys without a value shouldn't have a trailing |
I've pushed my changes to the https://github.com/hashicorp/consul/tree/zeroae-f-node-dns-txt-record-magiconair branch. I'll see whether I can fix this later today. |
Just re-read https://tools.ietf.org/html/rfc1464 so I think we're good.
|
rebased and merged to master. |
Update CHANGELOG, as GH-3343 references RFC1464 not 1434.
This is the node-part of feature request #2709