Merge lp:~jseutter/landscape-client/autodiscover-config into lp:~landscape/landscape-client/trunk
- autodiscover-config
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Chad Smith |
Approved revision: | 457 |
Merged at revision: | 451 |
Proposed branch: | lp:~jseutter/landscape-client/autodiscover-config |
Merge into: | lp:~landscape/landscape-client/trunk |
Diff against target: |
433 lines (+100/-38) 9 files modified
landscape-client.conf (+0/-2) landscape/broker/config.py (+10/-0) landscape/broker/dnslookup.py (+14/-9) landscape/broker/ping.py (+22/-4) landscape/broker/service.py (+6/-2) landscape/broker/tests/test_config.py (+4/-4) landscape/broker/tests/test_dnslookup.py (+22/-13) landscape/broker/tests/test_ping.py (+3/-1) landscape/broker/transport.py (+19/-3) |
To merge this branch: | bzr merge lp:~jseutter/landscape-client/autodiscover-config |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Chad Smith | Approve | ||
Free Ekanayaka (community) | Approve | ||
Review via email: mp+91691@code.launchpad.net |
Commit message
Description of the change
This branch exposes config file settings for server autodiscovery. The autodiscover_
- 455. By Jerry Seutter
-
query strings were being passed incorrectly for client pings.
- 456. By Jerry Seutter
-
Fixed a bug where autodiscovery was unsuccessful for message exchanges.
- 457. By Jerry Seutter
-
Reverting changes to landscape-
client. conf
Chad Smith (chad.smith) wrote : | # |
+1 looks good tests seem to exercise the added config params.
[1] This might be a pain to set up: In transport.py this section of code doesn't seem to have a test case associated with it. I tried mangling the code to throw errors but it doesn't seem to be covered by a test. It'd be nice if we can mock the discover_server call and test _url result or warning messages logged.
if self._server_
result = blockingCallFro
if result is not None:
else:
[2] Maybe a separate MP or maybe we already decided this to be something done during boot. Correct me if this is the wrong thought.
Upon successful auto-discover during PingClient connect, should we write those discovered values to the existing client config file so we don't autodiscover every ping attempt?
def handle_
if result is None:
else:
+? self.autodiscover = False
+? self.url = result
+? configuration.
return result
Preview Diff
1 | === modified file 'landscape-client.conf' |
2 | --- landscape-client.conf 2012-01-21 00:07:53 +0000 |
3 | +++ landscape-client.conf 2012-02-06 22:25:22 +0000 |
4 | @@ -9,5 +9,3 @@ |
5 | log_level = debug |
6 | pid_file = /tmp/landscape/landscape-client.pid |
7 | ping_url = http://localhost:8081/ping |
8 | -server_autodiscover = false |
9 | - |
10 | |
11 | === modified file 'landscape/broker/config.py' |
12 | --- landscape/broker/config.py 2012-02-02 02:49:13 +0000 |
13 | +++ landscape/broker/config.py 2012-02-06 22:25:22 +0000 |
14 | @@ -45,6 +45,9 @@ |
15 | - C{otp} |
16 | - C{record} |
17 | - C{provisioning_otp} |
18 | + - C{server_autodiscover} |
19 | + - C{autodiscover_srv_query_string} |
20 | + - C{autodiscover_a_query_string} |
21 | """ |
22 | parser = super(BrokerConfiguration, self).make_parser() |
23 | |
24 | @@ -91,6 +94,13 @@ |
25 | help="The OTP to use for a provisioned machine.") |
26 | parser.add_option("--server-autodiscover", type="string", |
27 | default="false", help="Enable server autodiscovery.") |
28 | + parser.add_option("--autodiscover-srv-query-string", type="string", |
29 | + default="_tcp._landscape.localdomain", |
30 | + help="autodiscovery string for DNS SRV queries") |
31 | + parser.add_option("--autodiscover-a-query-string", type="string", |
32 | + default="landscape.localdomain", |
33 | + help="autodiscovery string for DNS A queries") |
34 | + |
35 | return parser |
36 | |
37 | @property |
38 | |
39 | === modified file 'landscape/broker/dnslookup.py' |
40 | --- landscape/broker/dnslookup.py 2012-02-02 01:39:15 +0000 |
41 | +++ landscape/broker/dnslookup.py 2012-02-06 22:25:22 +0000 |
42 | @@ -5,31 +5,36 @@ |
43 | from twisted.names.client import Resolver |
44 | |
45 | |
46 | -def discover_server(resolver=None): |
47 | +def discover_server(resolver=None, autodiscover_srv_query_string="", |
48 | + autodiscover_a_query_string=""): |
49 | """ |
50 | Look up the dns location of the landscape server. |
51 | |
52 | @type resolver: The resolver to use. If none is specified a resolver that |
53 | uses settings from /etc/resolv.conf will be created. |
54 | + @param autodiscover_srv_query_string: The query string to send to the DNS |
55 | + server when making a SRV query. |
56 | + @param autodiscover_a_query_string: The query string to send to the DNS |
57 | + server when making a A query. |
58 | """ |
59 | if not resolver: |
60 | resolver = Resolver("/etc/resolv.conf") |
61 | - d = lookup_server_record(resolver) |
62 | - d.addErrback(lookup_hostname, resolver) |
63 | + d = lookup_server_record(resolver, autodiscover_srv_query_string) |
64 | + d.addErrback(lookup_hostname, resolver, autodiscover_a_query_string) |
65 | return d |
66 | |
67 | |
68 | -def lookup_server_record(resolver): |
69 | +def lookup_server_record(resolver, service_name): |
70 | """ |
71 | Do a DNS SRV record lookup for the location of the landscape server. |
72 | |
73 | @type resolver: A resolver to use for DNS lookups |
74 | L{twisted.names.client.Resolver}. |
75 | + @param service_name: The query string to send to the DNS server when |
76 | + making a SRV query. |
77 | @return: A deferred containing either the hostname of the landscape server |
78 | if found or an empty string if not found. |
79 | """ |
80 | - service_name = "_landscape._tcp.mylandscapehost.com" |
81 | - |
82 | def lookup_done(result): |
83 | name = "" |
84 | for item in result: |
85 | @@ -49,17 +54,17 @@ |
86 | return d |
87 | |
88 | |
89 | -def lookup_hostname(result, resolver): |
90 | +def lookup_hostname(result, resolver, hostname): |
91 | """ |
92 | Do a DNS name lookup for the location of the landscape server. |
93 | |
94 | @param result: The result from a call to lookup_server_record. |
95 | @param resolver: The resolver to use for DNS lookups. |
96 | + @param hostname: The query string to send to the DNS server when making |
97 | + a A query. |
98 | @param return: A deferred containing the ip address of the landscape |
99 | server if found or None if not found. |
100 | """ |
101 | - hostname = "landscape.localdomain" |
102 | - |
103 | def lookup_done(result): |
104 | return result |
105 | |
106 | |
107 | === modified file 'landscape/broker/ping.py' |
108 | --- landscape/broker/ping.py 2012-01-27 22:00:02 +0000 |
109 | +++ landscape/broker/ping.py 2012-02-06 22:25:22 +0000 |
110 | @@ -22,10 +22,19 @@ |
111 | @param url: The URL to ask the question to. |
112 | @type identity: L{landscape.broker.registration.Identity} |
113 | @param identity: This client's identity. |
114 | + @param get_page: The method to use to retrieve content. If not specified, |
115 | + landscape.lib.fetch.fetch is used. |
116 | + @param server_autodiscovery: Server autodiscovery is performed if True, |
117 | + otherwise server autodiscover is not done. |
118 | + @param autodiscover_srv_query_string: If server autodiscovery is done, this |
119 | + string will be sent to the DNS server when making a SRV query. |
120 | + @param autodiscover_a_query_string: If server autodiscovery is done, this |
121 | + string will be sent to the DNS server when making an A query. |
122 | """ |
123 | |
124 | def __init__(self, reactor, url, identity, get_page=None, |
125 | - server_autodiscover=False): |
126 | + server_autodiscover=False, autodiscover_srv_query_string="", |
127 | + autodiscover_a_query_string=""): |
128 | if get_page is None: |
129 | get_page = fetch |
130 | self._reactor = reactor |
131 | @@ -33,6 +42,8 @@ |
132 | self.get_page = get_page |
133 | self.url = url |
134 | self._server_autodiscover = server_autodiscover |
135 | + self._autodiscover_srv_query_string = autodiscover_srv_query_string |
136 | + self._autodiscover_a_query_string = autodiscover_a_query_string |
137 | |
138 | def ping(self): |
139 | """Ask the question. |
140 | @@ -72,7 +83,9 @@ |
141 | return defer.succeed(False) |
142 | |
143 | if self._server_autodiscover: |
144 | - lookup_deferred = discover_server() |
145 | + lookup_deferred = discover_server( |
146 | + None, self._autodiscover_srv_query_string, |
147 | + self._autodiscover_a_query_string) |
148 | lookup_deferred.addCallback(handle_result) |
149 | lookup_deferred.addCallback(do_rest) |
150 | return lookup_deferred |
151 | @@ -103,7 +116,8 @@ |
152 | |
153 | def __init__(self, reactor, url, identity, exchanger, |
154 | interval=30, ping_client_factory=PingClient, |
155 | - server_autodiscover=False): |
156 | + server_autodiscover=False, autodiscover_srv_query_string="", |
157 | + autodiscover_a_query_string=""): |
158 | self._url = url |
159 | self._interval = interval |
160 | self._identity = identity |
161 | @@ -113,6 +127,8 @@ |
162 | self._ping_client = None |
163 | self.ping_client_factory = ping_client_factory |
164 | self._server_autodiscover = server_autodiscover |
165 | + self._autodiscover_srv_query_string = autodiscover_srv_query_string |
166 | + self._autodiscover_a_query_string = autodiscover_a_query_string |
167 | reactor.call_on("message", self._handle_set_intervals) |
168 | |
169 | def get_url(self): |
170 | @@ -130,7 +146,9 @@ |
171 | """Start pinging.""" |
172 | self._ping_client = self.ping_client_factory( |
173 | self._reactor, self._url, self._identity, |
174 | - server_autodiscover=self._server_autodiscover) |
175 | + server_autodiscover=self._server_autodiscover, |
176 | + autodiscover_srv_query_string=self._autodiscover_srv_query_string, |
177 | + autodiscover_a_query_string=self._autodiscover_a_query_string) |
178 | self._call_id = self._reactor.call_every(self._interval, self.ping) |
179 | |
180 | def ping(self): |
181 | |
182 | === modified file 'landscape/broker/service.py' |
183 | --- landscape/broker/service.py 2012-01-30 16:11:20 +0000 |
184 | +++ landscape/broker/service.py 2012-02-06 22:25:22 +0000 |
185 | @@ -55,7 +55,9 @@ |
186 | |
187 | self.transport = self.transport_factory( |
188 | self.reactor, config.url, config.ssl_public_key, |
189 | - self.payload_recorder, config.server_autodiscover) |
190 | + self.payload_recorder, config.server_autodiscover, |
191 | + config.autodiscover_srv_query_string, |
192 | + config.autodiscover_a_query_string) |
193 | self.message_store = get_default_message_store( |
194 | self.persist, config.message_store_path) |
195 | self.identity = Identity(self.config, self.persist) |
196 | @@ -66,7 +68,9 @@ |
197 | self.pinger = self.pinger_factory( |
198 | self.reactor, config.ping_url, self.identity, self.exchanger, |
199 | interval=config.ping_interval, |
200 | - server_autodiscover=config.server_autodiscover) |
201 | + server_autodiscover=config.server_autodiscover, |
202 | + autodiscover_srv_query_string=config.autodiscover_srv_query_string, |
203 | + autodiscover_a_query_string=config.autodiscover_a_query_string) |
204 | self.registration = RegistrationHandler( |
205 | config, self.identity, self.reactor, self.exchanger, self.pinger, |
206 | self.message_store, fetch_async) |
207 | |
208 | === modified file 'landscape/broker/tests/test_config.py' |
209 | --- landscape/broker/tests/test_config.py 2012-02-02 02:49:13 +0000 |
210 | +++ landscape/broker/tests/test_config.py 2012-02-06 22:25:22 +0000 |
211 | @@ -92,19 +92,19 @@ |
212 | self.assertEqual(configuration.url, |
213 | "https://landscape.canonical.com/message-system") |
214 | |
215 | - def test_server_autodiscovery_handling(self): |
216 | + def test_server_autodiscover_handling(self): |
217 | """ |
218 | server_autodiscover is parsed and converted to a boolean value by |
219 | load(). |
220 | """ |
221 | configuration = BrokerConfiguration() |
222 | configuration.load([]) |
223 | - self.assertEquals(configuration.server_autodiscover, False) |
224 | + self.assertEqual(configuration.server_autodiscover, False) |
225 | |
226 | configuration = BrokerConfiguration() |
227 | configuration.load(["--server-autodiscover=true"]) |
228 | - self.assertEquals(configuration.server_autodiscover, True) |
229 | + self.assertEqual(configuration.server_autodiscover, True) |
230 | |
231 | configuration = BrokerConfiguration() |
232 | configuration.load(["--server-autodiscover=false"]) |
233 | - self.assertEquals(configuration.server_autodiscover, False) |
234 | + self.assertEqual(configuration.server_autodiscover, False) |
235 | |
236 | === modified file 'landscape/broker/tests/test_dnslookup.py' |
237 | --- landscape/broker/tests/test_dnslookup.py 2012-02-02 01:39:15 +0000 |
238 | +++ landscape/broker/tests/test_dnslookup.py 2012-02-06 22:25:22 +0000 |
239 | @@ -46,13 +46,16 @@ |
240 | def __init__(self): |
241 | self.results = None |
242 | self.name = None |
243 | + self.queried = None |
244 | |
245 | def lookupService(self, arg1): |
246 | + self.queried = arg1 |
247 | deferred = defer.Deferred() |
248 | deferred.callback(self.results) |
249 | return deferred |
250 | |
251 | def getHostByName(self, arg1): |
252 | + self.queried = arg1 |
253 | deferred = defer.Deferred() |
254 | deferred.callback(self.name) |
255 | return deferred |
256 | @@ -84,11 +87,13 @@ |
257 | fake_result.payload.target.name = "a.b.com" |
258 | fake_resolver = FakeResolver() |
259 | fake_resolver.results = [[fake_result]] |
260 | + query_string = "_landscape._tcp.mylandscapehost.com" |
261 | |
262 | def check(result): |
263 | - self.assertEquals("a.b.com", result) |
264 | + self.assertEqual(fake_resolver.queried, query_string) |
265 | + self.assertEqual("a.b.com", result) |
266 | |
267 | - d = lookup_server_record(fake_resolver) |
268 | + d = lookup_server_record(fake_resolver, query_string) |
269 | d.addCallback(check) |
270 | return d |
271 | |
272 | @@ -101,9 +106,10 @@ |
273 | fake_resolver.results = [[]] |
274 | |
275 | def check(result): |
276 | - self.assertEquals("", result) |
277 | + self.assertEqual("", result) |
278 | |
279 | - d = lookup_server_record(fake_resolver) |
280 | + d = lookup_server_record(fake_resolver, |
281 | + "_landscape._tcp.mylandscapehost.com") |
282 | d.addCallback(check) |
283 | return d |
284 | |
285 | @@ -115,7 +121,8 @@ |
286 | "failed.") |
287 | self.mocker.replay() |
288 | |
289 | - d = lookup_server_record(BadResolver()) |
290 | + d = lookup_server_record(BadResolver(), |
291 | + "_landscape._tcp.mylandscapehost.com") |
292 | self.assertFailure(d, ResolverError) |
293 | return d |
294 | |
295 | @@ -127,11 +134,13 @@ |
296 | """ |
297 | fake_resolver = FakeResolver() |
298 | fake_resolver.name = "a.b.com" |
299 | + query_string = "landscape.localdomain" |
300 | |
301 | def check(result): |
302 | - self.assertEquals("a.b.com", result) |
303 | + self.assertEqual(fake_resolver.queried, query_string) |
304 | + self.assertEqual("a.b.com", result) |
305 | |
306 | - d = lookup_hostname(None, fake_resolver) |
307 | + d = lookup_hostname(None, fake_resolver, query_string) |
308 | d.addCallback(check) |
309 | return d |
310 | |
311 | @@ -144,9 +153,9 @@ |
312 | fake_resolver.name = None |
313 | |
314 | def check(result): |
315 | - self.assertEquals(None, result) |
316 | + self.assertEqual(None, result) |
317 | |
318 | - d = lookup_hostname(None, fake_resolver) |
319 | + d = lookup_hostname(None, fake_resolver, "landscape.localdomain") |
320 | d.addCallback(check) |
321 | return d |
322 | |
323 | @@ -157,7 +166,7 @@ |
324 | logging_mock("Name lookup of landscape.localdomain failed.") |
325 | self.mocker.replay() |
326 | |
327 | - d = lookup_hostname(None, BadResolver()) |
328 | + d = lookup_hostname(None, BadResolver(), "landscape.localdomain") |
329 | self.assertFailure(d, ResolverError) |
330 | return d |
331 | |
332 | @@ -174,7 +183,7 @@ |
333 | d = discover_server(fake_resolver) |
334 | |
335 | def check(result): |
336 | - self.assertEquals("a.b.com", result) |
337 | + self.assertEqual("a.b.com", result) |
338 | |
339 | d.addCallback(check) |
340 | return d |
341 | @@ -187,13 +196,13 @@ |
342 | d = discover_server(fake_resolver) |
343 | |
344 | def check(result): |
345 | - self.assertEquals("x.y.com", result) |
346 | + self.assertEqual("x.y.com", result) |
347 | |
348 | d.addCallback(check) |
349 | return d |
350 | |
351 | def test_failed_lookup(self): |
352 | """A resolver error is returned when server autodiscovery fails.""" |
353 | - d = lookup_server_record(BadResolver()) |
354 | + d = lookup_server_record(BadResolver(), "landscape.localdomain") |
355 | self.assertFailure(d, ResolverError) |
356 | return d |
357 | |
358 | === modified file 'landscape/broker/tests/test_ping.py' |
359 | --- landscape/broker/tests/test_ping.py 2012-01-19 23:34:55 +0000 |
360 | +++ landscape/broker/tests/test_ping.py 2012-02-06 22:25:22 +0000 |
361 | @@ -128,7 +128,9 @@ |
362 | self.url = "http://localhost:8081/whatever" |
363 | self.page_getter = FakePageGetter(None) |
364 | |
365 | - def factory(reactor, url, insecure_id, server_autodiscover): |
366 | + def factory(reactor, url, insecure_id, server_autodiscover, |
367 | + autodiscover_srv_query_string, |
368 | + autodiscover_a_query_string): |
369 | return PingClient(reactor, url, insecure_id, |
370 | get_page=self.page_getter.get_page) |
371 | self.pinger = Pinger(self.broker_service.reactor, |
372 | |
373 | === modified file 'landscape/broker/transport.py' |
374 | --- landscape/broker/transport.py 2012-01-26 23:37:53 +0000 |
375 | +++ landscape/broker/transport.py 2012-02-06 22:25:22 +0000 |
376 | @@ -22,15 +22,24 @@ |
377 | @param pubkey: SSH public key used for secure communication. |
378 | @param payload_recorder: PayloadRecorder used for recording exchanges |
379 | with the server. If C{None}, exchanges will not be recorded. |
380 | + @param server_autodiscovery: Server autodiscovery is performed if True, |
381 | + otherwise server autodiscover is not done. |
382 | + @param autodiscover_srv_query_string: If server autodiscovery is done, this |
383 | + string will be sent to the DNS server when making a SRV query. |
384 | + @param autodiscover_a_query_string: If server autodiscovery is done, this |
385 | + string will be sent to the DNS server when making an A query. |
386 | """ |
387 | |
388 | def __init__(self, reactor, url, pubkey=None, payload_recorder=None, |
389 | - server_autodiscover=False): |
390 | + server_autodiscover=False, autodiscover_srv_query_string="", |
391 | + autodiscover_a_query_string=""): |
392 | self._reactor = reactor |
393 | self._url = url |
394 | self._pubkey = pubkey |
395 | self._payload_recorder = payload_recorder |
396 | self._server_autodiscover = server_autodiscover |
397 | + self._autodiscover_srv_query_string = autodiscover_srv_query_string |
398 | + self._autodiscover_a_query_string = autodiscover_a_query_string |
399 | |
400 | def get_url(self): |
401 | """Get the URL of the remote message system.""" |
402 | @@ -42,7 +51,10 @@ |
403 | |
404 | def _curl(self, payload, computer_id, message_api): |
405 | if self._server_autodiscover: |
406 | - result = blockingCallFromThread(self._reactor, discover_server) |
407 | + result = blockingCallFromThread( |
408 | + self._reactor, discover_server, None, |
409 | + self._autodiscover_srv_query_string, |
410 | + self._autodiscover_a_query_string) |
411 | if result is not None: |
412 | self._url = "https://%s/message-system" % result |
413 | else: |
414 | @@ -166,7 +178,9 @@ |
415 | """Fake transport for testing purposes.""" |
416 | |
417 | def __init__(self, reactor=None, url=None, pubkey=None, |
418 | - payload_recorder=None, server_autodiscover=False): |
419 | + payload_recorder=None, server_autodiscover=False, |
420 | + autodiscover_srv_query_string="", |
421 | + autodiscover_a_query_string=""): |
422 | self._pubkey = pubkey |
423 | self._payload_recorder = payload_recorder |
424 | self.payloads = [] |
425 | @@ -179,6 +193,8 @@ |
426 | self._url = url |
427 | self._reactor = reactor |
428 | self._server_autodiscover = server_autodiscover |
429 | + self._autodiscover_srv_query_string = autodiscover_srv_query_string |
430 | + self._autodiscover_a_query_string = autodiscover_a_query_string |
431 | |
432 | def get_url(self): |
433 | return self._url |
Looks good, only a couple of points about style. +1!
[1]
+def discover_ server( resolver= None, autodiscover_ srv_query_ string= "", a_query_ string= ""):
+ autodiscover_
and
+ lookup_deferred = discover_server( ver_srv_ query_string, ver_a_query_ string)
+ None, self._autodisco
+ self._autodisco
It feels a bit weird to pass None as first argument, the casual reader is probably going to wonder what that means, especially considering that this is the only use of discover_server() in non-test code.
If the resolver argument is used for testing only, please consider moving it at the end of the arguments list:
def discover_ server( autodiscover_ srv_query_ string= "",
autodisco ver_a_query_ string= "", resolver=None):
and use it like:
+ lookup_deferred = discover_server( ver_srv_ query_string, ver_a_query_ string)
+ self._autodisco
+ self._autodisco
[2]
Not really related to this branch, but while I was reading some context, I've noticed that the ping method has grown a bit:
def ping(self):
"""Ask the question.
Hits the URL previously specified with the insecure_id gotten
from the identity.
@return: A deferred resulting in True if there are messages result( result) :
logging. warning( "Autodiscovery failed. Reverting to previous "
"settings. ")
result = "http:// %s/ping" % result
and False otherwise.
"""
def handle_
if result is None:
else:
return result
def do_rest(result):
self. url = result
if result is not None:
if insecure_id is not None:
def errback(type, value, tb):
page_ deferred. errback( Failure( value, type, tb))
self. _reactor. call_in_ thread( page_deferred. callback, errback,
self. get_page, self.url,
post= True, data=data,
headers= headers)
page_ deferred. addCallback( self._got_ result)
return page_deferred False)
return defer.succeed(
if self._server_ autodiscover:
lookup_ deferred = discover_server(
None, self._autodisco ver_srv_ query_string,
self. _autodiscover_ a_query_ string)
lookup_ deferred. addCallback( handle_ result)
lookup_ deferred. addCallback( do_rest)
return lookup_deferred
else:
return do_rest(None)
What do you think of splitting it in methods like:
def ping(self):
"""Ask the question.
Hits the URL previously specified with the insecure_id gotten
from the identity.
@return: A deferred resulting in True if there a...