Merge lp:~blake-rouse/maas/fix-repo-dumper-hwe-images-1.7 into lp:maas/1.7

Proposed by Blake Rouse
Status: Merged
Approved by: Blake Rouse
Approved revision: no longer in the source branch.
Merged at revision: 3270
Proposed branch: lp:~blake-rouse/maas/fix-repo-dumper-hwe-images-1.7
Merge into: lp:maas/1.7
Prerequisite: lp:~blake-rouse/maas/fix-1378527-1.7-again
Diff against target: 286 lines (+201/-5)
6 files modified
src/maasserver/api/pxeconfig.py (+5/-1)
src/maasserver/api/tests/test_pxeconfig.py (+47/-0)
src/provisioningserver/import_images/boot_image_mapping.py (+5/-0)
src/provisioningserver/import_images/download_descriptions.py (+23/-4)
src/provisioningserver/import_images/tests/test_boot_image_mapping.py (+8/-0)
src/provisioningserver/import_images/tests/test_download_descriptions.py (+113/-0)
To merge this branch: bzr merge lp:~blake-rouse/maas/fix-repo-dumper-hwe-images-1.7
Reviewer Review Type Date Requested Status
Gavin Panella (community) Approve
Review via email: mp+239051@code.launchpad.net

Commit message

Fix RepoDumper to handle HWE images correctly. Fix pxeconfig to not use commissioning osystem and distro_series for Ubuntu xinstall.

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/api/pxeconfig.py'
2--- src/maasserver/api/pxeconfig.py 2014-10-09 12:03:53 +0000
3+++ src/maasserver/api/pxeconfig.py 2014-10-21 13:19:27 +0000
4@@ -212,7 +212,11 @@
5 else:
6 purpose = node.get_boot_purpose()
7 event_log_pxe_request(node, purpose)
8- if purpose == "xinstall":
9+
10+ # Use only the commissioning osystem and series, for operating systems
11+ # other than Ubuntu. As Ubuntu supports HWE kernels, and needs to use
12+ # that kernel to perform the installation.
13+ if purpose == "xinstall" and osystem != 'ubuntu':
14 osystem = Config.objects.get_config('commissioning_osystem')
15 series = Config.objects.get_config('commissioning_distro_series')
16
17
18=== modified file 'src/maasserver/api/tests/test_pxeconfig.py'
19--- src/maasserver/api/tests/test_pxeconfig.py 2014-10-09 10:08:54 +0000
20+++ src/maasserver/api/tests/test_pxeconfig.py 2014-10-21 13:19:27 +0000
21@@ -491,3 +491,50 @@
22 self.client.get(reverse('pxeconfig'), params)
23 node = reload_object(node)
24 self.assertEqual(mac, node.pxe_mac)
25+
26+ def test_pxeconfig_returns_commissioning_os_series_for_other_oses(self):
27+ osystem = Config.objects.get_config('default_osystem')
28+ release = Config.objects.get_config('default_distro_series')
29+ nodegroup = factory.make_NodeGroup()
30+ os_image = make_rpc_boot_image(purpose='xinstall')
31+ architecture = '%s/%s' % (
32+ os_image['architecture'], os_image['subarchitecture'])
33+ self.patch(
34+ preseed_module,
35+ 'get_boot_images_for').return_value = [os_image]
36+ self.patch(
37+ pxeconfig_module,
38+ 'get_boot_images_for').return_value = [os_image]
39+ node = factory.make_Node(
40+ mac=True, nodegroup=nodegroup, status=NODE_STATUS.DEPLOYING,
41+ osystem=os_image['osystem'],
42+ distro_series=os_image['release'],
43+ architecture=architecture)
44+ params = self.get_default_params()
45+ params['cluster_uuid'] = nodegroup.uuid
46+ params['mac'] = node.get_primary_mac()
47+ params_out = self.get_pxeconfig(params)
48+ self.assertEqual(osystem, params_out["osystem"])
49+ self.assertEqual(release, params_out["release"])
50+
51+ def test_pxeconfig_returns_ubuntu_os_series_for_ubuntu_xinstall(self):
52+ nodegroup = factory.make_NodeGroup()
53+ ubuntu_image = make_rpc_boot_image(
54+ osystem='ubuntu', purpose='xinstall')
55+ architecture = '%s/%s' % (
56+ ubuntu_image['architecture'], ubuntu_image['subarchitecture'])
57+ self.patch(
58+ preseed_module,
59+ 'get_boot_images_for').return_value = [ubuntu_image]
60+ self.patch(
61+ pxeconfig_module,
62+ 'get_boot_images_for').return_value = [ubuntu_image]
63+ node = factory.make_Node(
64+ mac=True, nodegroup=nodegroup, status=NODE_STATUS.DEPLOYING,
65+ osystem='ubuntu', distro_series=ubuntu_image['release'],
66+ architecture=architecture)
67+ params = self.get_default_params()
68+ params['cluster_uuid'] = nodegroup.uuid
69+ params['mac'] = node.get_primary_mac()
70+ params_out = self.get_pxeconfig(params)
71+ self.assertEqual(ubuntu_image['release'], params_out["release"])
72
73=== modified file 'src/provisioningserver/import_images/boot_image_mapping.py'
74--- src/provisioningserver/import_images/boot_image_mapping.py 2014-10-02 00:53:53 +0000
75+++ src/provisioningserver/import_images/boot_image_mapping.py 2014-10-21 13:19:27 +0000
76@@ -61,6 +61,11 @@
77 assert isinstance(image_spec, ImageSpec)
78 self.mapping.setdefault(image_spec, item)
79
80+ def set(self, image_spec, item):
81+ """"Set metadata for `image_spec` to item, even if already set."""
82+ assert isinstance(image_spec, ImageSpec)
83+ self.mapping[image_spec] = item
84+
85 def dump_json(self):
86 """Produce JSON representing the mapped boot images.
87
88
89=== modified file 'src/provisioningserver/import_images/download_descriptions.py'
90--- src/provisioningserver/import_images/download_descriptions.py 2014-10-21 13:19:27 +0000
91+++ src/provisioningserver/import_images/download_descriptions.py 2014-10-21 13:19:27 +0000
92@@ -64,7 +64,11 @@
93 """
94
95 def __init__(self, boot_images_dict):
96- super(RepoDumper, self).__init__()
97+ super(RepoDumper, self).__init__(config={
98+ # Only download the latest version. Without this all versions
99+ # will be read, causing miss matches in versions.
100+ 'max_items': 1,
101+ })
102 self.boot_images_dict = boot_images_dict
103
104 def load_products(self, path=None, content_id=None):
105@@ -78,12 +82,27 @@
106 """Overridable from `BasicMirrorWriter`."""
107 item = products_exdata(src, pedigree)
108 os = get_os_from_product(item)
109- arch, subarch = item['arch'], item['subarch']
110+ arch, subarches = item['arch'], item['subarches']
111 release = item['release']
112 label = item['label']
113- base_image = ImageSpec(os, arch, subarch, release, label)
114+ base_image = ImageSpec(os, arch, None, release, label)
115 compact_item = clean_up_repo_item(item)
116- self.boot_images_dict.setdefault(base_image, compact_item)
117+ for subarch in subarches.split(','):
118+ self.boot_images_dict.setdefault(
119+ base_image._replace(subarch=subarch), compact_item)
120+
121+ # HWE resources need to map to a specfic resource, and not just to
122+ # any of the supported subarchitectures for that resource.
123+ subarch = item['subarch']
124+ self.boot_images_dict.set(
125+ base_image._replace(subarch=subarch), compact_item)
126+
127+ # HWE resources with generic, should map to the HWE that ships with
128+ # that release.
129+ hwe_arch = 'hwe-%s' % release[0]
130+ if subarch == hwe_arch and 'generic' in subarches:
131+ self.boot_images_dict.set(
132+ base_image._replace(subarch='generic'), compact_item)
133
134
135 def value_passes_filter_list(filter_list, property_value):
136
137=== modified file 'src/provisioningserver/import_images/tests/test_boot_image_mapping.py'
138--- src/provisioningserver/import_images/tests/test_boot_image_mapping.py 2014-10-02 00:53:53 +0000
139+++ src/provisioningserver/import_images/tests/test_boot_image_mapping.py 2014-10-21 13:19:27 +0000
140@@ -63,6 +63,14 @@
141 image_dict.setdefault(image, factory.make_name('newresource'))
142 self.assertItemsEqual([(image, old_resource)], image_dict.items())
143
144+ def test_set_overwrites_item(self):
145+ image_dict = BootImageMapping()
146+ image = make_image_spec()
147+ resource = factory.make_name('resource')
148+ image_dict.setdefault(image, factory.make_name('resource'))
149+ image_dict.set(image, resource)
150+ self.assertItemsEqual([(image, resource)], image_dict.items())
151+
152 def test_dump_json_is_consistent(self):
153 image = make_image_spec()
154 resource = factory.make_name('resource')
155
156=== modified file 'src/provisioningserver/import_images/tests/test_download_descriptions.py'
157--- src/provisioningserver/import_images/tests/test_download_descriptions.py 2014-09-30 20:54:32 +0000
158+++ src/provisioningserver/import_images/tests/test_download_descriptions.py 2014-10-21 13:19:27 +0000
159@@ -16,10 +16,15 @@
160
161 from maastesting.factory import factory
162 from maastesting.testcase import MAASTestCase
163+from mock import sentinel
164 from provisioningserver.import_images import download_descriptions
165 from provisioningserver.import_images.boot_image_mapping import (
166 BootImageMapping,
167 )
168+from provisioningserver.import_images.download_descriptions import (
169+ clean_up_repo_item,
170+ RepoDumper,
171+ )
172 from provisioningserver.import_images.testing.factory import (
173 make_image_spec,
174 set_resource,
175@@ -221,3 +226,111 @@
176 resource="New resource", image_spec=image)
177 download_descriptions.boot_merge(total_resources, resources_from_repo)
178 self.assertEqual(original_resources, total_resources.mapping)
179+
180+
181+class TestRepoDumper(MAASTestCase):
182+ """Tests for `RepoDumper`."""
183+
184+ def make_item(self, os=None, release=None, arch=None,
185+ subarch=None, subarches=None, label=None):
186+ if os is None:
187+ os = factory.make_name('os')
188+ if release is None:
189+ release = factory.make_name('release')
190+ if arch is None:
191+ arch = factory.make_name('arch')
192+ if subarch is None:
193+ subarch = factory.make_name('subarch')
194+ if subarches is None:
195+ subarches = [factory.make_name('subarch') for _ in range(3)]
196+ if subarch not in subarches:
197+ subarches.append(subarch)
198+ if label is None:
199+ label = factory.make_name('label')
200+ item = {
201+ 'content_id': factory.make_name('content_id'),
202+ 'product_name': factory.make_name('product_name'),
203+ 'version_name': factory.make_name('version_name'),
204+ 'path': factory.make_name('path'),
205+ 'os': os,
206+ 'release': release,
207+ 'arch': arch,
208+ 'subarch': subarch,
209+ 'subarches': ','.join(subarches),
210+ 'label': label,
211+ }
212+ return item, clean_up_repo_item(item)
213+
214+ def test_insert_item_adds_item_per_subarch(self):
215+ boot_images_dict = BootImageMapping()
216+ dumper = RepoDumper(boot_images_dict)
217+ subarches = [factory.make_name('subarch') for _ in range(3)]
218+ item, _ = self.make_item(
219+ subarch=subarches.pop(), subarches=subarches)
220+ self.patch(
221+ download_descriptions, 'products_exdata').return_value = item
222+ dumper.insert_item(
223+ sentinel.data, sentinel.src, sentinel.target,
224+ sentinel.pedigree, sentinel.contentsource)
225+ image_specs = [
226+ make_image_spec(
227+ os=item['os'], release=item['release'],
228+ arch=item['arch'], subarch=subarch,
229+ label=item['label'])
230+ for subarch in subarches
231+ ]
232+ self.assertItemsEqual(image_specs, boot_images_dict.mapping.keys())
233+
234+ def test_insert_item_sets_compat_item_specific_to_subarch(self):
235+ boot_images_dict = BootImageMapping()
236+ dumper = RepoDumper(boot_images_dict)
237+ subarches = [factory.make_name('subarch') for _ in range(5)]
238+ compat_subarch = subarches.pop()
239+ item, _ = self.make_item(subarch=subarches.pop(), subarches=subarches)
240+ second_item, compat_item = self.make_item(
241+ os=item['os'], release=item['release'], arch=item['arch'],
242+ subarch=compat_subarch, subarches=[compat_subarch],
243+ label=item['label'])
244+ self.patch(
245+ download_descriptions,
246+ 'products_exdata').side_effect = [item, second_item]
247+ for _ in range(2):
248+ dumper.insert_item(
249+ sentinel.data, sentinel.src, sentinel.target,
250+ sentinel.pedigree, sentinel.contentsource)
251+ image_spec = make_image_spec(
252+ os=item['os'], release=item['release'],
253+ arch=item['arch'], subarch=compat_subarch,
254+ label=item['label'])
255+ self.assertEqual(compat_item, boot_images_dict.mapping[image_spec])
256+
257+ def test_insert_item_sets_generic_to_release_item_for_hwe(self):
258+ boot_images_dict = BootImageMapping()
259+ dumper = RepoDumper(boot_images_dict)
260+ os = 'ubuntu'
261+ release = 'precise'
262+ arch = 'amd64'
263+ label = 'release'
264+ hwep_subarch = 'hwe-p'
265+ hwep_subarches = ['generic', 'hwe-p']
266+ hwes_subarch = 'hwe-s'
267+ hwes_subarches = ['generic', 'hwe-p', 'hwe-s']
268+ hwep_item, compat_item = self.make_item(
269+ os=os, release=release,
270+ arch=arch, subarch=hwep_subarch,
271+ subarches=hwep_subarches, label=label)
272+ hwes_item, _ = self.make_item(
273+ os=os, release=release,
274+ arch=arch, subarch=hwes_subarch,
275+ subarches=hwes_subarches, label=label)
276+ self.patch(
277+ download_descriptions,
278+ 'products_exdata').side_effect = [hwep_item, hwes_item]
279+ for _ in range(2):
280+ dumper.insert_item(
281+ sentinel.data, sentinel.src, sentinel.target,
282+ sentinel.pedigree, sentinel.contentsource)
283+ image_spec = make_image_spec(
284+ os=os, release=release, arch=arch, subarch='generic',
285+ label=label)
286+ self.assertEqual(compat_item, boot_images_dict.mapping[image_spec])

Subscribers

People subscribed via source and target branches

to all changes: