Merge lp:~blake-rouse/maas/fix-1509417 into lp:~maas-committers/maas/trunk
- fix-1509417
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Blake Rouse | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 4431 | ||||
Proposed branch: | lp:~blake-rouse/maas/fix-1509417 | ||||
Merge into: | lp:~maas-committers/maas/trunk | ||||
Diff against target: |
396 lines (+179/-111) 3 files modified
src/maasserver/static/js/angular/controllers/node_details_storage.js (+43/-31) src/maasserver/static/js/angular/controllers/tests/test_node_details_storage.js (+125/-77) src/maasserver/static/partials/node-details.html (+11/-3) |
||||
To merge this branch: | bzr merge lp:~blake-rouse/maas/fix-1509417 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mike Pontillo (community) | Approve | ||
Lee Trager (community) | Approve | ||
Review via email: mp+276041@code.launchpad.net |
Commit message
Enable modification of storage tags on physical and virtual block devices in the available section.
Description of the change
This does not fully fix the bug. Has Rich still needs to fix the styling, so landing this branch will not mark the bug "Fix Committed".
Blake Rouse (blake-rouse) wrote : | # |
Thanks for the review.
Yeah I agree. I will be enabling that, just in a different branch.
Mike Pontillo (mpontillo) wrote : | # |
Looks pretty good to me; I may have spotted an issue or two that you might want to look at. Take a look below and let me know what you think.
Blake Rouse (blake-rouse) wrote : | # |
Thanks for the review. I will add the request comment.
MAAS Lander (maas-lander) wrote : | # |
The attempt to merge lp:~blake-rouse/maas/fix-1509417 into lp:maas failed. Below is the output from the failed tests.
Get:1 http://
Ign http://
Get:2 http://
Hit http://
Hit http://
Get:3 http://
Get:4 http://
Get:5 http://
Get:6 http://
Get:7 http://
Get:8 http://
Get:9 http://
Get:10 http://
Get:11 http://
Get:12 http://
Get:13 http://
Get:14 http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Ign http://
Ign http://
Fetched 2,823 kB in 4s (652 kB/s)
Reading package lists...
sudo DEBIAN_
--
Mike Pontillo (mpontillo) wrote : | # |
Digging through that log is annoying. But I found this:
maasserver.
maasserver.
=======
ERROR: maasserver.
-------
_StringException: Traceback (most recent call last):
File "/tmp/tarmac/
result = function(*args, **kwargs)
File "/usr/lib/
return self._get_
File "/tmp/tarmac/
vlan = factory.
File "/tmp/tarmac/
vlan.save()
File "/tmp/tarmac/
self.
File "/usr/lib/
raise ValidationError
ValidationError: {'__all__': [u'VLAN with this Vid and Fabric already exists.']}
=======
FAIL: maasserver.
-------
_StringException: Traceback (most recent call last):
File "/tmp/tarmac/
result = function(*args, **kwargs)
File "/usr/lib/
return self._get_
File "/tmp/tarmac/
populate_
File "/usr/lib/
raise mismatch_error
MismatchError: Expected call: mock(((
Actual call: mock(((
MAAS Lander (maas-lander) wrote : | # |
The attempt to merge lp:~blake-rouse/maas/fix-1509417 into lp:maas failed. Below is the output from the failed tests.
Get:1 http://
Ign http://
Get:2 http://
Hit http://
Hit http://
Get:3 http://
Get:4 http://
Get:5 http://
Get:6 http://
Get:7 http://
Get:8 http://
Get:9 http://
Hit http://
Hit http://
Get:10 http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Ign http://
Ign http://
Fetched 2,080 kB in 3s (527 kB/s)
Reading package lists...
sudo DEBIAN_
--
Preview Diff
1 | === modified file 'src/maasserver/static/js/angular/controllers/node_details_storage.js' |
2 | --- src/maasserver/static/js/angular/controllers/node_details_storage.js 2015-10-23 16:34:24 +0000 |
3 | +++ src/maasserver/static/js/angular/controllers/node_details_storage.js 2015-10-28 20:03:05 +0000 |
4 | @@ -105,8 +105,6 @@ |
5 | } |
6 | ]; |
7 | |
8 | - $scope.editing = false; |
9 | - $scope.editing_tags = false; |
10 | $scope.column = 'model'; |
11 | $scope.has_disks = false; |
12 | $scope.filesystems = []; |
13 | @@ -492,6 +490,10 @@ |
14 | |
15 | // Return true if another disk exists with name. |
16 | function isNameAlreadyInUse(name, exclude_disk) { |
17 | + if(!angular.isArray($scope.node.disks)) { |
18 | + return false; |
19 | + } |
20 | + |
21 | var i, j; |
22 | for(i = 0; i < $scope.node.disks.length; i++) { |
23 | var disk = $scope.node.disks[i]; |
24 | @@ -631,6 +633,7 @@ |
25 | return false; |
26 | }; |
27 | |
28 | + // Return true if the free space label should be shown. |
29 | $scope.showFreeSpace = function(disk) { |
30 | if(disk.type === "lvm-vg") { |
31 | return true; |
32 | @@ -1202,6 +1205,7 @@ |
33 | var selected = $scope.getSelectedAvailable(); |
34 | if(selected.length === 1) { |
35 | return ( |
36 | + !selected[0].has_partitions && |
37 | !$scope.hasUnmountedFilesystem(selected[0]) && |
38 | selected[0].type !== "lvm-vg"); |
39 | } |
40 | @@ -1471,7 +1475,11 @@ |
41 | $scope.availableNew.spares.length); |
42 | var minSize = Number.MAX_VALUE; |
43 | angular.forEach($scope.availableNew.devices, function(device) { |
44 | - minSize = Math.min(minSize, device.original.available_size); |
45 | + // Get the size of the device. For a block device it will be |
46 | + // at available_size and for a partition it will be at size. |
47 | + var deviceSize = ( |
48 | + device.original.available_size || device.original.size); |
49 | + minSize = Math.min(minSize, deviceSize); |
50 | }); |
51 | |
52 | // Calculate the new size. |
53 | @@ -1546,7 +1554,9 @@ |
54 | if(selected.length > 0) { |
55 | var i; |
56 | for(i = 0; i < selected.length; i++) { |
57 | - if($scope.hasUnmountedFilesystem(selected[i])) { |
58 | + if(selected[i].has_partitions) { |
59 | + return false; |
60 | + } else if($scope.hasUnmountedFilesystem(selected[i])) { |
61 | return false; |
62 | } else if(selected[i].type === "lvm-vg") { |
63 | return false; |
64 | @@ -1573,7 +1583,9 @@ |
65 | $scope.getNewVolumeGroupSize = function() { |
66 | var total = 0; |
67 | angular.forEach($scope.availableNew.devices, function(device) { |
68 | - total += device.original.available_size; |
69 | + // Add available_size or size if available_size is not set. |
70 | + total += ( |
71 | + device.original.available_size || device.original.size); |
72 | }); |
73 | return ConverterService.bytesToUnits(total).string; |
74 | }; |
75 | @@ -1703,33 +1715,33 @@ |
76 | $scope.updateAvailableSelection(true); |
77 | }; |
78 | |
79 | + // Return true when tags can be edited. |
80 | + $scope.canEditTags = function(disk) { |
81 | + return disk.type !== "partition" && disk.type !== "lvm-vg"; |
82 | + }; |
83 | + |
84 | // Called to enter tag editing mode |
85 | - $scope.editTags = function() { |
86 | - if($scope.$parent.canEdit() && !$scope.editing) { |
87 | - $scope.editing = true; |
88 | - $scope.editing_tags = true; |
89 | - } |
90 | - }; |
91 | - |
92 | - // Called to cancel editing. |
93 | - $scope.cancelTags = function() { |
94 | - $scope.editing = false; |
95 | - $scope.editing_tags = false; |
96 | - updateDisks(); |
97 | - }; |
98 | - |
99 | - // Called to save the changes. |
100 | - $scope.saveTags = function() { |
101 | - $scope.editing = false; |
102 | - $scope.editing_tags = false; |
103 | - |
104 | - angular.forEach($scope.available, function(disk) { |
105 | - var tags = []; |
106 | - angular.forEach(disk.tags, function(tag) { |
107 | - tags.push(tag.text); |
108 | - }); |
109 | - NodesManager.updateDiskTags( |
110 | - $scope.node, disk.block_id, tags); |
111 | + $scope.availableEditTags = function(disk) { |
112 | + disk.$options = { |
113 | + editingTags: true, |
114 | + tags: angular.copy(disk.tags) |
115 | + }; |
116 | + }; |
117 | + |
118 | + // Called to cancel editing tags. |
119 | + $scope.availableCancelTags = function(disk) { |
120 | + disk.$options = {}; |
121 | + }; |
122 | + |
123 | + // Called to save the tag changes. |
124 | + $scope.availableSaveTags = function(disk) { |
125 | + var tags = []; |
126 | + angular.forEach(disk.$options.tags, function(tag) { |
127 | + tags.push(tag.text); |
128 | }); |
129 | + NodesManager.updateDiskTags( |
130 | + $scope.node, disk.block_id, tags); |
131 | + disk.tags = disk.$options.tags; |
132 | + disk.$options = {}; |
133 | }; |
134 | }]); |
135 | |
136 | === modified file 'src/maasserver/static/js/angular/controllers/tests/test_node_details_storage.js' |
137 | --- src/maasserver/static/js/angular/controllers/tests/test_node_details_storage.js 2015-10-23 18:39:01 +0000 |
138 | +++ src/maasserver/static/js/angular/controllers/tests/test_node_details_storage.js 2015-10-28 20:03:05 +0000 |
139 | @@ -252,7 +252,6 @@ |
140 | |
141 | it("sets initial values", function() { |
142 | var controller = makeController(); |
143 | - expect($scope.editing).toBe(false); |
144 | expect($scope.column).toBe('model'); |
145 | expect($scope.has_disks).toBe(false); |
146 | expect($scope.filesystems).toEqual([]); |
147 | @@ -3277,6 +3276,25 @@ |
148 | expect($scope.getNewRAIDSize()).toBe("2.0 MB"); |
149 | }); |
150 | |
151 | + it("gets proper raid-0 size using size", function() { |
152 | + var controller = makeController(); |
153 | + var disk0 = { |
154 | + original: { |
155 | + size: 1000 * 1000 |
156 | + } |
157 | + }; |
158 | + var disk1 = { |
159 | + original: { |
160 | + size: 1000 * 1000 |
161 | + } |
162 | + }; |
163 | + $scope.availableNew.spares = []; |
164 | + $scope.availableNew.devices = [disk0, disk1]; |
165 | + $scope.availableNew.mode = $scope.getAvailableRAIDModes()[0]; |
166 | + |
167 | + expect($scope.getNewRAIDSize()).toBe("2.0 MB"); |
168 | + }); |
169 | + |
170 | it("gets proper raid-1 size", function() { |
171 | var controller = makeController(); |
172 | var disk0 = { |
173 | @@ -3632,6 +3650,29 @@ |
174 | |
175 | expect($scope.getNewVolumeGroupSize()).toBe("3.0 MB"); |
176 | }); |
177 | + |
178 | + it("return the total of all devices using size", function() { |
179 | + var controller = makeController(); |
180 | + $scope.availableNew.devices = [ |
181 | + { |
182 | + original: { |
183 | + size: 1000 * 1000 |
184 | + } |
185 | + }, |
186 | + { |
187 | + original: { |
188 | + size: 1000 * 1000 |
189 | + } |
190 | + }, |
191 | + { |
192 | + original: { |
193 | + size: 1000 * 1000 |
194 | + } |
195 | + } |
196 | + ]; |
197 | + |
198 | + expect($scope.getNewVolumeGroupSize()).toBe("3.0 MB"); |
199 | + }); |
200 | }); |
201 | |
202 | describe("createVolumeGroupCanSave", function() { |
203 | @@ -3925,83 +3966,90 @@ |
204 | }); |
205 | }); |
206 | |
207 | - describe("editTags", function() { |
208 | - |
209 | - it("doesnt sets editing to true if cannot edit", function() { |
210 | - var controller = makeController(); |
211 | - canEditSpy.and.returnValue(false); |
212 | - $scope.editing = false; |
213 | - $scope.editing_tags = false; |
214 | - $scope.editTags(); |
215 | - expect($scope.editing).toBe(false); |
216 | - expect($scope.editing_tags).toBe(false); |
217 | - }); |
218 | - |
219 | - it("sets editing to true", function() { |
220 | - var controller = makeController(); |
221 | - canEditSpy.and.returnValue(true); |
222 | - $scope.editing = false; |
223 | - $scope.editing_tags = false; |
224 | - $scope.editTags(); |
225 | - expect($scope.editing).toBe(true); |
226 | - expect($scope.editing_tags).toBe(true); |
227 | - }); |
228 | - }); |
229 | - |
230 | - describe("cancelTags", function() { |
231 | - |
232 | - it("sets editing to false", function() { |
233 | - var controller = makeController(); |
234 | - $scope.editing = true; |
235 | - $scope.editing_tags = true; |
236 | - $scope.cancelTags(); |
237 | - expect($scope.editing).toBe(false); |
238 | - expect($scope.editing_tags).toBe(false); |
239 | - }); |
240 | - |
241 | - it("calls updateDisks", function() { |
242 | - var controller = makeController(); |
243 | - |
244 | - // Updates disks so we can check that updateStorage |
245 | - // is called. |
246 | - node.disks = [ |
247 | - { |
248 | - id: 0, |
249 | - model: makeName("model"), |
250 | - tags: [], |
251 | - available_size: 0, |
252 | - filesystem: null, |
253 | - partitions: null |
254 | + describe("canEditTags", function() { |
255 | + |
256 | + it("returns false for partition", function() { |
257 | + var controller = makeController(); |
258 | + expect($scope.canEditTags({ |
259 | + type: "partition" |
260 | + })).toBe(false); |
261 | + }); |
262 | + |
263 | + it("returns false for lvm-vg", function() { |
264 | + var controller = makeController(); |
265 | + expect($scope.canEditTags({ |
266 | + type: "lvm-vg" |
267 | + })).toBe(false); |
268 | + }); |
269 | + |
270 | + it("returns true for physical", function() { |
271 | + var controller = makeController(); |
272 | + expect($scope.canEditTags({ |
273 | + type: "physical" |
274 | + })).toBe(true); |
275 | + }); |
276 | + |
277 | + it("returns true for virtual", function() { |
278 | + var controller = makeController(); |
279 | + expect($scope.canEditTags({ |
280 | + type: "virtual" |
281 | + })).toBe(true); |
282 | + }); |
283 | + }); |
284 | + |
285 | + describe("availableEditTags", function() { |
286 | + |
287 | + it("sets $options", function() { |
288 | + var controller = makeController(); |
289 | + var tags = [{}, {}]; |
290 | + var disk = { |
291 | + tags: tags |
292 | + }; |
293 | + |
294 | + $scope.availableEditTags(disk); |
295 | + expect(disk.$options.editingTags).toBe(true); |
296 | + expect(disk.$options.tags).toEqual(tags); |
297 | + expect(disk.$options.tags).not.toBe(tags); |
298 | + }); |
299 | + }); |
300 | + |
301 | + describe("availableCancelTags", function() { |
302 | + |
303 | + it("clears $options", function() { |
304 | + var controller = makeController(); |
305 | + var options = {}; |
306 | + var disk = { $options: options }; |
307 | + |
308 | + $scope.availableCancelTags(disk); |
309 | + expect(disk.$options).toEqual({}); |
310 | + expect(disk.$options).not.toBe(options); |
311 | + }); |
312 | + }); |
313 | + |
314 | + describe("availableSaveTags", function() { |
315 | + |
316 | + it("calls NodesManager.updateDiskTags", function() { |
317 | + var controller = makeController(); |
318 | + var tags = [ |
319 | + { text: "new" }, |
320 | + { text: "old" } |
321 | + ]; |
322 | + var disk = { |
323 | + block_id: makeInteger(0, 100), |
324 | + tags: [], |
325 | + $options: { |
326 | + editingTags:true, |
327 | + tags: tags |
328 | } |
329 | - ]; |
330 | - |
331 | - $scope.nodeLoaded(); |
332 | - $rootScope.$digest(); |
333 | - var filesystems = $scope.filesystems; |
334 | - var available = $scope.available; |
335 | - var used = $scope.used; |
336 | - $scope.editing = true; |
337 | - $scope.editing_tags = true; |
338 | - $scope.cancelTags(); |
339 | - |
340 | - // Verify cancel calls updateStorage but doesn't change any data |
341 | - expect($scope.filesystems).toEqual(filesystems); |
342 | - expect($scope.available).toEqual(available); |
343 | - expect($scope.used).toEqual(used); |
344 | - }); |
345 | - }); |
346 | - |
347 | - describe("saveTags", function() { |
348 | - |
349 | - it("sets editing to false", function() { |
350 | - var controller = makeController(); |
351 | - |
352 | - $scope.editing = true; |
353 | - $scope.editing_tags = true; |
354 | - $scope.saveTags(); |
355 | - |
356 | - expect($scope.editing).toBe(false); |
357 | - expect($scope.editing_tags).toBe(false); |
358 | + }; |
359 | + spyOn(NodesManager, "updateDiskTags"); |
360 | + |
361 | + $scope.availableSaveTags(disk); |
362 | + |
363 | + expect(NodesManager.updateDiskTags).toHaveBeenCalledWith( |
364 | + node, disk.block_id, ["new", "old"]); |
365 | + expect(disk.$options).toEqual({}); |
366 | + expect(disk.tags).toEqual(tags); |
367 | }); |
368 | }); |
369 | }); |
370 | |
371 | === modified file 'src/maasserver/static/partials/node-details.html' |
372 | --- src/maasserver/static/partials/node-details.html 2015-10-28 18:53:35 +0000 |
373 | +++ src/maasserver/static/partials/node-details.html 2015-10-28 20:03:05 +0000 |
374 | @@ -828,11 +828,19 @@ |
375 | <div class="table__data table__column--15" colspan="2" data-ng-show="column === 'model'">{$ item.model $}</div> |
376 | <div class="table__data table__column--15 ng-hide" colspan="2" data-ng-show="column === 'serial'">{$ item.serial $}</div> |
377 | <div class="table__data table__tags table__column--15"> |
378 | - <span class="table__tag" data-ng-repeat="tag in item.tags" data-ng-hide="editing_tags"> |
379 | + <span class="table__tag" data-ng-repeat="tag in item.tags" data-ng-hide="item.$options.editingTags"> |
380 | <a href="#/node/?query=storage_tags:({$ tag.text $})">{$ tag.text $}</a> |
381 | </span> |
382 | - <tags-input ng-model="item.tags" data-ng-show="editing_tags" allow-tags-pattern="[\w-]+"></tags-input> |
383 | - <a class="table__controls table__controls--secondary">edit</a> |
384 | + <tags-input ng-model="item.$options.tags" data-ng-show="item.$options.editingTags" allow-tags-pattern="[\w-]+"></tags-input> |
385 | + <a class="table__controls table__controls--secondary" |
386 | + data-ng-hide="!canEditTags(item) || item.$options.editingTags" |
387 | + data-ng-click="availableEditTags(item)">edit</a> |
388 | + <a class="link-cta-ubuntu text-button" |
389 | + data-ng-show="item.$options.editingTags" |
390 | + data-ng-click="availableCancelTags(item)">Cancel</a> |
391 | + <button class="cta-ubuntu" |
392 | + data-ng-show="item.$options.editingTags" |
393 | + data-ng-click="availableSaveTags(item)">Save</button> |
394 | </div> |
395 | <div class="table__data table__column--7"> |
396 | <div class="table__controls"> |
LGTM!
My only thought is that we should allow viewing and editing tags in either the filesystem or used disks and partitions section. Its a bit of a pain to have to make a disk available just to be able to view and edit its tags.