Merge lp:~rvb/maas/1081701-c-bis into lp:~maas-committers/maas/trunk

Proposed by Raphaël Badin
Status: Merged
Approved by: Raphaël Badin
Approved revision: no longer in the source branch.
Merged at revision: 1381
Proposed branch: lp:~rvb/maas/1081701-c-bis
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 357 lines (+77/-39)
8 files modified
src/maasserver/api.py (+4/-4)
src/maasserver/preseed.py (+23/-17)
src/maasserver/tests/test_api.py (+26/-2)
src/maasserver/tests/test_dns.py (+2/-2)
src/maasserver/tests/test_preseed.py (+11/-9)
src/maasserver/tests/test_server_address.py (+3/-3)
src/maastesting/factory.py (+7/-0)
src/metadataserver/api.py (+1/-2)
To merge this branch: bzr merge lp:~rvb/maas/1081701-c-bis
Reviewer Review Type Date Requested Status
Gavin Panella (community) Approve
Review via email: mp+136357@code.launchpad.net

Commit message

Fix the value of 'server_host' in the preseed.

Description of the change

This fixes a bug in the preseed generation. I just spotted that the preseed was still using "server_host = get_maas_facing_server_host()" to populate the 'server_host' field instead of "server_host = get_maas_facing_server_host(nodegroup)".

This was not caught by the tests in place for a stupid reason: "self.assertThat(preseed, MatchesAll(*[Contains(ng_url), Not(Contains(maas_url))]))" did not caught the problem because the value of 'server_host' is the hostname part of 'maas_url' but since it went trough urlparse.urlparse, it was lowercased. To avoid that kind of problem in the future, I created a utility method to create hostname (factory.make_hostname) which will return lowercase hostnames.

To fix that I had to refactor the preseed code a bit: instead of passing the url around, we pass the nodegroup. I think it's all for the best: extracting maas_url from nodegroup is done only in the preseed code.

To post a comment you must log in.
Revision history for this message
Gavin Panella (allenap) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/maasserver/api.py'
--- src/maasserver/api.py 2012-11-26 16:50:14 +0000
+++ src/maasserver/api.py 2012-11-27 16:03:23 +0000
@@ -1630,7 +1630,8 @@
1630 # The node's hostname may include a domain, but we ignore that1630 # The node's hostname may include a domain, but we ignore that
1631 # and use the one from the nodegroup instead.1631 # and use the one from the nodegroup instead.
1632 hostname = strip_domain(node.hostname)1632 hostname = strip_domain(node.hostname)
1633 domain = node.nodegroup.name1633 nodegroup = node.nodegroup
1634 domain = nodegroup.name
1634 else:1635 else:
1635 try:1636 try:
1636 pxelinux_arch = request.GET['arch']1637 pxelinux_arch = request.GET['arch']
@@ -1665,8 +1666,7 @@
1665 subarch = pxelinux_subarch1666 subarch = pxelinux_subarch
16661667
1667 nodegroup = find_nodegroup(request)1668 nodegroup = find_nodegroup(request)
1668 base_url = nodegroup.maas_url if nodegroup is not None else None1669 preseed_url = compose_enlistment_preseed_url(nodegroup=nodegroup)
1669 preseed_url = compose_enlistment_preseed_url(base_url=base_url)
1670 hostname = 'maas-enlist'1670 hostname = 'maas-enlist'
1671 domain = Config.objects.get_config('enlistment_domain')1671 domain = Config.objects.get_config('enlistment_domain')
16721672
@@ -1683,7 +1683,7 @@
1683 extra_kernel_opts = None1683 extra_kernel_opts = None
16841684
1685 purpose = get_boot_purpose(node)1685 purpose = get_boot_purpose(node)
1686 server_address = get_maas_facing_server_address()1686 server_address = get_maas_facing_server_address(nodegroup=nodegroup)
1687 cluster_address = get_mandatory_param(request.GET, "local")1687 cluster_address = get_mandatory_param(request.GET, "local")
16881688
1689 params = KernelParameters(1689 params = KernelParameters(
16901690
=== modified file 'src/maasserver/preseed.py'
--- src/maasserver/preseed.py 2012-11-23 14:35:53 +0000
+++ src/maasserver/preseed.py 2012-11-27 16:03:23 +0000
@@ -38,24 +38,26 @@
38GENERIC_FILENAME = 'generic'38GENERIC_FILENAME = 'generic'
3939
4040
41def get_enlist_preseed(base_url=''):41def get_enlist_preseed(nodegroup=None):
42 """Return the enlistment preseed.42 """Return the enlistment preseed.
4343
44 :param nodegroup: The nodegroup used to generate the preseed.
44 :return: The rendered preseed string.45 :return: The rendered preseed string.
45 :rtype: basestring.46 :rtype: basestring.
46 """47 """
47 return render_enlistment_preseed(48 return render_enlistment_preseed(
48 PRESEED_TYPE.ENLIST, base_url=base_url)49 PRESEED_TYPE.ENLIST, nodegroup=nodegroup)
4950
5051
51def get_enlist_userdata(base_url=''):52def get_enlist_userdata(nodegroup=None):
52 """Return the enlistment preseed.53 """Return the enlistment preseed.
5354
55 :param nodegroup: The nodegroup used to generate the preseed.
54 :return: The rendered enlistment user-data string.56 :return: The rendered enlistment user-data string.
55 :rtype: basestring.57 :rtype: basestring.
56 """58 """
57 return render_enlistment_preseed(59 return render_enlistment_preseed(
58 PRESEED_TYPE.ENLIST_USERDATA, base_url=base_url)60 PRESEED_TYPE.ENLIST_USERDATA, nodegroup=nodegroup)
5961
6062
61def get_preseed(node):63def get_preseed(node):
@@ -209,21 +211,21 @@
209 return parsed_url.hostname, parsed_url.path211 return parsed_url.hostname, parsed_url.path
210212
211213
212def get_preseed_context(release='', base_url=''):214def get_preseed_context(release='', nodegroup=None):
213 """Return the node-independent context dictionary to be used to render215 """Return the node-independent context dictionary to be used to render
214 preseed templates.216 preseed templates.
215217
216 :param node: See `get_preseed_filenames`.
217 :param prefix: See `get_preseed_filenames`.
218 :param release: See `get_preseed_filenames`.218 :param release: See `get_preseed_filenames`.
219 :param nodegroup: The nodegroup used to generate the preseed.
219 :return: The context dictionary.220 :return: The context dictionary.
220 :rtype: dict.221 :rtype: dict.
221 """222 """
222 server_host = get_maas_facing_server_host()223 server_host = get_maas_facing_server_host(nodegroup=nodegroup)
223 main_archive_hostname, main_archive_directory = get_hostname_and_path(224 main_archive_hostname, main_archive_directory = get_hostname_and_path(
224 Config.objects.get_config('main_archive'))225 Config.objects.get_config('main_archive'))
225 ports_archive_hostname, ports_archive_directory = get_hostname_and_path(226 ports_archive_hostname, ports_archive_directory = get_hostname_and_path(
226 Config.objects.get_config('ports_archive'))227 Config.objects.get_config('ports_archive'))
228 base_url = nodegroup.maas_url if nodegroup is not None else None
227 return {229 return {
228 'main_archive_hostname': main_archive_hostname,230 'main_archive_hostname': main_archive_hostname,
229 'main_archive_directory': main_archive_directory,231 'main_archive_directory': main_archive_directory,
@@ -242,7 +244,6 @@
242 preseed templates.244 preseed templates.
243245
244 :param node: See `get_preseed_filenames`.246 :param node: See `get_preseed_filenames`.
245 :param prefix: See `get_preseed_filenames`.
246 :param release: See `get_preseed_filenames`.247 :param release: See `get_preseed_filenames`.
247 :return: The context dictionary.248 :return: The context dictionary.
248 :rtype: dict.249 :rtype: dict.
@@ -261,16 +262,17 @@
261 }262 }
262263
263264
264def render_enlistment_preseed(prefix, release='', base_url=''):265def render_enlistment_preseed(prefix, release='', nodegroup=None):
265 """Return the enlistment preseed.266 """Return the enlistment preseed.
266267
267 :param prefix: See `get_preseed_filenames`.268 :param prefix: See `get_preseed_filenames`.
268 :param release: See `get_preseed_filenames`.269 :param release: See `get_preseed_filenames`.
270 :param nodegroup: The nodegroup used to generate the preseed.
269 :return: The rendered preseed string.271 :return: The rendered preseed string.
270 :rtype: basestring.272 :rtype: basestring.
271 """273 """
272 template = load_preseed_template(None, prefix, release)274 template = load_preseed_template(None, prefix, release)
273 context = get_preseed_context(release, base_url=base_url)275 context = get_preseed_context(release, nodegroup=nodegroup)
274 return template.substitute(**context)276 return template.substitute(**context)
275277
276278
@@ -284,15 +286,19 @@
284 :rtype: basestring.286 :rtype: basestring.
285 """287 """
286 template = load_preseed_template(node, prefix, release)288 template = load_preseed_template(node, prefix, release)
287 base_url = node.nodegroup.maas_url289 nodegroup = node.nodegroup
288 context = get_preseed_context(release, base_url=base_url)290 context = get_preseed_context(release, nodegroup=nodegroup)
289 context.update(get_node_preseed_context(node, release))291 context.update(get_node_preseed_context(node, release))
290 return template.substitute(**context)292 return template.substitute(**context)
291293
292294
293def compose_enlistment_preseed_url(base_url=''):295def compose_enlistment_preseed_url(nodegroup=None):
294 """Compose enlistment preseed URL."""296 """Compose enlistment preseed URL.
297
298 :param nodegroup: The nodegroup used to generate the preseed.
299 """
295 # Always uses the latest version of the metadata API.300 # Always uses the latest version of the metadata API.
301 base_url = nodegroup.maas_url if nodegroup is not None else None
296 version = 'latest'302 version = 'latest'
297 return absolute_reverse(303 return absolute_reverse(
298 'metadata-enlist-preseed', args=[version],304 'metadata-enlist-preseed', args=[version],
299305
=== modified file 'src/maasserver/tests/test_api.py'
--- src/maasserver/tests/test_api.py 2012-11-27 09:51:35 +0000
+++ src/maasserver/tests/test_api.py 2012-11-27 16:03:23 +0000
@@ -48,7 +48,10 @@
48 EnvironmentVariableFixture,48 EnvironmentVariableFixture,
49 Fixture,49 Fixture,
50 )50 )
51from maasserver import api51from maasserver import (
52 api,
53 server_address,
54 )
52from maasserver.api import (55from maasserver.api import (
53 describe,56 describe,
54 DISPLAYED_NODEGROUP_FIELDS,57 DISPLAYED_NODEGROUP_FIELDS,
@@ -3438,9 +3441,11 @@
34383441
3439 def test_pxeconfig_enlistment_preseed_url_detects_request_origin(self):3442 def test_pxeconfig_enlistment_preseed_url_detects_request_origin(self):
3440 self.silence_get_ephemeral_name()3443 self.silence_get_ephemeral_name()
3441 ng_url = 'http://%s' % factory.make_name('host')3444 hostname = factory.make_hostname()
3445 ng_url = 'http://%s' % hostname
3442 network = IPNetwork("10.1.1/24")3446 network = IPNetwork("10.1.1/24")
3443 ip = factory.getRandomIPInNetwork(network)3447 ip = factory.getRandomIPInNetwork(network)
3448 self.patch(server_address, 'gethostbyname', Mock(return_value=ip))
3444 factory.make_node_group(maas_url=ng_url, network=network)3449 factory.make_node_group(maas_url=ng_url, network=network)
3445 params = self.get_default_params()3450 params = self.get_default_params()
34463451
@@ -3451,6 +3456,24 @@
3451 json.loads(response.content)["preseed_url"],3456 json.loads(response.content)["preseed_url"],
3452 StartsWith(ng_url))3457 StartsWith(ng_url))
34533458
3459 def test_pxeconfig_enlistment_log_host_url_detects_request_origin(self):
3460 self.silence_get_ephemeral_name()
3461 hostname = factory.make_hostname()
3462 ng_url = 'http://%s' % hostname
3463 network = IPNetwork("10.1.1/24")
3464 ip = factory.getRandomIPInNetwork(network)
3465 mock = self.patch(
3466 server_address, 'gethostbyname', Mock(return_value=ip))
3467 factory.make_node_group(maas_url=ng_url, network=network)
3468 params = self.get_default_params()
3469
3470 # Simulate that the request targets ip by setting 'SERVER_NAME'.
3471 response = self.client.get(
3472 reverse('pxeconfig'), params, SERVER_NAME=ip)
3473 self.assertEqual(
3474 (ip, hostname),
3475 (json.loads(response.content)["log_host"], mock.call_args[0][0]))
3476
3454 def test_pxeconfig_has_preseed_url_for_known_node(self):3477 def test_pxeconfig_has_preseed_url_for_known_node(self):
3455 params = self.get_mac_params()3478 params = self.get_mac_params()
3456 node = MACAddress.objects.get(mac_address=params['mac']).node3479 node = MACAddress.objects.get(mac_address=params['mac']).node
@@ -3463,6 +3486,7 @@
3463 ng_url = 'http://%s' % factory.make_name('host')3486 ng_url = 'http://%s' % factory.make_name('host')
3464 network = IPNetwork("10.1.1/24")3487 network = IPNetwork("10.1.1/24")
3465 ip = factory.getRandomIPInNetwork(network)3488 ip = factory.getRandomIPInNetwork(network)
3489 self.patch(server_address, 'gethostbyname', Mock(return_value=ip))
3466 nodegroup = factory.make_node_group(maas_url=ng_url, network=network)3490 nodegroup = factory.make_node_group(maas_url=ng_url, network=network)
3467 params = self.get_mac_params()3491 params = self.get_mac_params()
3468 node = MACAddress.objects.get(mac_address=params['mac']).node3492 node = MACAddress.objects.get(mac_address=params['mac']).node
34693493
=== modified file 'src/maasserver/tests/test_dns.py'
--- src/maasserver/tests/test_dns.py 2012-11-26 14:41:53 +0000
+++ src/maasserver/tests/test_dns.py 2012-11-27 16:03:23 +0000
@@ -91,7 +91,7 @@
91 ip = factory.getRandomIPAddress()91 ip = factory.getRandomIPAddress()
92 resolver = FakeMethod(result=ip)92 resolver = FakeMethod(result=ip)
93 self.patch(server_address, 'gethostbyname', resolver)93 self.patch(server_address, 'gethostbyname', resolver)
94 hostname = factory.getRandomString().lower()94 hostname = factory.make_hostname()
95 self.patch_DEFAULT_MAAS_URL_with_random_values(hostname=hostname)95 self.patch_DEFAULT_MAAS_URL_with_random_values(hostname=hostname)
96 self.assertEqual(96 self.assertEqual(
97 (ip, [(hostname, )]),97 (ip, [(hostname, )]),
@@ -118,7 +118,7 @@
118 ip = factory.getRandomIPAddress()118 ip = factory.getRandomIPAddress()
119 resolver = FakeMethod(result=ip)119 resolver = FakeMethod(result=ip)
120 self.patch(server_address, 'gethostbyname', resolver)120 self.patch(server_address, 'gethostbyname', resolver)
121 hostname = factory.getRandomString().lower()121 hostname = factory.make_hostname()
122 maas_url = 'http://%s' % hostname122 maas_url = 'http://%s' % hostname
123 nodegroup = factory.make_node_group(maas_url=maas_url)123 nodegroup = factory.make_node_group(maas_url=maas_url)
124 self.assertEqual(124 self.assertEqual(
125125
=== modified file 'src/maasserver/tests/test_preseed.py'
--- src/maasserver/tests/test_preseed.py 2012-11-23 14:35:53 +0000
+++ src/maasserver/tests/test_preseed.py 2012-11-27 16:03:23 +0000
@@ -323,7 +323,8 @@
323323
324 def test_get_preseed_context_contains_keys(self):324 def test_get_preseed_context_contains_keys(self):
325 release = factory.getRandomString()325 release = factory.getRandomString()
326 context = get_preseed_context(None, release)326 nodegroup = factory.make_node_group(maas_url=factory.getRandomString())
327 context = get_preseed_context(release, nodegroup)
327 self.assertItemsEqual(328 self.assertItemsEqual(
328 ['release', 'metadata_enlist_url', 'server_host', 'server_url',329 ['release', 'metadata_enlist_url', 'server_host', 'server_url',
329 'main_archive_hostname', 'main_archive_directory',330 'main_archive_hostname', 'main_archive_directory',
@@ -339,8 +340,8 @@
339 ports_archive = make_url('ports_archive')340 ports_archive = make_url('ports_archive')
340 Config.objects.set_config('main_archive', main_archive)341 Config.objects.set_config('main_archive', main_archive)
341 Config.objects.set_config('ports_archive', ports_archive)342 Config.objects.set_config('ports_archive', ports_archive)
342 context = get_preseed_context(343 nodegroup = factory.make_node_group(maas_url=factory.getRandomString())
343 factory.make_node(), factory.getRandomString())344 context = get_preseed_context(factory.make_node(), nodegroup)
344 parsed_main_archive = urlparse(main_archive)345 parsed_main_archive = urlparse(main_archive)
345 parsed_ports_archive = urlparse(ports_archive)346 parsed_ports_archive = urlparse(ports_archive)
346 self.assertEqual(347 self.assertEqual(
@@ -402,9 +403,9 @@
402 self.assertIsInstance(preseed, str)403 self.assertIsInstance(preseed, str)
403404
404 def test_get_preseed_uses_nodegroup_maas_url(self):405 def test_get_preseed_uses_nodegroup_maas_url(self):
405 ng_url = 'http://%s' % factory.make_name('host')406 ng_url = 'http://%s' % factory.make_hostname()
406 ng = factory.make_node_group(maas_url=ng_url)407 ng = factory.make_node_group(maas_url=ng_url)
407 maas_url = 'http://%s' % factory.make_name('host')408 maas_url = 'http://%s' % factory.make_hostname()
408 node = factory.make_node(409 node = factory.make_node(
409 nodegroup=ng, status=NODE_STATUS.COMMISSIONING)410 nodegroup=ng, status=NODE_STATUS.COMMISSIONING)
410 self.patch(settings, 'DEFAULT_MAAS_URL', maas_url)411 self.patch(settings, 'DEFAULT_MAAS_URL', maas_url)
@@ -423,11 +424,12 @@
423 self.assertIsInstance(preseed, str)424 self.assertIsInstance(preseed, str)
424425
425 def test_get_preseed_uses_nodegroup_maas_url(self):426 def test_get_preseed_uses_nodegroup_maas_url(self):
426 ng_url = 'http://%s' % factory.make_name('host')427 ng_url = 'http://%s' % factory.make_hostname()
427 maas_url = 'http://%s' % factory.make_name('host')428 maas_url = 'http://%s' % factory.make_hostname()
428 self.patch(settings, 'DEFAULT_MAAS_URL', maas_url)429 self.patch(settings, 'DEFAULT_MAAS_URL', maas_url)
430 nodegroup = factory.make_node_group(maas_url=ng_url)
429 preseed = render_enlistment_preseed(431 preseed = render_enlistment_preseed(
430 PRESEED_TYPE.ENLIST, "precise", base_url=ng_url)432 PRESEED_TYPE.ENLIST, "precise", nodegroup=nodegroup)
431 self.assertThat(433 self.assertThat(
432 preseed, MatchesAll(*[Contains(ng_url), Not(Contains(maas_url))]))434 preseed, MatchesAll(*[Contains(ng_url), Not(Contains(maas_url))]))
433435
@@ -461,7 +463,7 @@
461class TestPreseedProxy(TestCase):463class TestPreseedProxy(TestCase):
462464
463 def test_preseed_uses_default_proxy(self):465 def test_preseed_uses_default_proxy(self):
464 server_host = factory.getRandomString().lower()466 server_host = factory.make_hostname()
465 url = 'http://%s:%d/%s' % (467 url = 'http://%s:%d/%s' % (
466 server_host, factory.getRandomPort(), factory.getRandomString())468 server_host, factory.getRandomPort(), factory.getRandomString())
467 self.patch(settings, 'DEFAULT_MAAS_URL', url)469 self.patch(settings, 'DEFAULT_MAAS_URL', url)
468470
=== modified file 'src/maasserver/tests/test_server_address.py'
--- src/maasserver/tests/test_server_address.py 2012-11-26 14:41:53 +0000
+++ src/maasserver/tests/test_server_address.py 2012-11-27 16:03:23 +0000
@@ -24,7 +24,7 @@
24class TestServerAddress(TestCase):24class TestServerAddress(TestCase):
2525
26 def make_hostname(self):26 def make_hostname(self):
27 return '%s.example.com' % factory.make_name('host').lower()27 return '%s.example.com' % factory.make_hostname()
2828
29 def set_DEFAULT_MAAS_URL(self, hostname=None, with_port=False):29 def set_DEFAULT_MAAS_URL(self, hostname=None, with_port=False):
30 """Patch DEFAULT_MAAS_URL to be a (partly) random URL."""30 """Patch DEFAULT_MAAS_URL to be a (partly) random URL."""
@@ -49,7 +49,7 @@
49 self.assertEqual(ip, server_address.get_maas_facing_server_host())49 self.assertEqual(ip, server_address.get_maas_facing_server_host())
5050
51 def test_get_maas_facing_server_host_returns_nodegroup_maas_url(self):51 def test_get_maas_facing_server_host_returns_nodegroup_maas_url(self):
52 hostname = factory.make_name('host').lower()52 hostname = factory.make_hostname()
53 maas_url = 'http://%s' % hostname53 maas_url = 'http://%s' % hostname
54 nodegroup = factory.make_node_group(maas_url=maas_url)54 nodegroup = factory.make_node_group(maas_url=maas_url)
55 self.assertEqual(55 self.assertEqual(
@@ -82,7 +82,7 @@
82 ip = factory.getRandomIPAddress()82 ip = factory.getRandomIPAddress()
83 resolver = FakeMethod(result=ip)83 resolver = FakeMethod(result=ip)
84 self.patch(server_address, 'gethostbyname', resolver)84 self.patch(server_address, 'gethostbyname', resolver)
85 hostname = self.make_hostname().lower()85 hostname = self.make_hostname()
86 self.set_DEFAULT_MAAS_URL(hostname=hostname)86 self.set_DEFAULT_MAAS_URL(hostname=hostname)
87 self.assertEqual(87 self.assertEqual(
88 (ip, [(hostname, )]),88 (ip, [(hostname, )]),
8989
=== modified file 'src/maastesting/factory.py'
--- src/maastesting/factory.py 2012-09-10 14:50:56 +0000
+++ src/maastesting/factory.py 2012-11-27 16:03:23 +0000
@@ -148,6 +148,13 @@
148 return sep.join(148 return sep.join(
149 filter(None, [prefix, self.getRandomString(size=size)]))149 filter(None, [prefix, self.getRandomString(size=size)]))
150150
151 def make_hostname(self, prefix='host', *args, **kwargs):
152 """Generate a random hostname.
153
154 The returned hostname is lowercase because python's urlparse
155 implicitely lowercases the hostnames."""
156 return self.make_name(prefix=prefix, *args, **kwargs).lower()
157
151 def make_names(self, *prefixes):158 def make_names(self, *prefixes):
152 """Generate random names.159 """Generate random names.
153160
154161
=== modified file 'src/metadataserver/api.py'
--- src/metadataserver/api.py 2012-11-26 08:52:01 +0000
+++ src/metadataserver/api.py 2012-11-27 16:03:23 +0000
@@ -395,9 +395,8 @@
395 def get_enlist_preseed(self, request, version=None):395 def get_enlist_preseed(self, request, version=None):
396 """Render and return a preseed script for enlistment."""396 """Render and return a preseed script for enlistment."""
397 nodegroup = find_nodegroup(request)397 nodegroup = find_nodegroup(request)
398 base_url = nodegroup.maas_url if nodegroup is not None else None
399 return HttpResponse(398 return HttpResponse(
400 get_enlist_preseed(base_url=base_url), mimetype="text/plain")399 get_enlist_preseed(nodegroup=nodegroup), mimetype="text/plain")
401400
402 @operation(idempotent=True)401 @operation(idempotent=True)
403 def get_preseed(self, request, version=None, system_id=None):402 def get_preseed(self, request, version=None, system_id=None):