]>
Commit | Line | Data |
---|---|---|
8bdce29f RG |
1 | #!/usr/bin/env python |
2 | ||
3 | import os | |
4 | import requests | |
5 | import socket | |
6 | import threading | |
7 | import unittest | |
8 | import dns | |
630eb526 | 9 | from dnsdisttests import DNSDistTest, pickAvailablePort |
8bdce29f | 10 | |
bd5a0bc6 | 11 | class RuleMetricsTest(object): |
8bdce29f RG |
12 | |
13 | _config_template = """ | |
c673ba85 RG |
14 | addTLSLocal("127.0.0.1:%s", "%s", "%s", { provider="openssl" }) |
15 | addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/"}) | |
16 | ||
17 | newServer{address="127.0.0.1:%s", pool={'', 'cache'}} | |
8bdce29f RG |
18 | webserver("127.0.0.1:%s") |
19 | setWebserverConfig({apiKey="%s"}) | |
20 | ||
21 | addAction('rcode-nxdomain.metrics.tests.powerdns.com', RCodeAction(DNSRCode.NXDOMAIN)) | |
22 | addAction('rcode-refused.metrics.tests.powerdns.com', RCodeAction(DNSRCode.REFUSED)) | |
23 | addAction('rcode-servfail.metrics.tests.powerdns.com', RCodeAction(DNSRCode.SERVFAIL)) | |
c673ba85 RG |
24 | |
25 | pc = newPacketCache(100) | |
26 | getPool('cache'):setCache(pc) | |
27 | addAction('cache.metrics.tests.powerdns.com', PoolAction('cache')) | |
8bdce29f RG |
28 | """ |
29 | _webTimeout = 2.0 | |
630eb526 | 30 | _webServerPort = pickAvailablePort() |
8bdce29f RG |
31 | _webServerAPIKey = 'apisecret' |
32 | _webServerAPIKeyHashed = '$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso=' | |
c673ba85 RG |
33 | _serverKey = 'server.key' |
34 | _serverCert = 'server.chain' | |
35 | _serverName = 'tls.tests.dnsdist.org' | |
36 | _caCert = 'ca.pem' | |
630eb526 RG |
37 | _tlsServerPort = pickAvailablePort() |
38 | _dohServerPort = pickAvailablePort() | |
c673ba85 RG |
39 | _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort)) |
40 | _config_params = ['_tlsServerPort', '_serverCert', '_serverKey', '_dohServerPort', '_serverCert', '_serverKey', '_testServerPort', '_webServerPort', '_webServerAPIKeyHashed'] | |
8bdce29f | 41 | |
648edcba RG |
42 | @classmethod |
43 | def setUpClass(cls): | |
44 | cls.startResponders() | |
45 | cls.startDNSDist() | |
46 | cls.setUpSockets() | |
47 | cls.waitForTCPSocket('127.0.0.1', cls._webServerPort) | |
48 | print("Launching tests..") | |
49 | ||
8bdce29f RG |
50 | def getMetric(self, name): |
51 | headers = {'x-api-key': self._webServerAPIKey} | |
52 | url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost' | |
53 | r = requests.get(url, headers=headers, timeout=self._webTimeout) | |
54 | self.assertTrue(r) | |
55 | self.assertEqual(r.status_code, 200) | |
56 | self.assertTrue(r.json()) | |
57 | content = r.json() | |
58 | stats = content['statistics'] | |
59 | self.assertIn(name, stats) | |
60 | return int(stats[name]) | |
61 | ||
bc4d98b7 RG |
62 | def getPoolMetric(self, poolName, metricName): |
63 | headers = {'x-api-key': self._webServerAPIKey} | |
64 | url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost/pool?name=' + poolName | |
65 | r = requests.get(url, headers=headers, timeout=self._webTimeout) | |
66 | self.assertTrue(r) | |
67 | self.assertEqual(r.status_code, 200) | |
68 | self.assertTrue(r.json()) | |
69 | content = r.json() | |
70 | stats = content['stats'] | |
71 | self.assertIn(metricName, stats) | |
72 | return int(stats[metricName]) | |
73 | ||
8bdce29f RG |
74 | def testRCodeIncreaseMetrics(self): |
75 | """ | |
76 | Metrics: Check that metrics are correctly updated for RCodeAction | |
77 | """ | |
78 | rcodes = [ | |
79 | ( 'nxdomain', dns.rcode.NXDOMAIN ), | |
80 | ( 'refused', dns.rcode.REFUSED ), | |
81 | ( 'servfail', dns.rcode.SERVFAIL ) | |
82 | ] | |
fd42420e RG |
83 | servfailBackendResponses = self.getMetric('servfail-responses') |
84 | ||
8bdce29f RG |
85 | for (name, rcode) in rcodes: |
86 | qname = 'rcode-' + name + '.metrics.tests.powerdns.com.' | |
87 | query = dns.message.make_query(qname, 'A', 'IN') | |
88 | # dnsdist set RA = RD for spoofed responses | |
89 | query.flags &= ~dns.flags.RD | |
90 | expectedResponse = dns.message.make_response(query) | |
91 | expectedResponse.set_rcode(rcode) | |
92 | ||
fd42420e RG |
93 | ruleMetricBefore = self.getMetric('rule-' + name) |
94 | if name != 'refused': | |
95 | frontendMetricBefore = self.getMetric('frontend-' + name) | |
96 | ||
8bdce29f RG |
97 | for method in ("sendUDPQuery", "sendTCPQuery"): |
98 | sender = getattr(self, method) | |
99 | (_, receivedResponse) = sender(query, response=None, useQueue=False) | |
100 | self.assertEqual(receivedResponse, expectedResponse) | |
101 | ||
fd42420e RG |
102 | self.assertEqual(self.getMetric('rule-' + name), ruleMetricBefore + 2) |
103 | if name != 'refused': | |
104 | self.assertEqual(self.getMetric('frontend-' + name), frontendMetricBefore + 2) | |
c673ba85 | 105 | |
fd42420e RG |
106 | # self-generated responses should not increase this metric |
107 | self.assertEqual(self.getMetric('servfail-responses'), servfailBackendResponses) | |
bc4d98b7 | 108 | |
c673ba85 RG |
109 | def testCacheMetrics(self): |
110 | """ | |
111 | Metrics: Check that metrics are correctly updated for cache misses and hits | |
112 | """ | |
113 | ||
114 | for method in ("sendUDPQuery", "sendTCPQuery", "sendDOTQueryWrapper", "sendDOHQueryWrapper"): | |
115 | qname = method + '.cache.metrics.tests.powerdns.com.' | |
116 | query = dns.message.make_query(qname, 'A', 'IN') | |
117 | # dnsdist set RA = RD for spoofed responses | |
118 | query.flags &= ~dns.flags.RD | |
119 | response = dns.message.make_response(query) | |
120 | rrset = dns.rrset.from_text(qname, | |
121 | 3600, | |
122 | dns.rdataclass.IN, | |
123 | dns.rdatatype.A, | |
124 | '127.0.0.1') | |
125 | response.answer.append(rrset) | |
126 | ||
127 | responsesBefore = self.getMetric('responses') | |
128 | cacheHitsBefore = self.getMetric('cache-hits') | |
129 | cacheMissesBefore = self.getMetric('cache-misses') | |
bc4d98b7 RG |
130 | poolCacheHitsBefore = self.getPoolMetric('cache', 'cacheHits') |
131 | poolCacheMissesBefore = self.getPoolMetric('cache', 'cacheMisses') | |
c673ba85 RG |
132 | |
133 | sender = getattr(self, method) | |
134 | # first time, cache miss | |
135 | (receivedQuery, receivedResponse) = sender(query, response) | |
136 | receivedQuery.id = query.id | |
137 | self.assertEqual(query, receivedQuery) | |
138 | self.assertEqual(receivedResponse, response) | |
139 | # second time, hit | |
140 | (_, receivedResponse) = sender(query, response=None, useQueue=False) | |
141 | self.assertEqual(receivedResponse, response) | |
142 | ||
143 | self.assertEqual(self.getMetric('responses'), responsesBefore + 2) | |
144 | self.assertEqual(self.getMetric('cache-hits'), cacheHitsBefore + 1) | |
145 | self.assertEqual(self.getMetric('cache-misses'), cacheMissesBefore + 1) | |
bc4d98b7 RG |
146 | self.assertEqual(self.getPoolMetric('cache', 'cacheHits'), poolCacheHitsBefore + 1) |
147 | self.assertEqual(self.getPoolMetric('cache', 'cacheMisses'), poolCacheMissesBefore + 1) | |
fd42420e RG |
148 | |
149 | def testServFailMetrics(self): | |
150 | """ | |
cd53a276 | 151 | Metrics: Check that servfail metrics are correctly updated for server failures |
fd42420e RG |
152 | """ |
153 | ||
154 | for method in ("sendUDPQuery", "sendTCPQuery", "sendDOTQueryWrapper", "sendDOHQueryWrapper"): | |
155 | qname = method + '.servfail.cache.metrics.tests.powerdns.com.' | |
156 | query = dns.message.make_query(qname, 'A', 'IN') | |
157 | # dnsdist set RA = RD for spoofed responses | |
158 | query.flags &= ~dns.flags.RD | |
159 | response = dns.message.make_response(query) | |
160 | response.set_rcode(dns.rcode.SERVFAIL) | |
161 | ||
162 | frontendBefore = self.getMetric('frontend-servfail') | |
163 | servfailBefore = self.getMetric('servfail-responses') | |
164 | ruleBefore = self.getMetric('rule-servfail') | |
165 | ||
166 | sender = getattr(self, method) | |
167 | # first time, cache miss | |
168 | (receivedQuery, receivedResponse) = sender(query, response) | |
169 | receivedQuery.id = query.id | |
170 | self.assertEqual(query, receivedQuery) | |
171 | self.assertEqual(receivedResponse, response) | |
172 | # second time, hit | |
173 | (_, receivedResponse) = sender(query, response=None, useQueue=False) | |
174 | self.assertEqual(receivedResponse, response) | |
175 | ||
176 | self.assertEqual(self.getMetric('frontend-servfail'), frontendBefore + 2) | |
177 | self.assertEqual(self.getMetric('servfail-responses'), servfailBefore + 1) | |
178 | self.assertEqual(self.getMetric('rule-servfail'), ruleBefore) | |
bd5a0bc6 RG |
179 | |
180 | class TestRuleMetricsDefault(RuleMetricsTest, DNSDistTest): | |
181 | None | |
182 | ||
183 | class TestRuleMetricsRecvmmsg(RuleMetricsTest, DNSDistTest): | |
184 | # test the metrics with recvmmsg/sendmmsg support enabled as well | |
185 | _config_template = RuleMetricsTest._config_template + """ | |
186 | setUDPMultipleMessagesVectorSize(10) | |
187 | """ |