Переглянути джерело

Add a health RR

Add a RR which returns the health status of a record, for debugging
purposes. This returns in JSON format the health record of all
the records associated with a label if a health test is running.

Example follows.

$ dig -p 10053 TXT _health.foo.example2.com @127.0.0.1

; <<>> DiG 9.8.3-P1 <<>> -p 10053 TXT _health.foo.example2.com @127.0.0.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59545
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;_health.foo.example2.com.	IN	TXT

;; ANSWER SECTION:
_health.foo.example2.com. 1	IN	TXT	"{\"A\":{\"192.168.1.2\":false,\"192.168.1.3\":false,\"192.168.1.4\":false},\"AAAA\":{\"fd06:c1d3:e902:202:a5ff:fecd:13a6:a\":false,\"fd06:c1d3:e902::2\":false,\"fd06:c1d3:e902::4\":false}}"

;; Query time: 1 msec
;; SERVER: 127.0.0.1#10053(127.0.0.1)
;; WHEN: Wed Sep  2 19:24:01 2015
;; MSG SIZE  rcvd: 251

Decoding that JSON:

{
   "A" : {
      "192.168.1.4" : false,
      "192.168.1.3" : false,
      "192.168.1.2" : false
   },
   "AAAA" : {
      "fd06:c1d3:e902:202:a5ff:fecd:13a6:a" : false,
      "fd06:c1d3:e902::4" : false,
      "fd06:c1d3:e902::2" : false
   }
}

Signed-off-by: Alex Bligh <[email protected]>
Alex Bligh 10 роки тому
батько
коміт
a4420a9e47
1 змінених файлів з 39 додано та 0 видалено
  1. 39 0
      serve.go

+ 39 - 0
serve.go

@@ -123,6 +123,20 @@ func serve(w dns.ResponseWriter, req *dns.Msg, z *Zone) {
 			return
 		}
 
+		if permitDebug && firstLabel == "_health" {
+			if qtype == dns.TypeANY || qtype == dns.TypeTXT {
+				baseLabel := strings.Join((strings.Split(label, "."))[1:], ".")
+				m.Answer = z.healthRR(label+"."+z.Origin+".", baseLabel)
+				m.Authoritative = true
+				w.WriteMsg(m)
+				return
+			}
+			m.Ns = append(m.Ns, z.SoaRR())
+			m.Authoritative = true
+			w.WriteMsg(m)
+			return
+		}
+
 		if firstLabel == "_country" {
 			if qtype == dns.TypeANY || qtype == dns.TypeTXT {
 				h := dns.RR_Header{Ttl: 1, Class: dns.ClassINET, Rrtype: dns.TypeTXT}
@@ -214,6 +228,31 @@ func statusRR(label string) []dns.RR {
 	return []dns.RR{&dns.TXT{Hdr: h, Txt: []string{string(js)}}}
 }
 
+func (z *Zone) healthRR(label string, baseLabel string) []dns.RR {
+	h := dns.RR_Header{Ttl: 1, Class: dns.ClassINET, Rrtype: dns.TypeTXT}
+	h.Name = label
+
+	health := make(map[string]map[string]bool)
+
+	if l, ok := z.Labels[baseLabel]; ok {
+		for qt, records := range l.Records {
+			if qts, ok := dns.TypeToString[qt]; ok {
+				hmap := make(map[string]bool)
+				for _, record := range records {
+					if record.Test != nil {
+						hmap[(*record.Test).ipAddress.String()] = healthTestRunner.isHealthy(record.Test)
+					}
+				}
+				health[qts] = hmap
+			}
+		}
+	}
+
+	js, _ := json.Marshal(health)
+
+	return []dns.RR{&dns.TXT{Hdr: h, Txt: []string{string(js)}}}
+}
+
 func setupServerFunc(Zone *Zone) func(dns.ResponseWriter, *dns.Msg) {
 	return func(w dns.ResponseWriter, r *dns.Msg) {
 		serve(w, r, Zone)