Merge lp:~free.ekanayaka/landscape-client/drop-cloud-registration into lp:~landscape/landscape-client/trunk
- drop-cloud-registration
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Free Ekanayaka | ||||
Approved revision: | 783 | ||||
Merged at revision: | 778 | ||||
Proposed branch: | lp:~free.ekanayaka/landscape-client/drop-cloud-registration | ||||
Merge into: | lp:~landscape/landscape-client/trunk | ||||
Diff against target: |
1179 lines (+12/-941) 11 files modified
debian/cloud-default.conf (+0/-7) debian/landscape-client.init (+2/-18) debian/landscape-client.install (+0/-1) landscape/broker/config.py (+0/-6) landscape/broker/registration.py (+3/-210) landscape/broker/tests/test_registration.py (+3/-669) landscape/configuration.py (+1/-1) landscape/message_schemas.py (+3/-0) landscape/tests/test_configuration.py (+0/-16) scripts/landscape-is-cloud-managed (+0/-12) setup.py (+0/-1) |
||||
To merge this branch: | bzr merge lp:~free.ekanayaka/landscape-client/drop-cloud-registration | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Benji York (community) | Approve | ||
Geoff Teale (community) | Approve | ||
Review via email: mp+226993@code.launchpad.net |
Commit message
Drop the cloud registration code and associated tests.
Description of the change
Drop the cloud registration code and associated tests.
Benji York (benji) wrote : | # |
So much deleteed code! It's a thing of beauty.
=== modified file 'landscape/
from landscape.
- InvalidCredenti
- EC2_API, Identity)
+ InvalidCredenti
I can't remember if we're uptight about alphebetical import order, but
if we are, look above.
=== modified file 'landscape/
--- landscape/
+++ landscape/
@@ -211,6 +211,8 @@
{"otp": Bytes()})
+# XXX The register-cloud-vm message is obsolete, it's kept around just to not
+# break older LDS releases that import it. Eventually it shall be dropped.
REGISTER_CLOUD_VM = Message(
"register-
{"hostname": Unicode(),
I guess we can bzr-blame the above, but a date would make it obvious
when we can drop the noop.
Free Ekanayaka (free.ekanayaka) wrote : | # |
Benji: we don't maintain imports in alphabetical order for now, but it'd be probably a good thing to do, together to having them one per line instead of smashed together. That takes increases a bit the lines count but it easier to read and maintain (e.g. conflicts). Might be a good topic for the sprint if you care to add it.
About the date, I've added the last LDS version that has this imports: 14.07.
Preview Diff
1 | === removed file 'debian/cloud-default.conf' |
2 | --- debian/cloud-default.conf 2009-03-28 19:04:34 +0000 |
3 | +++ debian/cloud-default.conf 1970-01-01 00:00:00 +0000 |
4 | @@ -1,7 +0,0 @@ |
5 | -[client] |
6 | -cloud = True |
7 | -url = https://landscape.canonical.com/message-system |
8 | -data_path = /var/lib/landscape/client |
9 | -ping_url = http://landscape.canonical.com/ping |
10 | -include_manager_plugins = ScriptExecution |
11 | -script_users = ALL |
12 | |
13 | === modified file 'debian/landscape-client.init' |
14 | --- debian/landscape-client.init 2012-09-05 15:37:17 +0000 |
15 | +++ debian/landscape-client.init 2014-07-17 06:52:14 +0000 |
16 | @@ -31,24 +31,8 @@ |
17 | # This $RUN check should match the semantics of |
18 | # l.sysvconfig.SysVConfig.is_configured_to_run. |
19 | if [ $RUN -eq 0 ]; then |
20 | - if [ $CLOUD -eq 1 ]; then |
21 | - if landscape-is-cloud-managed; then |
22 | - # Install the cloud default configuration file |
23 | - cp /usr/share/landscape/cloud-default.conf /etc/landscape/client.conf |
24 | - # Override default file for not going in this conditional again at |
25 | - # next startup |
26 | - sed -i "s/^RUN=.*/RUN=1/" $LANDSCAPE_DEFAULTS |
27 | - if ! grep -q "^RUN=" $LANDSCAPE_DEFAULTS; then |
28 | - echo "RUN=1" >> $LANDSCAPE_DEFAULTS |
29 | - fi |
30 | - else |
31 | - echo "$NAME is not configured, please run landscape-config." |
32 | - exit 0 |
33 | - fi |
34 | - else |
35 | - echo "$NAME is not configured, please run landscape-config." |
36 | - exit 0 |
37 | - fi |
38 | + echo "$NAME is not configured, please run landscape-config." |
39 | + exit 0 |
40 | fi |
41 | } |
42 | |
43 | |
44 | === modified file 'debian/landscape-client.install' |
45 | --- debian/landscape-client.install 2013-05-16 09:15:13 +0000 |
46 | +++ debian/landscape-client.install 2014-07-17 06:52:14 +0000 |
47 | @@ -7,7 +7,6 @@ |
48 | usr/bin/landscape-package-changer |
49 | usr/bin/landscape-package-reporter |
50 | usr/bin/landscape-release-upgrader |
51 | -usr/bin/landscape-is-cloud-managed |
52 | usr/bin/landscape-dbus-proxy |
53 | usr/share/landscape/cloud-default.conf |
54 | usr/lib/landscape |
55 | |
56 | === modified file 'landscape/broker/config.py' |
57 | --- landscape/broker/config.py 2014-03-25 15:21:52 +0000 |
58 | +++ landscape/broker/config.py 2014-07-17 06:52:14 +0000 |
59 | @@ -32,8 +32,6 @@ |
60 | - C{urgent_exchange_interval} (C{1*60}) |
61 | - C{http_proxy} |
62 | - C{https_proxy} |
63 | - - C{cloud} |
64 | - - C{otp} |
65 | - C{provisioning_otp} |
66 | """ |
67 | parser = super(BrokerConfiguration, self).make_parser() |
68 | @@ -60,10 +58,6 @@ |
69 | help="The URL of the HTTP proxy, if one is needed.") |
70 | parser.add_option("--https-proxy", metavar="URL", |
71 | help="The URL of the HTTPS proxy, if one is needed.") |
72 | - parser.add_option("--cloud", action="store_true", |
73 | - help="Set this if your computer is in an EC2 cloud.") |
74 | - parser.add_option("--otp", default="", |
75 | - help="The OTP to use in cloud configuration.") |
76 | parser.add_option("--access-group", default="", |
77 | help="Suggested access group for this computer.") |
78 | parser.add_option("--tags", |
79 | |
80 | === modified file 'landscape/broker/registration.py' |
81 | --- landscape/broker/registration.py 2014-06-19 10:51:57 +0000 |
82 | +++ landscape/broker/registration.py 2014-07-17 06:52:14 +0000 |
83 | @@ -8,25 +8,16 @@ |
84 | credentials yet and that the server accepts registration messages, so it |
85 | will craft an appropriate one and send it out. |
86 | """ |
87 | -import time |
88 | import logging |
89 | -import socket |
90 | |
91 | from twisted.internet.defer import Deferred |
92 | |
93 | -from landscape.lib.bpickle import loads |
94 | -from landscape.lib.log import log_failure |
95 | from landscape.lib.juju import get_juju_info |
96 | -from landscape.lib.fetch import fetch, FetchError |
97 | from landscape.lib.tag import is_valid_tag_list |
98 | from landscape.lib.network import get_fqdn |
99 | from landscape.lib.vm_info import get_vm_info, get_container_info |
100 | |
101 | |
102 | -EC2_HOST = "169.254.169.254" |
103 | -EC2_API = "http://%s/latest" % (EC2_HOST,) |
104 | - |
105 | - |
106 | class InvalidCredentialsError(Exception): |
107 | """ |
108 | Raised when an invalid account title and/or registration key |
109 | @@ -99,7 +90,6 @@ |
110 | self._exchange = exchange |
111 | self._pinger = pinger |
112 | self._message_store = message_store |
113 | - self._reactor.call_on("run", self._fetch_ec2_data) |
114 | self._reactor.call_on("run", self._get_juju_data) |
115 | self._reactor.call_on("pre-exchange", self._handle_pre_exchange) |
116 | self._reactor.call_on("exchange-done", self._handle_exchange_done) |
117 | @@ -109,21 +99,15 @@ |
118 | self._handle_registration) |
119 | self._should_register = None |
120 | self._fetch_async = fetch_async |
121 | - self._otp = None |
122 | self._ec2_data = None |
123 | self._juju_data = None |
124 | |
125 | def should_register(self): |
126 | id = self._identity |
127 | if id.secure_id: |
128 | - # We already have a secure ID, no need to register |
129 | - logging.info("Machine already has a secure-id. Skipping " |
130 | - "registration.") |
131 | return False |
132 | |
133 | - if self._config.cloud: |
134 | - return self._message_store.accepts("register-cloud-vm") |
135 | - elif self._config.provisioning_otp: |
136 | + if self._config.provisioning_otp: |
137 | return self._message_store.accepts("register-provisioned-machine") |
138 | |
139 | return bool(id.computer_title and id.account_name |
140 | @@ -157,94 +141,6 @@ |
141 | """ |
142 | return self._fetch_async(EC2_API + path).addCallback(accumulate.append) |
143 | |
144 | - def _fetch_ec2_data(self): |
145 | - """Retrieve available EC2 information, if in a EC2 compatible cloud.""" |
146 | - id = self._identity |
147 | - if self._config.cloud and not id.secure_id: |
148 | - # Fetch data from the EC2 API, to be used later in the registration |
149 | - # process |
150 | - # We ignore errors from user-data because it's common for the |
151 | - # URL to return a 404 when the data is unavailable. |
152 | - ec2_data = [] |
153 | - deferred = self._fetch_async(EC2_API + "/user-data").addErrback( |
154 | - log_failure).addCallback(ec2_data.append) |
155 | - paths = [ |
156 | - "/meta-data/instance-id", |
157 | - "/meta-data/reservation-id", |
158 | - "/meta-data/local-hostname", |
159 | - "/meta-data/public-hostname", |
160 | - "/meta-data/ami-launch-index", |
161 | - "/meta-data/ami-id", |
162 | - "/meta-data/local-ipv4", |
163 | - "/meta-data/public-ipv4"] |
164 | - # We're not using a DeferredList here because we want to keep the |
165 | - # number of connections to the backend minimal. See lp:567515. |
166 | - for path in paths: |
167 | - deferred.addCallback( |
168 | - lambda ignore, path=path: self._get_data(path, ec2_data)) |
169 | - # Special case the ramdisk retrieval, because it may not be present |
170 | - deferred.addCallback( |
171 | - lambda ignore: self._fetch_async( |
172 | - EC2_API + "/meta-data/ramdisk-id").addErrback(log_failure)) |
173 | - deferred.addCallback(ec2_data.append) |
174 | - # And same for kernel |
175 | - deferred.addCallback( |
176 | - lambda ignore: self._fetch_async( |
177 | - EC2_API + "/meta-data/kernel-id").addErrback(log_failure)) |
178 | - deferred.addCallback(ec2_data.append) |
179 | - |
180 | - def record_data(ignore): |
181 | - """Record the instance data returned by the EC2 API.""" |
182 | - (raw_user_data, instance_key, reservation_key, |
183 | - local_hostname, public_hostname, launch_index, |
184 | - ami_key, local_ip, public_ip, ramdisk_key, |
185 | - kernel_key) = ec2_data |
186 | - self._ec2_data = { |
187 | - "instance_key": instance_key, |
188 | - "reservation_key": reservation_key, |
189 | - "local_hostname": local_hostname, |
190 | - "public_hostname": public_hostname, |
191 | - "launch_index": launch_index, |
192 | - "kernel_key": kernel_key, |
193 | - "ramdisk_key": ramdisk_key, |
194 | - "image_key": ami_key, |
195 | - "public_ipv4": public_ip, |
196 | - "local_ipv4": local_ip} |
197 | - for k, v in self._ec2_data.items(): |
198 | - if v is None and k in ("ramdisk_key", "kernel_key"): |
199 | - continue |
200 | - self._ec2_data[k] = v.decode("utf-8") |
201 | - self._ec2_data["launch_index"] = int( |
202 | - self._ec2_data["launch_index"]) |
203 | - |
204 | - if self._config.otp: |
205 | - self._otp = self._config.otp |
206 | - return |
207 | - instance_data = _extract_ec2_instance_data( |
208 | - raw_user_data, int(launch_index)) |
209 | - if instance_data is not None: |
210 | - self._otp = instance_data["otp"] |
211 | - exchange_url = instance_data["exchange-url"] |
212 | - ping_url = instance_data["ping-url"] |
213 | - self._exchange._transport.set_url(exchange_url) |
214 | - self._config.url = exchange_url |
215 | - self._config.ping_url = ping_url |
216 | - if "ssl-ca-certificate" in instance_data: |
217 | - from landscape.configuration import \ |
218 | - store_public_key_data |
219 | - public_key_file = store_public_key_data( |
220 | - self._config, instance_data["ssl-ca-certificate"]) |
221 | - self._config.ssl_public_key = public_key_file |
222 | - self._exchange._transport._pubkey = public_key_file |
223 | - self._config.write() |
224 | - |
225 | - def log_error(error): |
226 | - log_failure(error, msg="Got error while fetching meta-data: %r" |
227 | - % (error.value,)) |
228 | - |
229 | - deferred.addCallback(record_data) |
230 | - deferred.addErrback(log_error) |
231 | - |
232 | def _handle_exchange_done(self): |
233 | """Registered handler for the C{"exchange-done"} event. |
234 | |
235 | @@ -264,12 +160,8 @@ |
236 | message with the server. |
237 | |
238 | A computer can fall into several categories: |
239 | - - a "cloud VM" |
240 | - a "normal" computer |
241 | - a "provisionned machine". |
242 | - |
243 | - Furthermore, Cloud VMs can be registered with either a One Time |
244 | - Password (OTP), or with a normal registration password. |
245 | """ |
246 | registration_failed = False |
247 | |
248 | @@ -293,10 +185,9 @@ |
249 | |
250 | if not is_valid_tag_list(tags): |
251 | tags = None |
252 | - logging.error("Invalid tags provided for cloud registration.") |
253 | + logging.error("Invalid tags provided for registration.") |
254 | |
255 | message = {"type": None, # either "register" or "register-cloud-vm" |
256 | - "otp": None, |
257 | "hostname": get_fqdn(), |
258 | "account_name": identity.account_name, |
259 | "registration_password": None, |
260 | @@ -306,28 +197,7 @@ |
261 | if group: |
262 | message["access_group"] = group |
263 | |
264 | - if self._config.cloud and self._ec2_data is not None: |
265 | - # This is the "cloud VM" case. |
266 | - message["type"] = "register-cloud-vm" |
267 | - |
268 | - message.update(self._ec2_data) |
269 | - if self._otp: |
270 | - logging.info("Queueing message to register with OTP") |
271 | - message["otp"] = self._otp |
272 | - |
273 | - elif account_name: |
274 | - with_tags = "and tags %s " % tags if tags else "" |
275 | - with_group = "in access group '%s' " % group if group else "" |
276 | - logging.info( |
277 | - u"Queueing message to register with account %r %s%s" |
278 | - u"as an EC2 instance." % ( |
279 | - account_name, with_group, with_tags)) |
280 | - message["registration_password"] = registration_key |
281 | - |
282 | - else: |
283 | - registration_failed = True |
284 | - |
285 | - elif account_name: |
286 | + if account_name: |
287 | # The computer is a normal computer, possibly a container. |
288 | with_word = "with" if bool(registration_key) else "without" |
289 | with_tags = "and tags %s " % tags if tags else "" |
290 | @@ -433,80 +303,3 @@ |
291 | def _failed(self): |
292 | self.deferred.errback(InvalidCredentialsError()) |
293 | self._cancel_calls() |
294 | - |
295 | - |
296 | -def _extract_ec2_instance_data(raw_user_data, launch_index): |
297 | - """ |
298 | - Given the raw string of EC2 User Data, parse it and return the dict of |
299 | - instance data for this particular instance. |
300 | - |
301 | - If the data can't be parsed, a debug message will be logged and None |
302 | - will be returned. |
303 | - """ |
304 | - try: |
305 | - user_data = loads(raw_user_data) |
306 | - except ValueError: |
307 | - logging.debug("Got invalid user-data %r" % (raw_user_data,)) |
308 | - return |
309 | - |
310 | - if not isinstance(user_data, dict): |
311 | - logging.debug("user-data %r is not a dict" % (user_data,)) |
312 | - return |
313 | - for key in "otps", "exchange-url", "ping-url": |
314 | - if key not in user_data: |
315 | - logging.debug("user-data %r doesn't have key %r." |
316 | - % (user_data, key)) |
317 | - return |
318 | - if len(user_data["otps"]) <= launch_index: |
319 | - logging.debug("user-data %r doesn't have OTP for launch index %d" |
320 | - % (user_data, launch_index)) |
321 | - return |
322 | - instance_data = {"otp": user_data["otps"][launch_index], |
323 | - "exchange-url": user_data["exchange-url"], |
324 | - "ping-url": user_data["ping-url"]} |
325 | - if "ssl-ca-certificate" in user_data: |
326 | - instance_data["ssl-ca-certificate"] = user_data["ssl-ca-certificate"] |
327 | - return instance_data |
328 | - |
329 | - |
330 | -def _wait_for_network(): |
331 | - """ |
332 | - Keep trying to connect to the EC2 metadata server until it becomes |
333 | - accessible or until five minutes pass. |
334 | - |
335 | - This is necessary because the networking init script on Ubuntu is |
336 | - asynchronous; the network may not actually be up by the time the |
337 | - landscape-client init script is invoked. |
338 | - """ |
339 | - timeout = 5 * 60 |
340 | - port = 80 |
341 | - |
342 | - start = time.time() |
343 | - while True: |
344 | - s = socket.socket() |
345 | - try: |
346 | - s.connect((EC2_HOST, port)) |
347 | - s.close() |
348 | - return |
349 | - except socket.error: |
350 | - time.sleep(1) |
351 | - if time.time() - start > timeout: |
352 | - break |
353 | - |
354 | - |
355 | -def is_cloud_managed(fetch=fetch): |
356 | - """ |
357 | - Return C{True} if the machine has been started by Landscape, i.e. if we can |
358 | - find the expected data inside the EC2 user-data field. |
359 | - """ |
360 | - _wait_for_network() |
361 | - try: |
362 | - raw_user_data = fetch(EC2_API + "/user-data", |
363 | - connect_timeout=5) |
364 | - launch_index = fetch(EC2_API + "/meta-data/ami-launch-index", |
365 | - connect_timeout=5) |
366 | - except FetchError: |
367 | - return False |
368 | - instance_data = _extract_ec2_instance_data( |
369 | - raw_user_data, int(launch_index)) |
370 | - return instance_data is not None |
371 | |
372 | === modified file 'landscape/broker/tests/test_registration.py' |
373 | --- landscape/broker/tests/test_registration.py 2014-06-20 06:06:51 +0000 |
374 | +++ landscape/broker/tests/test_registration.py 2014-07-17 06:52:14 +0000 |
375 | @@ -1,24 +1,15 @@ |
376 | import json |
377 | -import os |
378 | import logging |
379 | -import pycurl |
380 | import socket |
381 | |
382 | -from twisted.internet.defer import succeed, fail |
383 | - |
384 | from landscape.broker.registration import ( |
385 | - InvalidCredentialsError, RegistrationHandler, is_cloud_managed, EC2_HOST, |
386 | - EC2_API, Identity) |
387 | + InvalidCredentialsError, Identity) |
388 | |
389 | -from landscape.broker.config import BrokerConfiguration |
390 | from landscape.tests.helpers import LandscapeTest |
391 | from landscape.broker.tests.helpers import ( |
392 | BrokerConfigurationHelper, RegistrationHelper) |
393 | -from landscape.lib.bpickle import dumps |
394 | -from landscape.lib.fetch import HTTPCodeError, FetchError |
395 | from landscape.lib.persist import Persist |
396 | from landscape.lib.vm_info import get_vm_info |
397 | -from landscape.configuration import print_text |
398 | |
399 | |
400 | class IdentityTest(LandscapeTest): |
401 | @@ -250,8 +241,7 @@ |
402 | If the admin has defined tags for this computer, but they are not |
403 | valid, we drop them, and report an error. |
404 | """ |
405 | - self.log_helper.ignore_errors("Invalid tags provided for cloud " |
406 | - "registration") |
407 | + self.log_helper.ignore_errors("Invalid tags provided for registration") |
408 | self.mstore.set_accepted_types(["register"]) |
409 | self.config.computer_title = "Computer Title" |
410 | self.config.account_name = "account_name" |
411 | @@ -261,8 +251,7 @@ |
412 | messages = self.mstore.get_pending_messages() |
413 | self.assertIs(None, messages[0]["tags"]) |
414 | self.assertEqual(self.logfile.getvalue().strip(), |
415 | - "ERROR: Invalid tags provided for cloud " |
416 | - "registration.\n " |
417 | + "ERROR: Invalid tags provided for registration.\n " |
418 | "INFO: Queueing message to register with account " |
419 | "'account_name' with a password.\n " |
420 | "INFO: Sending registration message to exchange.") |
421 | @@ -588,661 +577,6 @@ |
422 | self.assertIn(expected2, juju_info) |
423 | |
424 | |
425 | -class CloudRegistrationHandlerTest(RegistrationHandlerTestBase): |
426 | - |
427 | - cloud = True |
428 | - |
429 | - def setUp(self): |
430 | - super(CloudRegistrationHandlerTest, self).setUp() |
431 | - self.query_results = {} |
432 | - |
433 | - def fetch_stub(url): |
434 | - value = self.query_results[url] |
435 | - if isinstance(value, Exception): |
436 | - return fail(value) |
437 | - else: |
438 | - return succeed(value) |
439 | - |
440 | - self.fetch_func = fetch_stub |
441 | - |
442 | - def get_user_data(self, otps=None, |
443 | - exchange_url="https://example.com/message-system", |
444 | - ping_url="http://example.com/ping", |
445 | - ssl_ca_certificate=None): |
446 | - if otps is None: |
447 | - otps = ["otp1"] |
448 | - user_data = {"otps": otps, "exchange-url": exchange_url, |
449 | - "ping-url": ping_url} |
450 | - if ssl_ca_certificate is not None: |
451 | - user_data["ssl-ca-certificate"] = ssl_ca_certificate |
452 | - return user_data |
453 | - |
454 | - def prepare_query_results( |
455 | - self, user_data=None, instance_key="key1", launch_index=0, |
456 | - local_hostname="ooga.local", public_hostname="ooga.amazon.com", |
457 | - reservation_key=u"res1", ramdisk_key=u"ram1", kernel_key=u"kernel1", |
458 | - image_key=u"image1", local_ip="10.0.0.1", public_ip="10.0.0.2", |
459 | - ssl_ca_certificate=None): |
460 | - if user_data is None: |
461 | - user_data = self.get_user_data( |
462 | - ssl_ca_certificate=ssl_ca_certificate) |
463 | - if not isinstance(user_data, Exception): |
464 | - user_data = dumps(user_data) |
465 | - api_base = "http://169.254.169.254/latest" |
466 | - self.query_results.clear() |
467 | - for url_suffix, value in [ |
468 | - ("/user-data", user_data), |
469 | - ("/meta-data/instance-id", instance_key), |
470 | - ("/meta-data/reservation-id", reservation_key), |
471 | - ("/meta-data/local-hostname", local_hostname), |
472 | - ("/meta-data/public-hostname", public_hostname), |
473 | - ("/meta-data/ami-launch-index", str(launch_index)), |
474 | - ("/meta-data/kernel-id", kernel_key), |
475 | - ("/meta-data/ramdisk-id", ramdisk_key), |
476 | - ("/meta-data/ami-id", image_key), |
477 | - ("/meta-data/local-ipv4", local_ip), |
478 | - ("/meta-data/public-ipv4", public_ip), |
479 | - ]: |
480 | - self.query_results[api_base + url_suffix] = value |
481 | - |
482 | - def prepare_cloud_registration(self, account_name=None, |
483 | - registration_key=None, tags=None, |
484 | - access_group=None): |
485 | - # Set things up so that the client thinks it should register |
486 | - self.mstore.set_accepted_types(list(self.mstore.get_accepted_types()) |
487 | - + ["register-cloud-vm"]) |
488 | - self.config.account_name = account_name |
489 | - self.config.registration_key = registration_key |
490 | - self.config.computer_title = None |
491 | - self.config.tags = tags |
492 | - self.config.access_group = access_group |
493 | - self.identity.secure_id = None |
494 | - self.assertTrue(self.handler.should_register()) |
495 | - |
496 | - def get_expected_cloud_message(self, **kwargs): |
497 | - """ |
498 | - Return the message which is expected from a similar call to |
499 | - L{get_registration_handler_for_cloud}. |
500 | - """ |
501 | - message = dict(type="register-cloud-vm", |
502 | - otp="otp1", |
503 | - hostname="ooga.local", |
504 | - local_hostname="ooga.local", |
505 | - public_hostname="ooga.amazon.com", |
506 | - instance_key=u"key1", |
507 | - reservation_key=u"res1", |
508 | - ramdisk_key=u"ram1", |
509 | - kernel_key=u"kernel1", |
510 | - launch_index=0, |
511 | - image_key=u"image1", |
512 | - account_name=None, |
513 | - registration_password=None, |
514 | - local_ipv4=u"10.0.0.1", |
515 | - public_ipv4=u"10.0.0.2", |
516 | - tags=None) |
517 | - # The get_vm_info() needs to be deferred to the else. If vm-info is |
518 | - # not specified in kwargs, get_vm_info() will typically be mocked. |
519 | - if "vm_info" in kwargs: |
520 | - message["vm-info"] = kwargs.pop("vm_info") |
521 | - else: |
522 | - message["vm-info"] = get_vm_info() |
523 | - message.update(kwargs) |
524 | - return message |
525 | - |
526 | - def test_cloud_registration(self): |
527 | - """ |
528 | - When the 'cloud' configuration variable is set, cloud registration is |
529 | - done instead of normal password-based registration. This means: |
530 | - |
531 | - - "Launch Data" is fetched from the EC2 Launch Data URL. This contains |
532 | - a one-time password that is used during registration. |
533 | - - A different "register-cloud-vm" message is sent to the server instead |
534 | - of "register", containing the OTP. This message is handled by |
535 | - immediately accepting the computer, instead of going through the |
536 | - pending computer stage. |
537 | - """ |
538 | - get_vm_info_mock = self.mocker.replace(get_vm_info) |
539 | - get_vm_info_mock() |
540 | - self.mocker.result("xen") |
541 | - self.mocker.replay() |
542 | - self.prepare_query_results() |
543 | - self.prepare_cloud_registration(tags=u"server,london") |
544 | - |
545 | - # metadata is fetched and stored at reactor startup: |
546 | - self.reactor.fire("run") |
547 | - |
548 | - # And the metadata returned determines the URLs that are used |
549 | - self.assertEqual(self.transport.get_url(), |
550 | - "https://example.com/message-system") |
551 | - self.assertEqual(self.pinger.get_url(), |
552 | - "http://example.com/ping") |
553 | - # Lets make sure those values were written back to the config file |
554 | - new_config = BrokerConfiguration() |
555 | - new_config.load_configuration_file(self.config_filename) |
556 | - self.assertEqual(new_config.url, "https://example.com/message-system") |
557 | - self.assertEqual(new_config.ping_url, "http://example.com/ping") |
558 | - |
559 | - # Okay! Exchange should cause the registration to happen. |
560 | - self.exchanger.exchange() |
561 | - # This *should* be asynchronous, but I think a billion tests are |
562 | - # written like this |
563 | - self.assertEqual(len(self.transport.payloads), 1) |
564 | - self.assertMessages( |
565 | - self.transport.payloads[0]["messages"], |
566 | - [self.get_expected_cloud_message(tags=u"server,london", |
567 | - vm_info="xen")]) |
568 | - |
569 | - def test_cloud_registration_with_access_group(self): |
570 | - """ |
571 | - If the access_group field is presnet in the configuration, the |
572 | - access_group field is present in the outgoing message for a VM |
573 | - registration, and a notice appears in the logs. |
574 | - """ |
575 | - self.prepare_query_results() |
576 | - self.prepare_cloud_registration(access_group=u"dinosaurs", |
577 | - tags=u"server,london") |
578 | - |
579 | - self.reactor.fire("run") |
580 | - self.exchanger.exchange() |
581 | - self.assertEqual(len(self.transport.payloads), 1) |
582 | - self.assertMessages( |
583 | - self.transport.payloads[0]["messages"], |
584 | - [self.get_expected_cloud_message( |
585 | - access_group=u"dinosaurs", tags=u"server,london")]) |
586 | - |
587 | - def test_cloud_registration_with_otp(self): |
588 | - """ |
589 | - If the OTP is present in the configuration, it's used to trigger the |
590 | - registration instead of using the user data. |
591 | - """ |
592 | - self.config.otp = "otp1" |
593 | - self.prepare_query_results(user_data=None) |
594 | - |
595 | - self.prepare_cloud_registration() |
596 | - |
597 | - # metadata is fetched and stored at reactor startup: |
598 | - self.reactor.fire("run") |
599 | - |
600 | - # Okay! Exchange should cause the registration to happen. |
601 | - self.exchanger.exchange() |
602 | - # This *should* be asynchronous, but I think a billion tests are |
603 | - # written like this |
604 | - self.assertEqual(len(self.transport.payloads), 1) |
605 | - self.assertMessages( |
606 | - self.transport.payloads[0]["messages"], |
607 | - [self.get_expected_cloud_message()]) |
608 | - |
609 | - def test_cloud_registration_with_invalid_tags(self): |
610 | - """ |
611 | - Invalid tags in the configuration should result in the tags not being |
612 | - sent to the server, and this fact logged. |
613 | - """ |
614 | - self.log_helper.ignore_errors("Invalid tags provided for cloud " |
615 | - "registration") |
616 | - self.prepare_query_results() |
617 | - self.prepare_cloud_registration(tags=u"<script>alert()</script>,hardy") |
618 | - |
619 | - # metadata is fetched and stored at reactor startup: |
620 | - self.reactor.fire("run") |
621 | - self.exchanger.exchange() |
622 | - self.assertEqual(len(self.transport.payloads), 1) |
623 | - self.assertMessages(self.transport.payloads[0]["messages"], |
624 | - [self.get_expected_cloud_message(tags=None)]) |
625 | - self.assertEqual(self.logfile.getvalue().strip()[:-7], |
626 | - "ERROR: Invalid tags provided for cloud " |
627 | - "registration.\n " |
628 | - "INFO: Queueing message to register with OTP\n " |
629 | - "INFO: Sending registration message to exchange.\n " |
630 | - " INFO: Starting message exchange with " |
631 | - "https://example.com/message-system.\n " |
632 | - "INFO: Message exchange completed in") |
633 | - |
634 | - def test_cloud_registration_with_ssl_ca_certificate(self): |
635 | - """ |
636 | - If we have an SSL certificate CA included in the user-data, this should |
637 | - be written out, and the configuration updated to reflect this. |
638 | - """ |
639 | - key_filename = os.path.join(self.config.data_path, |
640 | - "%s.ssl_public_key" % os.path.basename(self.config_filename)) |
641 | - |
642 | - print_text_mock = self.mocker.replace(print_text) |
643 | - print_text_mock("Writing SSL CA certificate to %s..." % |
644 | - key_filename) |
645 | - self.mocker.replay() |
646 | - self.prepare_query_results(ssl_ca_certificate=u"1234567890") |
647 | - self.prepare_cloud_registration(tags=u"server,london") |
648 | - # metadata is fetched and stored at reactor startup: |
649 | - self.reactor.fire("run") |
650 | - # And the metadata returned determines the URLs that are used |
651 | - self.assertEqual("https://example.com/message-system", |
652 | - self.transport.get_url()) |
653 | - self.assertEqual(key_filename, self.transport._pubkey) |
654 | - self.assertEqual("http://example.com/ping", |
655 | - self.pinger.get_url()) |
656 | - # Let's make sure those values were written back to the config file |
657 | - new_config = BrokerConfiguration() |
658 | - new_config.load_configuration_file(self.config_filename) |
659 | - self.assertEqual("https://example.com/message-system", new_config.url) |
660 | - self.assertEqual("http://example.com/ping", new_config.ping_url) |
661 | - self.assertEqual(key_filename, new_config.ssl_public_key) |
662 | - self.assertEqual("1234567890", open(key_filename, "r").read()) |
663 | - |
664 | - def test_wrong_user_data(self): |
665 | - self.prepare_query_results(user_data="other stuff, not a bpickle") |
666 | - self.prepare_cloud_registration() |
667 | - |
668 | - # Mock registration-failed call |
669 | - reactor_mock = self.mocker.patch(self.reactor) |
670 | - reactor_mock.fire("registration-failed") |
671 | - self.mocker.replay() |
672 | - |
673 | - self.reactor.fire("run") |
674 | - self.exchanger.exchange() |
675 | - |
676 | - def test_wrong_object_type_in_user_data(self): |
677 | - self.prepare_query_results(user_data=True) |
678 | - self.prepare_cloud_registration() |
679 | - |
680 | - # Mock registration-failed call |
681 | - reactor_mock = self.mocker.patch(self.reactor) |
682 | - reactor_mock.fire("registration-failed") |
683 | - self.mocker.replay() |
684 | - |
685 | - self.reactor.fire("run") |
686 | - self.exchanger.exchange() |
687 | - |
688 | - def test_user_data_with_not_enough_elements(self): |
689 | - """ |
690 | - If the AMI launch index isn't represented in the list of OTPs in the |
691 | - user data then BOOM. |
692 | - """ |
693 | - self.prepare_query_results(launch_index=1) |
694 | - self.prepare_cloud_registration() |
695 | - |
696 | - # Mock registration-failed call |
697 | - reactor_mock = self.mocker.patch(self.reactor) |
698 | - reactor_mock.fire("registration-failed") |
699 | - self.mocker.replay() |
700 | - |
701 | - self.reactor.fire("run") |
702 | - self.exchanger.exchange() |
703 | - |
704 | - def test_user_data_bpickle_without_otp(self): |
705 | - self.prepare_query_results(user_data={"foo": "bar"}) |
706 | - self.prepare_cloud_registration() |
707 | - |
708 | - # Mock registration-failed call |
709 | - reactor_mock = self.mocker.patch(self.reactor) |
710 | - reactor_mock.fire("registration-failed") |
711 | - self.mocker.replay() |
712 | - |
713 | - self.reactor.fire("run") |
714 | - self.exchanger.exchange() |
715 | - |
716 | - def test_no_otp_fallback_to_account(self): |
717 | - self.prepare_query_results(user_data="other stuff, not a bpickle", |
718 | - instance_key=u"key1") |
719 | - self.prepare_cloud_registration(account_name=u"onward", |
720 | - registration_key=u"password", |
721 | - tags=u"london,server") |
722 | - |
723 | - self.reactor.fire("run") |
724 | - self.exchanger.exchange() |
725 | - |
726 | - self.assertEqual(len(self.transport.payloads), 1) |
727 | - self.assertMessages(self.transport.payloads[0]["messages"], |
728 | - [self.get_expected_cloud_message( |
729 | - otp=None, |
730 | - account_name=u"onward", |
731 | - registration_password=u"password", |
732 | - tags=u"london,server")]) |
733 | - self.assertEqual(self.logfile.getvalue().strip()[:-7], |
734 | - "INFO: Queueing message to register with account u'onward' and " |
735 | - "tags london,server as an EC2 instance.\n " |
736 | - "INFO: Sending registration message to exchange.\n " |
737 | - "INFO: Starting message exchange with http://localhost:91919.\n " |
738 | - " INFO: Message exchange completed in") |
739 | - |
740 | - def test_queueing_cloud_registration_message_resets_message_store(self): |
741 | - """ |
742 | - When a registration from a cloud is about to happen, the message store |
743 | - is reset, because all previous messages are now meaningless. |
744 | - """ |
745 | - self.mstore.set_accepted_types(list(self.mstore.get_accepted_types()) |
746 | - + ["test"]) |
747 | - |
748 | - self.mstore.add({"type": "test"}) |
749 | - |
750 | - self.prepare_query_results() |
751 | - |
752 | - self.prepare_cloud_registration() |
753 | - |
754 | - self.reactor.fire("run") |
755 | - self.reactor.fire("pre-exchange") |
756 | - |
757 | - messages = self.mstore.get_pending_messages() |
758 | - self.assertEqual(len(messages), 1) |
759 | - self.assertEqual(messages[0]["type"], "register-cloud-vm") |
760 | - |
761 | - def test_cloud_registration_fetch_errors(self): |
762 | - """ |
763 | - If fetching metadata fails, and we have no account details to fall |
764 | - back to, we fire 'registration-failed'. |
765 | - """ |
766 | - self.log_helper.ignore_errors(pycurl.error) |
767 | - |
768 | - def fetch_stub(url): |
769 | - return fail(pycurl.error(7, "couldn't connect to host")) |
770 | - |
771 | - self.handler = RegistrationHandler( |
772 | - self.config, self.identity, self.reactor, self.exchanger, |
773 | - self.pinger, self.mstore, fetch_async=fetch_stub) |
774 | - |
775 | - self.fetch_stub = fetch_stub |
776 | - self.prepare_query_results() |
777 | - self.fetch_stub = fetch_stub |
778 | - |
779 | - self.prepare_cloud_registration() |
780 | - |
781 | - failed = [] |
782 | - self.reactor.call_on( |
783 | - "registration-failed", lambda: failed.append(True)) |
784 | - |
785 | - self.log_helper.ignore_errors("Got error while fetching meta-data") |
786 | - self.reactor.fire("run") |
787 | - self.exchanger.exchange() |
788 | - self.assertEqual(failed, [True]) |
789 | - self.assertIn('error: (7, "couldn\'t connect to host")', |
790 | - self.logfile.getvalue()) |
791 | - |
792 | - def test_cloud_registration_continues_without_user_data(self): |
793 | - """ |
794 | - If no user-data exists (i.e., the user-data URL returns a 404), then |
795 | - register-cloud-vm still occurs. |
796 | - """ |
797 | - self.log_helper.ignore_errors(HTTPCodeError) |
798 | - self.prepare_query_results(user_data=HTTPCodeError(404, "ohno")) |
799 | - self.prepare_cloud_registration(account_name="onward", |
800 | - registration_key="password") |
801 | - |
802 | - self.reactor.fire("run") |
803 | - self.exchanger.exchange() |
804 | - self.assertIn("HTTPCodeError: Server returned HTTP code 404", |
805 | - self.logfile.getvalue()) |
806 | - self.assertEqual(len(self.transport.payloads), 1) |
807 | - self.assertMessages(self.transport.payloads[0]["messages"], |
808 | - [self.get_expected_cloud_message( |
809 | - otp=None, |
810 | - account_name=u"onward", |
811 | - registration_password=u"password")]) |
812 | - |
813 | - def test_cloud_registration_continues_without_ramdisk(self): |
814 | - """ |
815 | - If the instance doesn't have a ramdisk (ie, the query for ramdisk |
816 | - returns a 404), then register-cloud-vm still occurs. |
817 | - """ |
818 | - self.log_helper.ignore_errors(HTTPCodeError) |
819 | - self.prepare_query_results(ramdisk_key=HTTPCodeError(404, "ohno")) |
820 | - self.prepare_cloud_registration() |
821 | - |
822 | - self.reactor.fire("run") |
823 | - self.exchanger.exchange() |
824 | - self.assertIn("HTTPCodeError: Server returned HTTP code 404", |
825 | - self.logfile.getvalue()) |
826 | - self.assertEqual(len(self.transport.payloads), 1) |
827 | - self.assertMessages(self.transport.payloads[0]["messages"], |
828 | - [self.get_expected_cloud_message( |
829 | - ramdisk_key=None)]) |
830 | - |
831 | - def test_cloud_registration_continues_without_kernel(self): |
832 | - """ |
833 | - If the instance doesn't have a kernel (ie, the query for kernel |
834 | - returns a 404), then register-cloud-vm still occurs. |
835 | - """ |
836 | - self.log_helper.ignore_errors(HTTPCodeError) |
837 | - self.prepare_query_results(kernel_key=HTTPCodeError(404, "ohno")) |
838 | - self.prepare_cloud_registration() |
839 | - |
840 | - self.reactor.fire("run") |
841 | - self.exchanger.exchange() |
842 | - self.assertIn("HTTPCodeError: Server returned HTTP code 404", |
843 | - self.logfile.getvalue()) |
844 | - self.assertEqual(len(self.transport.payloads), 1) |
845 | - self.assertMessages(self.transport.payloads[0]["messages"], |
846 | - [self.get_expected_cloud_message( |
847 | - kernel_key=None)]) |
848 | - |
849 | - def test_fall_back_to_normal_registration_when_metadata_fetch_fails(self): |
850 | - """ |
851 | - If fetching metadata fails, but we do have an account name, then we |
852 | - fall back to normal 'register' registration. |
853 | - """ |
854 | - self.mstore.set_accepted_types(["register"]) |
855 | - self.log_helper.ignore_errors(HTTPCodeError) |
856 | - self.prepare_query_results( |
857 | - public_hostname=HTTPCodeError(404, "ohnoes")) |
858 | - self.prepare_cloud_registration(account_name="onward", |
859 | - registration_key="password") |
860 | - self.config.computer_title = "whatever" |
861 | - self.reactor.fire("run") |
862 | - self.exchanger.exchange() |
863 | - self.assertIn("HTTPCodeError: Server returned HTTP code 404", |
864 | - self.logfile.getvalue()) |
865 | - self.assertEqual(len(self.transport.payloads), 1) |
866 | - messages = self.transport.payloads[0]["messages"] |
867 | - self.assertEqual("register", messages[0]["type"]) |
868 | - |
869 | - def test_should_register_in_cloud(self): |
870 | - """ |
871 | - The client should register when it's in the cloud even though |
872 | - it doesn't have the normal account details. |
873 | - """ |
874 | - self.mstore.set_accepted_types(self.mstore.get_accepted_types() |
875 | - + ("register-cloud-vm",)) |
876 | - self.config.account_name = None |
877 | - self.config.registration_key = None |
878 | - self.config.computer_title = None |
879 | - self.identity.secure_id = None |
880 | - self.assertTrue(self.handler.should_register()) |
881 | - |
882 | - def test_launch_index(self): |
883 | - """ |
884 | - The client used the value in C{ami-launch-index} to choose the |
885 | - appropriate OTP in the user data. |
886 | - """ |
887 | - otp = "correct otp for launch index" |
888 | - self.prepare_query_results( |
889 | - user_data=self.get_user_data(otps=["wrong index", otp, |
890 | - "wrong again"],), |
891 | - instance_key="key1", |
892 | - launch_index=1) |
893 | - |
894 | - self.prepare_cloud_registration() |
895 | - |
896 | - self.reactor.fire("run") |
897 | - self.exchanger.exchange() |
898 | - self.assertEqual(len(self.transport.payloads), 1) |
899 | - self.assertMessages(self.transport.payloads[0]["messages"], |
900 | - [self.get_expected_cloud_message(otp=otp, |
901 | - launch_index=1)]) |
902 | - |
903 | - def test_should_not_register_in_cloud(self): |
904 | - """ |
905 | - Having a secure ID means we shouldn't register, even in the cloud. |
906 | - """ |
907 | - self.mstore.set_accepted_types(self.mstore.get_accepted_types() |
908 | - + ("register-cloud-vm",)) |
909 | - self.config.account_name = None |
910 | - self.config.registration_key = None |
911 | - self.config.computer_title = None |
912 | - self.identity.secure_id = "hello" |
913 | - self.assertFalse(self.handler.should_register()) |
914 | - |
915 | - def test_should_not_register_without_register_cloud_vm(self): |
916 | - """ |
917 | - If the server isn't accepting a 'register-cloud-vm' message, |
918 | - we shouldn't register. |
919 | - """ |
920 | - self.config.account_name = None |
921 | - self.config.registration_key = None |
922 | - self.config.computer_title = None |
923 | - self.identity.secure_id = None |
924 | - self.assertFalse(self.handler.should_register()) |
925 | - |
926 | - |
927 | -class IsCloudManagedTests(LandscapeTest): |
928 | - |
929 | - def setUp(self): |
930 | - super(IsCloudManagedTests, self).setUp() |
931 | - self.urls = [] |
932 | - self.responses = [] |
933 | - |
934 | - def fake_fetch(self, url, connect_timeout=None): |
935 | - self.urls.append((url, connect_timeout)) |
936 | - return self.responses.pop(0) |
937 | - |
938 | - def mock_socket(self): |
939 | - """ |
940 | - Mock out socket usage by is_cloud_managed to wait for the network. |
941 | - """ |
942 | - # Mock the socket.connect call that it also does |
943 | - socket_class = self.mocker.replace("socket.socket", passthrough=False) |
944 | - socket = socket_class() |
945 | - socket.connect((EC2_HOST, 80)) |
946 | - socket.close() |
947 | - |
948 | - def test_is_managed(self): |
949 | - """ |
950 | - L{is_cloud_managed} returns True if the EC2 user-data contains |
951 | - Landscape instance information. It fetches the EC2 data with low |
952 | - timeouts. |
953 | - """ |
954 | - user_data = {"otps": ["otp1"], "exchange-url": "http://exchange", |
955 | - "ping-url": "http://ping"} |
956 | - self.responses = [dumps(user_data), "0"] |
957 | - |
958 | - self.mock_socket() |
959 | - self.mocker.replay() |
960 | - |
961 | - self.assertTrue(is_cloud_managed(self.fake_fetch)) |
962 | - self.assertEqual( |
963 | - self.urls, |
964 | - [(EC2_API + "/user-data", 5), |
965 | - (EC2_API + "/meta-data/ami-launch-index", 5)]) |
966 | - |
967 | - def test_is_managed_index(self): |
968 | - user_data = {"otps": ["otp1", "otp2"], |
969 | - "exchange-url": "http://exchange", |
970 | - "ping-url": "http://ping"} |
971 | - self.responses = [dumps(user_data), "1"] |
972 | - self.mock_socket() |
973 | - self.mocker.replay() |
974 | - self.assertTrue(is_cloud_managed(self.fake_fetch)) |
975 | - |
976 | - def test_is_managed_wrong_index(self): |
977 | - user_data = {"otps": ["otp1"], "exchange-url": "http://exchange", |
978 | - "ping-url": "http://ping"} |
979 | - self.responses = [dumps(user_data), "1"] |
980 | - self.mock_socket() |
981 | - self.mocker.replay() |
982 | - self.assertFalse(is_cloud_managed(self.fake_fetch)) |
983 | - |
984 | - def test_is_managed_exchange_url(self): |
985 | - user_data = {"otps": ["otp1"], "ping-url": "http://ping"} |
986 | - self.responses = [dumps(user_data), "0"] |
987 | - self.mock_socket() |
988 | - self.mocker.replay() |
989 | - self.assertFalse(is_cloud_managed(self.fake_fetch)) |
990 | - |
991 | - def test_is_managed_ping_url(self): |
992 | - user_data = {"otps": ["otp1"], "exchange-url": "http://exchange"} |
993 | - self.responses = [dumps(user_data), "0"] |
994 | - self.mock_socket() |
995 | - self.mocker.replay() |
996 | - self.assertFalse(is_cloud_managed(self.fake_fetch)) |
997 | - |
998 | - def test_is_managed_bpickle(self): |
999 | - self.responses = ["some other user data", "0"] |
1000 | - self.mock_socket() |
1001 | - self.mocker.replay() |
1002 | - self.assertFalse(is_cloud_managed(self.fake_fetch)) |
1003 | - |
1004 | - def test_is_managed_no_data(self): |
1005 | - self.responses = ["", "0"] |
1006 | - self.mock_socket() |
1007 | - self.mocker.replay() |
1008 | - self.assertFalse(is_cloud_managed(self.fake_fetch)) |
1009 | - |
1010 | - def test_is_managed_fetch_not_found(self): |
1011 | - |
1012 | - def fake_fetch(url, connect_timeout=None): |
1013 | - raise HTTPCodeError(404, "ohnoes") |
1014 | - |
1015 | - self.mock_socket() |
1016 | - self.mocker.replay() |
1017 | - self.assertFalse(is_cloud_managed(fake_fetch)) |
1018 | - |
1019 | - def test_is_managed_fetch_error(self): |
1020 | - |
1021 | - def fake_fetch(url, connect_timeout=None): |
1022 | - raise FetchError(7, "couldn't connect to host") |
1023 | - |
1024 | - self.mock_socket() |
1025 | - self.mocker.replay() |
1026 | - self.assertFalse(is_cloud_managed(fake_fetch)) |
1027 | - |
1028 | - def test_waits_for_network(self): |
1029 | - """ |
1030 | - is_cloud_managed will wait until the network before trying to fetch |
1031 | - the EC2 user data. |
1032 | - """ |
1033 | - user_data = {"otps": ["otp1"], "exchange-url": "http://exchange", |
1034 | - "ping-url": "http://ping"} |
1035 | - self.responses = [dumps(user_data), "0"] |
1036 | - |
1037 | - self.mocker.order() |
1038 | - time_sleep = self.mocker.replace("time.sleep", passthrough=False) |
1039 | - socket_class = self.mocker.replace("socket.socket", passthrough=False) |
1040 | - socket_obj = socket_class() |
1041 | - socket_obj.connect((EC2_HOST, 80)) |
1042 | - self.mocker.throw(socket.error("woops")) |
1043 | - time_sleep(1) |
1044 | - socket_obj = socket_class() |
1045 | - socket_obj.connect((EC2_HOST, 80)) |
1046 | - self.mocker.result(None) |
1047 | - socket_obj.close() |
1048 | - self.mocker.replay() |
1049 | - self.assertTrue(is_cloud_managed(self.fake_fetch)) |
1050 | - |
1051 | - def test_waiting_times_out(self): |
1052 | - """ |
1053 | - We'll only wait five minutes for the network to come up. |
1054 | - """ |
1055 | - |
1056 | - def fake_fetch(url, connect_timeout=None): |
1057 | - raise FetchError(7, "couldn't connect to host") |
1058 | - |
1059 | - self.mocker.order() |
1060 | - time_sleep = self.mocker.replace("time.sleep", passthrough=False) |
1061 | - time_time = self.mocker.replace("time.time", passthrough=False) |
1062 | - time_time() |
1063 | - self.mocker.result(100) |
1064 | - socket_class = self.mocker.replace("socket.socket", passthrough=False) |
1065 | - socket_obj = socket_class() |
1066 | - socket_obj.connect((EC2_HOST, 80)) |
1067 | - self.mocker.throw(socket.error("woops")) |
1068 | - time_sleep(1) |
1069 | - time_time() |
1070 | - self.mocker.result(401) |
1071 | - self.mocker.replay() |
1072 | - # Mocking time.time is dangerous, because the test harness calls it. So |
1073 | - # we explicitly reset mocker before returning from the test. |
1074 | - try: |
1075 | - self.assertFalse(is_cloud_managed(fake_fetch)) |
1076 | - finally: |
1077 | - self.mocker.reset() |
1078 | - |
1079 | - |
1080 | class ProvisioningRegistrationTest(RegistrationHandlerTestBase): |
1081 | |
1082 | def test_provisioned_machine_registration_with_otp(self): |
1083 | |
1084 | === modified file 'landscape/configuration.py' |
1085 | --- landscape/configuration.py 2014-07-01 14:52:02 +0000 |
1086 | +++ landscape/configuration.py 2014-07-17 06:52:14 +0000 |
1087 | @@ -581,7 +581,7 @@ |
1088 | decode_base64_ssl_public_certificate(config) |
1089 | config.write() |
1090 | # Restart the client to ensure that it's using the new configuration. |
1091 | - if not config.no_start and not config.otp: |
1092 | + if not config.no_start: |
1093 | try: |
1094 | sysvconfig.restart_landscape() |
1095 | except ProcessError: |
1096 | |
1097 | === modified file 'landscape/message_schemas.py' |
1098 | --- landscape/message_schemas.py 2014-06-09 08:18:05 +0000 |
1099 | +++ landscape/message_schemas.py 2014-07-17 06:52:14 +0000 |
1100 | @@ -211,6 +211,9 @@ |
1101 | {"otp": Bytes()}) |
1102 | |
1103 | |
1104 | +# XXX The register-cloud-vm message is obsolete, it's kept around just to not |
1105 | +# break older LDS releases that import it (the last LDS release to have it |
1106 | +# is 14.07). Eventually it shall be dropped. |
1107 | REGISTER_CLOUD_VM = Message( |
1108 | "register-cloud-vm", |
1109 | {"hostname": Unicode(), |
1110 | |
1111 | === modified file 'landscape/tests/test_configuration.py' |
1112 | --- landscape/tests/test_configuration.py 2014-02-25 18:06:48 +0000 |
1113 | +++ landscape/tests/test_configuration.py 2014-07-17 06:52:14 +0000 |
1114 | @@ -820,7 +820,6 @@ |
1115 | "--ping-interval", "30", |
1116 | "--http-proxy", "", |
1117 | "--https-proxy", "", |
1118 | - "--otp", "", |
1119 | "--tags", "", |
1120 | "--provisioning-otp", ""] |
1121 | config = self.get_config(args) |
1122 | @@ -837,7 +836,6 @@ |
1123 | "https_proxy = \n" |
1124 | "url = https://landscape.canonical.com/message-system\n" |
1125 | "exchange_interval = 900\n" |
1126 | - "otp = \n" |
1127 | "ping_interval = 30\n" |
1128 | "ping_url = http://landscape.canonical.com/ping\n" |
1129 | "provisioning_otp = \n" |
1130 | @@ -862,20 +860,6 @@ |
1131 | config = self.get_config(["--silent", "-t", "rex"]) |
1132 | self.assertRaises(ConfigurationError, setup, config) |
1133 | |
1134 | - def test_silent_setup_with_otp(self): |
1135 | - """ |
1136 | - If the OTP is specified, there is no need to pass the account name and |
1137 | - the computer title. |
1138 | - """ |
1139 | - sysvconfig_mock = self.mocker.patch(SysVConfig) |
1140 | - sysvconfig_mock.set_start_on_boot(True) |
1141 | - self.mocker.replay() |
1142 | - |
1143 | - config = self.get_config(["--silent", "--otp", "otp1"]) |
1144 | - setup(config) |
1145 | - |
1146 | - self.assertEqual("otp1", config.otp) |
1147 | - |
1148 | def test_silent_setup_with_provisioning_otp(self): |
1149 | """ |
1150 | If the provisioning OTP is specified, there is no need to pass the |
1151 | |
1152 | === removed file 'scripts/landscape-is-cloud-managed' |
1153 | --- scripts/landscape-is-cloud-managed 2009-04-09 14:32:45 +0000 |
1154 | +++ scripts/landscape-is-cloud-managed 1970-01-01 00:00:00 +0000 |
1155 | @@ -1,12 +0,0 @@ |
1156 | -#!/usr/bin/python |
1157 | -import sys, os |
1158 | -if os.path.dirname(os.path.abspath(sys.argv[0])) == os.path.abspath("scripts"): |
1159 | - sys.path.insert(0, "./") |
1160 | -else: |
1161 | - from landscape.lib.warning import hide_warnings |
1162 | - hide_warnings() |
1163 | - |
1164 | -from landscape.broker.registration import is_cloud_managed |
1165 | - |
1166 | -# We return 0 if it succeeds |
1167 | -sys.exit(not is_cloud_managed()) |
1168 | |
1169 | === modified file 'setup.py' |
1170 | --- setup.py 2013-06-03 12:26:30 +0000 |
1171 | +++ setup.py 2014-07-17 06:52:14 +0000 |
1172 | @@ -56,7 +56,6 @@ |
1173 | "scripts/landscape-package-reporter", |
1174 | "scripts/landscape-release-upgrader", |
1175 | "scripts/landscape-sysinfo", |
1176 | - "scripts/landscape-is-cloud-managed", |
1177 | "scripts/landscape-dbus-proxy", |
1178 | "scripts/landscape-client-settings-mechanism", |
1179 | "scripts/landscape-client-registration-mechanism", |
+1 - I see a lot of lint output, might want to take a look.