Merge lp:~blake-rouse/maas/fix-1388373 into lp:~maas-committers/maas/trunk

Proposed by Blake Rouse
Status: Merged
Approved by: Blake Rouse
Approved revision: no longer in the source branch.
Merged at revision: 3338
Proposed branch: lp:~blake-rouse/maas/fix-1388373
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 253 lines (+46/-59)
2 files modified
src/maasserver/views/images.py (+26/-39)
src/maasserver/views/tests/test_images.py (+20/-20)
To merge this branch: bzr merge lp:~blake-rouse/maas/fix-1388373
Reviewer Review Type Date Requested Status
Julian Edwards (community) Approve
Review via email: mp+240621@code.launchpad.net

Commit message

Combine all subarchitectures or boot resources, so only one line is show in the UI per release/architecture.

To post a comment you must log in.
Revision history for this message
Julian Edwards (julian-edwards) wrote :

The code change looks fine, approving on that basis.

However, I think we need to see which HWE images were imported as it gives a clue to the admin which hardware he's able to use with the current imported set. In particular, I think there needs to be a stronger indication that what HWE images you have here directly affects the architecture drop-downs on the node edit page.

review: Approve
Revision history for this message
Christian Reis (kiko) wrote :

Yes, Blake and I discussed whether it was more sensible to just show the subarchitecture here. We figured that the cleaner interface was better but it would be nice to have a way to unfold and see that detail (which should be done in a separate bug if agreed).

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/views/images.py'
2--- src/maasserver/views/images.py 2014-10-17 00:25:31 +0000
3+++ src/maasserver/views/images.py 2014-11-04 17:44:28 +0000
4@@ -461,15 +461,6 @@
5 self.add_resource_template_attributes(resource)
6 return resources
7
8- def is_hwe_resource(self, resource):
9- """Return True if the resource is an Ubuntu HWE resource."""
10- if resource.rtype != BOOT_RESOURCE_TYPE.SYNCED:
11- return False
12- if not resource.name.startswith('ubuntu/'):
13- return False
14- arch, subarch = resource.split_arch()
15- return subarch.startswith('hwe-')
16-
17 def pick_latest_datetime(self, time, other_time):
18 """Return the datetime that is the latest."""
19 if time is None:
20@@ -536,19 +527,20 @@
21 return 0
22 return 100.0 * (size / float(total_size))
23
24- def hwes_to_resource(self, hwes):
25- """Convert the list of hwes into one resource to be used in the UI."""
26- # Calculate all of the values using all of the hwe resources for
27- # this combination of resources.
28- last_update = self.get_last_update_for_resources(hwes)
29- unique_size = self.calculate_unique_size_for_resources(hwes)
30- number_of_nodes = self.get_number_of_nodes_for_resources(hwes)
31- complete = self.are_all_resources_complete(hwes)
32- progress = self.get_progress_for_resources(hwes)
33+ def resource_group_to_resource(self, group):
34+ """Convert the list of resources into one resource to be used in
35+ the UI."""
36+ # Calculate all of the values using all of the resources for
37+ # this combination.
38+ last_update = self.get_last_update_for_resources(group)
39+ unique_size = self.calculate_unique_size_for_resources(group)
40+ number_of_nodes = self.get_number_of_nodes_for_resources(group)
41+ complete = self.are_all_resources_complete(group)
42+ progress = self.get_progress_for_resources(group)
43
44 # Set the computed attributes on the first resource as that will
45 # be the only one returned to the UI.
46- resource = hwes[0]
47+ resource = group[0]
48 resource.arch, resource.subarch = resource.split_arch()
49 resource.title = self.get_resource_title(resource)
50 resource.complete = complete
51@@ -564,10 +556,10 @@
52 resource.status = "Queued for download"
53 resource.downloading = False
54 else:
55- # See if all the hwe resources exist on all the clusters.
56- cluster_has_hwes = any(
57- hwe in hwes for hwe in self.cluster_resources)
58- if cluster_has_hwes:
59+ # See if all the resources exist on all the clusters.
60+ cluster_has_resources = any(
61+ res in group for res in self.cluster_resources)
62+ if cluster_has_resources:
63 resource.status = "Complete"
64 resource.downloading = False
65 else:
66@@ -580,30 +572,25 @@
67 resource.downloading = False
68 return resource
69
70- def combine_hwe_resources(self, resources):
71- """Return a list of resources removing the duplicate hwe resources."""
72- none_hwe_resources = []
73- hwe_resources = defaultdict(list)
74+ def combine_resources(self, resources):
75+ """Return a list of resources combining all of subarchitecture
76+ resources into one resource."""
77+ resource_group = defaultdict(list)
78 for resource in resources:
79- if not self.is_hwe_resource(resource):
80- self.add_resource_template_attributes(resource)
81- none_hwe_resources.append(resource)
82- else:
83- arch = resource.split_arch()[0]
84- key = '%s/%s' % (resource.name, arch)
85- hwe_resources[key].append(resource)
86- combined_hwes = [
87- self.hwes_to_resource(hwes)
88- for _, hwes in hwe_resources.items()
89+ arch = resource.split_arch()[0]
90+ key = '%s/%s' % (resource.name, arch)
91+ resource_group[key].append(resource)
92+ return [
93+ self.resource_group_to_resource(group)
94+ for _, group in resource_group.items()
95 ]
96- return none_hwe_resources + combined_hwes
97
98 def ajax(self, request, *args, **kwargs):
99 """Return all resources in a json object.
100
101 This is used by the image model list on the client side to update
102 the status of images."""
103- resources = self.combine_hwe_resources(BootResource.objects.all())
104+ resources = self.combine_resources(BootResource.objects.all())
105 json_resources = [
106 dict(
107 id=resource.id,
108
109=== modified file 'src/maasserver/views/tests/test_images.py'
110--- src/maasserver/views/tests/test_images.py 2014-10-16 20:41:45 +0000
111+++ src/maasserver/views/tests/test_images.py 2014-11-04 17:44:28 +0000
112@@ -690,11 +690,11 @@
113 json_resource = json_obj['resources'][0]
114 self.assertEqual(number_of_nodes, json_resource['numberOfNodes'])
115
116- def test_combines_hwe_resources_into_one_resource(self):
117+ def test_combines_subarch_resources_into_one_resource(self):
118 self.client_log_in()
119 name = 'ubuntu/%s' % factory.make_name('series')
120 arch = factory.make_name('arch')
121- subarches = [factory.make_name('hwe') for _ in range(3)]
122+ subarches = [factory.make_name('subarch') for _ in range(3)]
123 for subarch in subarches:
124 factory.make_usable_boot_resource(
125 rtype=BOOT_RESOURCE_TYPE.SYNCED,
126@@ -705,11 +705,11 @@
127 1, len(json_obj['resources']),
128 'More than one resource was returned.')
129
130- def test_combined_hwe_resource_calculates_unique_size(self):
131+ def test_combined_subarch_resource_calculates_unique_size(self):
132 self.client_log_in()
133 name = 'ubuntu/%s' % factory.make_name('series')
134 arch = factory.make_name('arch')
135- subarches = [factory.make_name('hwe') for _ in range(3)]
136+ subarches = [factory.make_name('subarch') for _ in range(3)]
137 largefile = factory.make_LargeFile()
138 for subarch in subarches:
139 resource = factory.make_BootResource(
140@@ -723,13 +723,13 @@
141 self.assertEqual(
142 format_size(largefile.total_size), json_resource['size'])
143
144- def test_combined_hwe_resource_calculates_number_of_nodes_deployed(self):
145+ def test_combined_subarch_resource_calculates_num_of_nodes_deployed(self):
146 self.client_log_in()
147 osystem = 'ubuntu'
148 series = factory.make_name('series')
149 name = '%s/%s' % (osystem, series)
150 arch = factory.make_name('arch')
151- subarches = [factory.make_name('hwe') for _ in range(3)]
152+ subarches = [factory.make_name('subarch') for _ in range(3)]
153 for subarch in subarches:
154 factory.make_usable_boot_resource(
155 rtype=BOOT_RESOURCE_TYPE.SYNCED,
156@@ -749,11 +749,11 @@
157 json_resource = json_obj['resources'][0]
158 self.assertEqual(number_of_nodes, json_resource['numberOfNodes'])
159
160- def test_combined_hwe_resource_calculates_complete_True(self):
161+ def test_combined_subarch_resource_calculates_complete_True(self):
162 self.client_log_in()
163 name = 'ubuntu/%s' % factory.make_name('series')
164 arch = factory.make_name('arch')
165- subarches = [factory.make_name('hwe') for _ in range(3)]
166+ subarches = [factory.make_name('subarch') for _ in range(3)]
167 resources = [
168 factory.make_usable_boot_resource(
169 rtype=BOOT_RESOURCE_TYPE.SYNCED,
170@@ -768,11 +768,11 @@
171 json_resource = json_obj['resources'][0]
172 self.assertTrue(json_resource['complete'])
173
174- def test_combined_hwe_resource_calculates_complete_False(self):
175+ def test_combined_subarch_resource_calculates_complete_False(self):
176 self.client_log_in()
177 name = 'ubuntu/%s' % factory.make_name('series')
178 arch = factory.make_name('arch')
179- subarches = [factory.make_name('hwe') for _ in range(3)]
180+ subarches = [factory.make_name('subarch') for _ in range(3)]
181 incomplete_subarch = subarches.pop()
182 factory.make_BootResource(
183 rtype=BOOT_RESOURCE_TYPE.SYNCED,
184@@ -786,11 +786,11 @@
185 json_resource = json_obj['resources'][0]
186 self.assertFalse(json_resource['complete'])
187
188- def test_combined_hwe_resource_calculates_progress(self):
189+ def test_combined_subarch_resource_calculates_progress(self):
190 self.client_log_in()
191 name = 'ubuntu/%s' % factory.make_name('series')
192 arch = factory.make_name('arch')
193- subarches = [factory.make_name('hwe') for _ in range(3)]
194+ subarches = [factory.make_name('subarch') for _ in range(3)]
195 largefile = factory.make_LargeFile()
196 largefile.total_size = largefile.total_size * 2
197 largefile.save()
198@@ -805,11 +805,11 @@
199 json_resource = json_obj['resources'][0]
200 self.assertEqual("Downloading 50%", json_resource['status'])
201
202- def test_combined_hwe_resource_shows_queued_if_no_progress(self):
203+ def test_combined_subarch_resource_shows_queued_if_no_progress(self):
204 self.client_log_in()
205 name = 'ubuntu/%s' % factory.make_name('series')
206 arch = factory.make_name('arch')
207- subarches = [factory.make_name('hwe') for _ in range(3)]
208+ subarches = [factory.make_name('subarch') for _ in range(3)]
209 largefile = factory.make_LargeFile(content="")
210 for subarch in subarches:
211 resource = factory.make_BootResource(
212@@ -822,11 +822,11 @@
213 json_resource = json_obj['resources'][0]
214 self.assertEqual("Queued for download", json_resource['status'])
215
216- def test_combined_hwe_resource_shows_complete_status(self):
217+ def test_combined_subarch_resource_shows_complete_status(self):
218 self.client_log_in()
219 name = 'ubuntu/%s' % factory.make_name('series')
220 arch = factory.make_name('arch')
221- subarches = [factory.make_name('hwe') for _ in range(3)]
222+ subarches = [factory.make_name('subarch') for _ in range(3)]
223 resources = [
224 factory.make_usable_boot_resource(
225 rtype=BOOT_RESOURCE_TYPE.SYNCED,
226@@ -841,11 +841,11 @@
227 json_resource = json_obj['resources'][0]
228 self.assertEqual("Complete", json_resource['status'])
229
230- def test_combined_hwe_resource_shows_waiting_for_cluster_to_sync(self):
231+ def test_combined_subarch_resource_shows_waiting_for_cluster_to_sync(self):
232 self.client_log_in()
233 name = 'ubuntu/%s' % factory.make_name('series')
234 arch = factory.make_name('arch')
235- subarches = [factory.make_name('hwe') for _ in range(3)]
236+ subarches = [factory.make_name('subarch') for _ in range(3)]
237 for subarch in subarches:
238 factory.make_usable_boot_resource(
239 rtype=BOOT_RESOURCE_TYPE.SYNCED,
240@@ -859,11 +859,11 @@
241 self.assertEqual(
242 "Waiting for clusters to sync", json_resource['status'])
243
244- def test_combined_hwe_resource_shows_clusters_syncing(self):
245+ def test_combined_subarch_resource_shows_clusters_syncing(self):
246 self.client_log_in()
247 name = 'ubuntu/%s' % factory.make_name('series')
248 arch = factory.make_name('arch')
249- subarches = [factory.make_name('hwe') for _ in range(3)]
250+ subarches = [factory.make_name('subarch') for _ in range(3)]
251 for subarch in subarches:
252 factory.make_usable_boot_resource(
253 rtype=BOOT_RESOURCE_TYPE.SYNCED,