Merge lp:~blake-rouse/maas/fix-power8-1.9 into lp:maas/1.9
- fix-power8-1.9
- Merge into 1.9
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Blake Rouse | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 4540 | ||||
Proposed branch: | lp:~blake-rouse/maas/fix-power8-1.9 | ||||
Merge into: | lp:maas/1.9 | ||||
Diff against target: |
917 lines (+553/-28) 15 files modified
docs/changelog.rst (+8/-5) src/maasserver/models/node.py (+3/-3) src/maasserver/models/partition.py (+11/-1) src/maasserver/models/partitiontable.py (+20/-4) src/maasserver/models/tests/test_node.py (+8/-0) src/maasserver/models/tests/test_partition.py (+25/-1) src/maasserver/models/tests/test_partitiontable.py (+49/-1) src/maasserver/preseed_storage.py (+66/-8) src/maasserver/static/js/angular/controllers/node_details_storage.js (+11/-0) src/maasserver/static/js/angular/controllers/tests/test_node_details_storage.js (+51/-0) src/maasserver/storage_layouts.py (+6/-1) src/maasserver/tests/test_preseed_storage.py (+215/-1) src/maasserver/tests/test_storage_layouts.py (+78/-1) src/provisioningserver/boot/powerkvm.py (+1/-1) src/provisioningserver/boot/powernv.py (+1/-1) |
||||
To merge this branch: | bzr merge lp:~blake-rouse/maas/fix-power8-1.9 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Blake Rouse (community) | Approve | ||
Review via email: mp+287034@code.launchpad.net |
Commit message
Fix storage configuration so it adds a prep partition at the beginning of the disk for deploying PowerNV. Fix PowerNV and PowerKVM to not create the EFI partition when the storage layout is generated.
Description of the change
MAAS Lander (maas-lander) wrote : | # |
The attempt to merge lp:~blake-rouse/maas/fix-power8-1.9 into lp:maas/1.9 failed. Below is the output from the failed tests.
Ign http://
Get:1 http://
Get:2 http://
Get:3 http://
Hit http://
Hit http://
Get:4 http://
Get:5 http://
Get:6 http://
Get:7 http://
Hit http://
Hit 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://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Hit http://
Preview Diff
1 | === modified file 'docs/changelog.rst' |
2 | --- docs/changelog.rst 2016-01-26 00:26:34 +0000 |
3 | +++ docs/changelog.rst 2016-02-24 16:23:03 +0000 |
4 | @@ -8,14 +8,17 @@ |
5 | |
6 | See https://launchpad.net/maas/+milestone/1.9.1 for full details. |
7 | |
8 | -Minor bugs fixed in this release |
9 | --------------------------------- |
10 | - |
11 | -LP: #1536754 Upgrade from 1.8 to 1.9 lost connected macs in all but one network |
12 | - |
13 | Bug Fix Update |
14 | -------------- |
15 | |
16 | +#1523779 Fix grub-install error on deploying power8 machines. |
17 | + |
18 | +#1526542 Skip block devices with duplicate serial numbers to fix multipath issue. |
19 | + |
20 | +#1536754 Upgrade from 1.8 to 1.9 lost connected macs in all but one network. |
21 | + |
22 | +#1532262 Fix failure to power query requests for SM15K servers. |
23 | + |
24 | #1484696 Fix bug in apache2 maas config where it will reuse websocket connections |
25 | to work around a bug in apache2 itself. |
26 | |
27 | |
28 | === modified file 'src/maasserver/models/node.py' |
29 | --- src/maasserver/models/node.py 2015-11-30 07:50:50 +0000 |
30 | +++ src/maasserver/models/node.py 2016-02-24 16:23:03 +0000 |
31 | @@ -155,7 +155,7 @@ |
32 | |
33 | # Holds the known `bios_boot_methods`. If `bios_boot_method` is not in this |
34 | # list then it will fallback to `DEFAULT_BIOS_BOOT_METHOD`. |
35 | -KNOWN_BIOS_BOOT_METHODS = ["pxe", "uefi"] |
36 | +KNOWN_BIOS_BOOT_METHODS = ["pxe", "uefi", "powernv", "powerkvm"] |
37 | |
38 | # Default `bios_boot_method`. See `KNOWN_BIOS_BOOT_METHOD` above for usage. |
39 | DEFAULT_BIOS_BOOT_METHOD = "pxe" |
40 | @@ -837,8 +837,8 @@ |
41 | """Return true if the node is connected to a managed network.""" |
42 | for interface in self.interface_set.all(): |
43 | for link in interface.get_links(): |
44 | - if (link['mode'] != INTERFACE_LINK_TYPE.LINK_UP |
45 | - and 'subnet' in link): |
46 | + if (link['mode'] != INTERFACE_LINK_TYPE.LINK_UP and |
47 | + 'subnet' in link): |
48 | return True |
49 | return False |
50 | |
51 | |
52 | === modified file 'src/maasserver/models/partition.py' |
53 | --- src/maasserver/models/partition.py 2015-11-17 23:19:51 +0000 |
54 | +++ src/maasserver/models/partition.py 2016-02-24 16:23:03 +0000 |
55 | @@ -189,7 +189,17 @@ |
56 | partitions_in_table = sorted(partitions_in_table, key=attrgetter('id')) |
57 | idx = partitions_in_table.index(self) |
58 | if self.partition_table.table_type == PARTITION_TABLE_TYPE.GPT: |
59 | - return idx + 1 |
60 | + # ppc64el machines get part1 skipped when this partition is on |
61 | + # the boot disk. This is because the prep partition is part1 and |
62 | + # is added when the preseed for storage is generated. |
63 | + node = self.get_node() |
64 | + arch, _ = node.split_arch() |
65 | + boot_disk = node.get_boot_disk() |
66 | + if (arch == "ppc64el" and |
67 | + self.partition_table.block_device.id == boot_disk.id): |
68 | + return idx + 2 |
69 | + else: |
70 | + return idx + 1 |
71 | elif self.partition_table.table_type == PARTITION_TABLE_TYPE.MBR: |
72 | # If more than 4 partitions then the 4th partition number is |
73 | # skipped because that is used for the extended partition. |
74 | |
75 | === modified file 'src/maasserver/models/partitiontable.py' |
76 | --- src/maasserver/models/partitiontable.py 2015-11-17 23:19:51 +0000 |
77 | +++ src/maasserver/models/partitiontable.py 2016-02-24 16:23:03 +0000 |
78 | @@ -49,6 +49,13 @@ |
79 | PARTITION_TABLE_EXTRA_SPACE = ( |
80 | INITIAL_PARTITION_OFFSET + END_OF_PARTITION_TABLE_SPACE) |
81 | |
82 | +# The amount of space required to be reserved for the prep partition. Prep |
83 | +# partition is required by all ppc64el architectures. Because of the way the |
84 | +# system boots it requires that a 8MiB prep partition exist with grub installed |
85 | +# on that partition. Without this partition the installation of grub will fail |
86 | +# on ppc64el and will fail to boot. |
87 | +PREP_PARTITION_SIZE = 8 * 1024 * 1024 # 8MiB |
88 | + |
89 | |
90 | class PartitionTable(CleanSave, TimestampedModel): |
91 | """A partition table on a block device. |
92 | @@ -73,7 +80,7 @@ |
93 | def get_size(self): |
94 | """Total usable size of partition table.""" |
95 | return round_size_to_nearest_block( |
96 | - self.block_device.size - PARTITION_TABLE_EXTRA_SPACE, |
97 | + self.block_device.size - self.get_overhead_size(), |
98 | PARTITION_ALIGNMENT_SIZE, |
99 | False) |
100 | |
101 | @@ -81,6 +88,15 @@ |
102 | """Block size of partition table.""" |
103 | return self.block_device.block_size |
104 | |
105 | + def get_overhead_size(self): |
106 | + """Return the total amount of extra space this partition table |
107 | + requires.""" |
108 | + extra_space = PARTITION_TABLE_EXTRA_SPACE |
109 | + node_arch, _ = self.block_device.node.split_arch() |
110 | + if node_arch == "ppc64el": |
111 | + extra_space += PREP_PARTITION_SIZE |
112 | + return extra_space |
113 | + |
114 | def get_used_size(self, ignore_partitions=[]): |
115 | """Return the used size of partitions on the table.""" |
116 | ignore_ids = [ |
117 | @@ -93,7 +109,7 @@ |
118 | if used_size is None: |
119 | used_size = 0 |
120 | # The extra space taken by the partition table header is used space. |
121 | - return used_size + PARTITION_TABLE_EXTRA_SPACE |
122 | + return used_size + self.get_overhead_size() |
123 | |
124 | def get_available_size(self, ignore_partitions=[]): |
125 | """Return the remaining size available for partitions.""" |
126 | @@ -143,8 +159,8 @@ |
127 | # placed on the boot disk. |
128 | if boot_disk is not None and self.block_device.id == boot_disk.id: |
129 | bios_boot_method = node.get_bios_boot_method() |
130 | - if bios_boot_method == "uefi": |
131 | - # UEFI must always use a GPT table. |
132 | + if bios_boot_method in ["uefi", "powernv", "powerkvm"]: |
133 | + # UEFI, PowerNV, or PowerKVM must always use a GPT table. |
134 | if not self.table_type: |
135 | self.table_type = PARTITION_TABLE_TYPE.GPT |
136 | elif self.table_type != PARTITION_TABLE_TYPE.GPT: |
137 | |
138 | === modified file 'src/maasserver/models/tests/test_node.py' |
139 | --- src/maasserver/models/tests/test_node.py 2015-11-21 02:16:17 +0000 |
140 | +++ src/maasserver/models/tests/test_node.py 2016-02-24 16:23:03 +0000 |
141 | @@ -242,6 +242,14 @@ |
142 | node = factory.make_Node(bios_boot_method="uefi") |
143 | self.assertEquals("uefi", node.get_bios_boot_method()) |
144 | |
145 | + def test_get_bios_boot_method_returns_powernv(self): |
146 | + node = factory.make_Node(bios_boot_method="powernv") |
147 | + self.assertEqual("powernv", node.get_bios_boot_method()) |
148 | + |
149 | + def test_get_bios_boot_method_returns_powerkvm(self): |
150 | + node = factory.make_Node(bios_boot_method="powerkvm") |
151 | + self.assertEqual("powerkvm", node.get_bios_boot_method()) |
152 | + |
153 | def test_get_bios_boot_method_fallback_to_pxe(self): |
154 | node = factory.make_Node(bios_boot_method=factory.make_name("boot")) |
155 | self.assertEquals("pxe", node.get_bios_boot_method()) |
156 | |
157 | === modified file 'src/maasserver/models/tests/test_partition.py' |
158 | --- src/maasserver/models/tests/test_partition.py 2015-11-17 23:19:51 +0000 |
159 | +++ src/maasserver/models/tests/test_partition.py 2016-02-24 16:23:03 +0000 |
160 | @@ -31,7 +31,10 @@ |
161 | Partition, |
162 | PARTITION_ALIGNMENT_SIZE, |
163 | ) |
164 | -from maasserver.models.partitiontable import PARTITION_TABLE_EXTRA_SPACE |
165 | +from maasserver.models.partitiontable import ( |
166 | + PARTITION_TABLE_EXTRA_SPACE, |
167 | + PREP_PARTITION_SIZE, |
168 | +) |
169 | from maasserver.testing.factory import factory |
170 | from maasserver.testing.orm import reload_object |
171 | from maasserver.testing.testcase import MAASServerTestCase |
172 | @@ -311,6 +314,27 @@ |
173 | self.expectThat(idx, Equals(partition.get_partition_number())) |
174 | idx += 1 |
175 | |
176 | + def test_get_partition_number_returns_starting_at_2_for_ppc64el(self): |
177 | + node = factory.make_Node( |
178 | + architecture="ppc64el/generic", bios_boot_method="uefi") |
179 | + block_device = factory.make_PhysicalBlockDevice( |
180 | + node=node, |
181 | + size=( |
182 | + (MIN_PARTITION_SIZE * 4) + PARTITION_TABLE_EXTRA_SPACE + |
183 | + PREP_PARTITION_SIZE)) |
184 | + node.boot_disk = block_device |
185 | + node.save() |
186 | + partition_table = factory.make_PartitionTable( |
187 | + block_device=block_device, table_type=PARTITION_TABLE_TYPE.GPT) |
188 | + partitions = [ |
189 | + partition_table.add_partition(size=MIN_BLOCK_DEVICE_SIZE) |
190 | + for _ in range(4) |
191 | + ] |
192 | + idx = 2 |
193 | + for partition in partitions: |
194 | + self.expectThat(idx, Equals(partition.get_partition_number())) |
195 | + idx += 1 |
196 | + |
197 | def test_get_partition_number_returns_correct_numbering_for_mbr(self): |
198 | block_device = factory.make_PhysicalBlockDevice( |
199 | size=(MIN_BLOCK_DEVICE_SIZE * 6) + PARTITION_TABLE_EXTRA_SPACE) |
200 | |
201 | === modified file 'src/maasserver/models/tests/test_partitiontable.py' |
202 | --- src/maasserver/models/tests/test_partitiontable.py 2015-11-17 23:19:51 +0000 |
203 | +++ src/maasserver/models/tests/test_partitiontable.py 2016-02-24 16:23:03 +0000 |
204 | @@ -28,7 +28,10 @@ |
205 | MIN_PARTITION_SIZE, |
206 | PARTITION_ALIGNMENT_SIZE, |
207 | ) |
208 | -from maasserver.models.partitiontable import PARTITION_TABLE_EXTRA_SPACE |
209 | +from maasserver.models.partitiontable import ( |
210 | + PARTITION_TABLE_EXTRA_SPACE, |
211 | + PREP_PARTITION_SIZE, |
212 | +) |
213 | from maasserver.testing.factory import factory |
214 | from maasserver.testing.testcase import MAASServerTestCase |
215 | from maasserver.utils.converters import round_size_to_nearest_block |
216 | @@ -52,6 +55,19 @@ |
217 | False), |
218 | partition_table.get_size()) |
219 | |
220 | + def test_get_size_returns_block_device_size_minus_ppc64el(self): |
221 | + node = factory.make_Node(architecture="ppc64el/generic") |
222 | + block_device = factory.make_PhysicalBlockDevice(node=node) |
223 | + partition_table = factory.make_PartitionTable( |
224 | + block_device=block_device) |
225 | + self.assertEqual( |
226 | + round_size_to_nearest_block( |
227 | + partition_table.block_device.size - |
228 | + PARTITION_TABLE_EXTRA_SPACE - PREP_PARTITION_SIZE, |
229 | + PARTITION_ALIGNMENT_SIZE, |
230 | + False), |
231 | + partition_table.get_size()) |
232 | + |
233 | def test_get_block_size_returns_block_device_block_size(self): |
234 | partition_table = factory.make_PartitionTable() |
235 | self.assertEquals( |
236 | @@ -123,6 +139,24 @@ |
237 | self.assertRaises( |
238 | ValidationError, partition_table.add_partition) |
239 | |
240 | + def test_get_overhead_size(self): |
241 | + node = factory.make_Node(bios_boot_method="pxe") |
242 | + block_device = factory.make_PhysicalBlockDevice(node=node) |
243 | + partition_table = factory.make_PartitionTable( |
244 | + block_device=block_device) |
245 | + self.assertEquals( |
246 | + PARTITION_TABLE_EXTRA_SPACE, |
247 | + partition_table.get_overhead_size()) |
248 | + |
249 | + def test_get_overhead_size_for_ppc64el(self): |
250 | + node = factory.make_Node(architecture="ppc64el/generic") |
251 | + block_device = factory.make_PhysicalBlockDevice(node=node) |
252 | + partition_table = factory.make_PartitionTable( |
253 | + block_device=block_device) |
254 | + self.assertEquals( |
255 | + PARTITION_TABLE_EXTRA_SPACE + PREP_PARTITION_SIZE, |
256 | + partition_table.get_overhead_size()) |
257 | + |
258 | def test_get_available_size(self): |
259 | block_size = 4096 |
260 | device = factory.make_BlockDevice( |
261 | @@ -162,6 +196,20 @@ |
262 | partition_table = factory.make_PartitionTable(block_device=boot_disk) |
263 | self.assertEquals(PARTITION_TABLE_TYPE.GPT, partition_table.table_type) |
264 | |
265 | + def test_save_sets_table_type_to_gpt_for_powernv_boot(self): |
266 | + node = factory.make_Node( |
267 | + with_boot_disk=False, bios_boot_method="powernv") |
268 | + boot_disk = factory.make_PhysicalBlockDevice(node=node) |
269 | + partition_table = factory.make_PartitionTable(block_device=boot_disk) |
270 | + self.assertEqual(PARTITION_TABLE_TYPE.GPT, partition_table.table_type) |
271 | + |
272 | + def test_save_sets_table_type_to_gpt_for_powerkvm_boot(self): |
273 | + node = factory.make_Node( |
274 | + with_boot_disk=False, bios_boot_method="powerkvm") |
275 | + boot_disk = factory.make_PhysicalBlockDevice(node=node) |
276 | + partition_table = factory.make_PartitionTable(block_device=boot_disk) |
277 | + self.assertEqual(PARTITION_TABLE_TYPE.GPT, partition_table.table_type) |
278 | + |
279 | def test_save_sets_table_type_to_gpt_for_none_boot_disk(self): |
280 | node = factory.make_Node(with_boot_disk=False, bios_boot_method="pxe") |
281 | factory.make_PhysicalBlockDevice(node=node) |
282 | |
283 | === modified file 'src/maasserver/preseed_storage.py' |
284 | --- src/maasserver/preseed_storage.py 2015-10-29 16:39:49 +0000 |
285 | +++ src/maasserver/preseed_storage.py 2016-02-24 16:23:03 +0000 |
286 | @@ -22,7 +22,10 @@ |
287 | FILESYSTEM_TYPE, |
288 | PARTITION_TABLE_TYPE, |
289 | ) |
290 | -from maasserver.models.partitiontable import INITIAL_PARTITION_OFFSET |
291 | +from maasserver.models.partitiontable import ( |
292 | + INITIAL_PARTITION_OFFSET, |
293 | + PREP_PARTITION_SIZE, |
294 | +) |
295 | from maasserver.models.physicalblockdevice import PhysicalBlockDevice |
296 | from maasserver.models.virtualblockdevice import VirtualBlockDevice |
297 | import yaml |
298 | @@ -34,6 +37,7 @@ |
299 | def __init__(self, node): |
300 | self.node = node |
301 | self.boot_disk = node.get_boot_disk() |
302 | + self.boot_disk_first_partition = None |
303 | self.operations = { |
304 | "disk": [], |
305 | "partition": [], |
306 | @@ -111,6 +115,13 @@ |
307 | raise ValueError("Unknown block device instance: %s" % ( |
308 | block_device.__class__.__name__)) |
309 | |
310 | + def _requires_prep_partition(self, block_device): |
311 | + """Return True if block device requires the prep partition.""" |
312 | + arch, _ = self.node.split_arch() |
313 | + return ( |
314 | + self.boot_disk.id == block_device.id and |
315 | + arch == "ppc64el") |
316 | + |
317 | def _add_partition_operations(self): |
318 | """Add all the partition operations. |
319 | |
320 | @@ -118,9 +129,16 @@ |
321 | attached to the node. |
322 | """ |
323 | for block_device in self.node.blockdevice_set.order_by('id'): |
324 | + requires_prep = self._requires_prep_partition(block_device) |
325 | partition_table = block_device.get_partitiontable() |
326 | if partition_table is not None: |
327 | - for partition in partition_table.partitions.order_by('id'): |
328 | + partitions = list(partition_table.partitions.order_by('id')) |
329 | + for idx, partition in enumerate(partitions): |
330 | + # If this is the last partition and prep partition is |
331 | + # required then set boot_disk_first_partition so extra |
332 | + # space can be removed. |
333 | + if requires_prep and idx == 0: |
334 | + self.boot_disk_first_partition = partition |
335 | self.operations["partition"].append(partition) |
336 | |
337 | def _add_format_and_mount_operations(self): |
338 | @@ -180,21 +198,35 @@ |
339 | |
340 | # Set the partition table type if a partition table exists or if this |
341 | # is the boot disk. |
342 | + add_prep_partition = False |
343 | partition_table = block_device.get_partitiontable() |
344 | if partition_table is not None: |
345 | disk_operation["ptable"] = self._get_ptable_type( |
346 | partition_table) |
347 | elif block_device.id == self.boot_disk.id: |
348 | - if self.node.get_bios_boot_method() == "uefi": |
349 | + bios_boot_method = self.node.get_bios_boot_method() |
350 | + node_arch, _ = self.node.split_arch() |
351 | + if bios_boot_method in [ |
352 | + "uefi", "powernv", "powerkvm"]: |
353 | disk_operation["ptable"] = "gpt" |
354 | + if node_arch == "ppc64el": |
355 | + add_prep_partition = True |
356 | else: |
357 | disk_operation["ptable"] = "msdos" |
358 | |
359 | - # Set this disk to be the grub device if its the boot disk. |
360 | - if self.boot_disk == block_device: |
361 | + # Set this disk to be the grub device if it's the boot disk and doesn't |
362 | + # require a prep partition. When a prep partition is required grub |
363 | + # must be installed on that partition and not in the partition header |
364 | + # of that disk. |
365 | + requires_prep = self._requires_prep_partition(block_device) |
366 | + if self.boot_disk.id == block_device.id and not requires_prep: |
367 | disk_operation["grub_device"] = True |
368 | self.storage_config.append(disk_operation) |
369 | |
370 | + # Add the prep partition at the end of the disk when it is required. |
371 | + if add_prep_partition: |
372 | + self._generate_prep_partition(block_device.get_name()) |
373 | + |
374 | def _get_ptable_type(self, partition_table): |
375 | """Return the value for the "ptable" entry in the physical operation. |
376 | """ |
377 | @@ -207,12 +239,38 @@ |
378 | "Unknown partition table type: %s" % ( |
379 | partition_table.table_type)) |
380 | |
381 | + def _generate_prep_partition(self, device_name): |
382 | + """Generate the prep partition at the beginning of the block device.""" |
383 | + prep_part_name = "%s-part1" % (device_name) |
384 | + partition_operation = { |
385 | + "id": prep_part_name, |
386 | + "name": prep_part_name, |
387 | + "type": "partition", |
388 | + "number": 1, |
389 | + "offset": "%dB" % INITIAL_PARTITION_OFFSET, |
390 | + "size": "%dB" % PREP_PARTITION_SIZE, |
391 | + "device": device_name, |
392 | + "wipe": "zero", |
393 | + "flag": "prep", |
394 | + "grub_device": True, |
395 | + } |
396 | + self.storage_config.append(partition_operation) |
397 | + |
398 | def _generate_partition_operations(self): |
399 | """Generate all partition operations.""" |
400 | for partition in self.operations["partition"]: |
401 | - self._generate_partition_operation(partition) |
402 | + if partition == self.boot_disk_first_partition: |
403 | + # This is the first partition in the boot disk and add prep |
404 | + # partition at the beginning of the partition table. |
405 | + device_name = partition.partition_table.block_device.get_name() |
406 | + self._generate_prep_partition(device_name) |
407 | + self._generate_partition_operation( |
408 | + partition, include_initial=False) |
409 | + else: |
410 | + self._generate_partition_operation( |
411 | + partition, include_initial=True) |
412 | |
413 | - def _generate_partition_operation(self, partition): |
414 | + def _generate_partition_operation(self, partition, include_initial): |
415 | """Generate partition operation for `partition` and place in |
416 | `storage_config`.""" |
417 | partition_table = partition.partition_table |
418 | @@ -229,7 +287,7 @@ |
419 | "wipe": "superblock", |
420 | } |
421 | # First partition always sets the initial offset. |
422 | - if partition_number == 1: |
423 | + if partition_number == 1 and include_initial: |
424 | partition_operation["offset"] = "%sB" % INITIAL_PARTITION_OFFSET |
425 | if partition.bootable: |
426 | partition_operation["flag"] = "boot" |
427 | |
428 | === modified file 'src/maasserver/static/js/angular/controllers/node_details_storage.js' |
429 | --- src/maasserver/static/js/angular/controllers/node_details_storage.js 2015-11-20 17:36:10 +0000 |
430 | +++ src/maasserver/static/js/angular/controllers/node_details_storage.js 2016-02-24 16:23:03 +0000 |
431 | @@ -51,6 +51,7 @@ |
432 | var END_OF_PARTITION_TABLE_SPACE = 1024 * 1024; |
433 | var PARTITION_TABLE_EXTRA_SPACE = INITIAL_PARTITION_OFFSET + |
434 | END_OF_PARTITION_TABLE_SPACE; |
435 | + var PREP_PARTITION_SIZE = 8 * 1024 * 1024; |
436 | |
437 | // From models/partition.py - must be kept in sync. |
438 | var PARTITION_ALIGNMENT_SIZE = 4 * 1024 * 1024; |
439 | @@ -855,6 +856,11 @@ |
440 | || disk.original.partition_table_type === "") { |
441 | // Disk has no partition table, so reserve space for it. |
442 | space_to_reserve = PARTITION_TABLE_EXTRA_SPACE; |
443 | + // ppc64el node requires that space be saved for the prep |
444 | + // partition. |
445 | + if($scope.node.architecture.indexOf("ppc64el") === 0) { |
446 | + space_to_reserve += PREP_PARTITION_SIZE; |
447 | + } |
448 | } |
449 | return ConverterService.roundByBlockSize( |
450 | disk.original.available_size - space_to_reserve, |
451 | @@ -1130,6 +1136,11 @@ |
452 | if(disk.original.partition_table_type === "mbr" && |
453 | length > 2) { |
454 | return disk.name + "-part" + (length + 2); |
455 | + } else if($scope.node.architecture.indexOf("ppc64el") === 0 && |
456 | + disk.original.is_boot) { |
457 | + // Boot disk on ppc64el machines skip the first partition as |
458 | + // its reserved for the prep partition. |
459 | + return disk.name + "-part" + (length + 2); |
460 | } else { |
461 | return disk.name + "-part" + (length + 1); |
462 | } |
463 | |
464 | === modified file 'src/maasserver/static/js/angular/controllers/tests/test_node_details_storage.js' |
465 | --- src/maasserver/static/js/angular/controllers/tests/test_node_details_storage.js 2015-11-20 17:36:10 +0000 |
466 | +++ src/maasserver/static/js/angular/controllers/tests/test_node_details_storage.js 2016-02-24 16:23:03 +0000 |
467 | @@ -101,6 +101,7 @@ |
468 | var node, updateNodeSpy, canEditSpy; |
469 | beforeEach(function() { |
470 | node = { |
471 | + architecture: "amd64/generic", |
472 | disks: [] |
473 | }; |
474 | updateNodeSpy = jasmine.createSpy("updateNode"); |
475 | @@ -1455,6 +1456,25 @@ |
476 | expect($scope.canAddPartition(disk)).toBe(false); |
477 | }); |
478 | |
479 | + it("returns false if available_size is less than partition size " + |
480 | + "when node is ppc64el architecture", |
481 | + function() { |
482 | + var controller = makeController(); |
483 | + var disk = { |
484 | + type: "physical", |
485 | + fstype: "", |
486 | + original: { |
487 | + partition_table_type: null, |
488 | + available_size: (2.5 * 1024 * 1024) + (8 * 1024 * 1024), |
489 | + block_size: 1024 |
490 | + } |
491 | + }; |
492 | + node.architecture = "ppc64el/generic"; |
493 | + spyOn($scope, "isAllStorageDisabled").and.returnValue(false); |
494 | + $scope.isSuperUser = function() { return true; }; |
495 | + expect($scope.canAddPartition(disk)).toBe(false); |
496 | + }); |
497 | + |
498 | it("returns false if not super user", function() { |
499 | var controller = makeController(); |
500 | var disk = { |
501 | @@ -2350,6 +2370,37 @@ |
502 | expect($scope.getAddPartitionName(disk)).toBe(name + "-part3"); |
503 | }); |
504 | |
505 | + it("returns disk.name with -part2 for ppc64el", function() { |
506 | + node.architecture = "ppc64el/generic"; |
507 | + var controller = makeController(); |
508 | + var name = makeName("sda"); |
509 | + var disk = { |
510 | + name: name, |
511 | + original: { |
512 | + is_boot: true, |
513 | + partition_table_type: "gpt" |
514 | + } |
515 | + }; |
516 | + |
517 | + expect($scope.getAddPartitionName(disk)).toBe(name + "-part2"); |
518 | + }); |
519 | + |
520 | + it("returns disk.name with -part4 for ppc64el", function() { |
521 | + node.architecture = "ppc64el/generic"; |
522 | + var controller = makeController(); |
523 | + var name = makeName("sda"); |
524 | + var disk = { |
525 | + name: name, |
526 | + original: { |
527 | + is_boot: true, |
528 | + partition_table_type: "gpt", |
529 | + partitions: [{}, {}] |
530 | + } |
531 | + }; |
532 | + |
533 | + expect($scope.getAddPartitionName(disk)).toBe(name + "-part4"); |
534 | + }); |
535 | + |
536 | it("returns disk.name with -part3 for MBR", function() { |
537 | var controller = makeController(); |
538 | var name = makeName("sda"); |
539 | |
540 | === modified file 'src/maasserver/storage_layouts.py' |
541 | --- src/maasserver/storage_layouts.py 2015-10-07 23:07:32 +0000 |
542 | +++ src/maasserver/storage_layouts.py 2016-02-24 16:23:03 +0000 |
543 | @@ -178,7 +178,12 @@ |
544 | from maasserver.models.partitiontable import PartitionTable |
545 | boot_partition_table = PartitionTable.objects.create( |
546 | block_device=self.boot_disk) |
547 | - if boot_partition_table.table_type == PARTITION_TABLE_TYPE.GPT: |
548 | + bios_boot_method = self.node.get_bios_boot_method() |
549 | + node_arch, _ = self.node.split_arch() |
550 | + if (boot_partition_table.table_type == PARTITION_TABLE_TYPE.GPT and |
551 | + bios_boot_method == "uefi" and node_arch != "ppc64el"): |
552 | + # Add EFI partition only if booting UEFI and not a ppc64el |
553 | + # architecture. |
554 | efi_partition = boot_partition_table.add_partition( |
555 | size=EFI_PARTITION_SIZE, bootable=True) |
556 | Filesystem.objects.create( |
557 | |
558 | === modified file 'src/maasserver/tests/test_preseed_storage.py' |
559 | --- src/maasserver/tests/test_preseed_storage.py 2015-11-17 23:19:51 +0000 |
560 | +++ src/maasserver/tests/test_preseed_storage.py 2016-02-24 16:23:03 +0000 |
561 | @@ -28,7 +28,10 @@ |
562 | RAID, |
563 | VolumeGroup, |
564 | ) |
565 | -from maasserver.models.partitiontable import PARTITION_TABLE_EXTRA_SPACE |
566 | +from maasserver.models.partitiontable import ( |
567 | + PARTITION_TABLE_EXTRA_SPACE, |
568 | + PREP_PARTITION_SIZE, |
569 | +) |
570 | from maasserver.preseed_storage import compose_curtin_storage_config |
571 | from maasserver.testing.factory import factory |
572 | from maasserver.testing.testcase import MAASServerTestCase |
573 | @@ -757,3 +760,214 @@ |
574 | node._create_acquired_filesystems() |
575 | config = compose_curtin_storage_config(node) |
576 | self.assertStorageConfig(self.STORAGE_CONFIG, config) |
577 | + |
578 | + |
579 | +class TestSimplePower8Layout(MAASServerTestCase, AssertStorageConfigMixin): |
580 | + |
581 | + STORAGE_CONFIG = dedent("""\ |
582 | + config: |
583 | + - id: sda |
584 | + name: sda |
585 | + type: disk |
586 | + wipe: superblock |
587 | + ptable: gpt |
588 | + model: QEMU HARDDISK |
589 | + serial: QM00001 |
590 | + - id: sda-part1 |
591 | + name: sda-part1 |
592 | + type: partition |
593 | + number: 1 |
594 | + offset: 4194304B |
595 | + size: 8388608B |
596 | + device: sda |
597 | + wipe: zero |
598 | + flag: prep |
599 | + grub_device: True |
600 | + - id: sda-part2 |
601 | + name: sda-part2 |
602 | + type: partition |
603 | + number: 2 |
604 | + uuid: f74ff260-2a5b-4a36-b1b8-37f746b946bf |
605 | + size: 8573157376B |
606 | + wipe: superblock |
607 | + device: sda |
608 | + - id: sda-part2_format |
609 | + type: format |
610 | + fstype: ext4 |
611 | + label: root |
612 | + uuid: 90a69b22-e281-4c5b-8df9-b09514f27ba1 |
613 | + volume: sda-part2 |
614 | + - id: sda-part2_mount |
615 | + type: mount |
616 | + path: / |
617 | + device: sda-part2_format |
618 | + """) |
619 | + |
620 | + def test__renders_expected_output(self): |
621 | + node = factory.make_Node( |
622 | + status=NODE_STATUS.ALLOCATED, architecture="ppc64el/generic", |
623 | + bios_boot_method="uefi", with_boot_disk=False) |
624 | + boot_disk = factory.make_PhysicalBlockDevice( |
625 | + node=node, size=8 * 1024 ** 3, name="sda", |
626 | + model="QEMU HARDDISK", serial="QM00001") # 8 GiB |
627 | + partition_table = factory.make_PartitionTable( |
628 | + table_type=PARTITION_TABLE_TYPE.GPT, block_device=boot_disk) |
629 | + root_partition = factory.make_Partition( |
630 | + partition_table=partition_table, |
631 | + uuid="f74ff260-2a5b-4a36-b1b8-37f746b946bf", |
632 | + size=( |
633 | + (8 * 1024 ** 3) - PARTITION_TABLE_EXTRA_SPACE - |
634 | + PREP_PARTITION_SIZE), |
635 | + bootable=False) |
636 | + factory.make_Filesystem( |
637 | + partition=root_partition, fstype=FILESYSTEM_TYPE.EXT4, |
638 | + uuid="90a69b22-e281-4c5b-8df9-b09514f27ba1", label="root", |
639 | + mount_point="/") |
640 | + node._create_acquired_filesystems() |
641 | + config = compose_curtin_storage_config(node) |
642 | + self.assertStorageConfig(self.STORAGE_CONFIG, config) |
643 | + |
644 | + |
645 | +class TestPower8ExtraSpaceLayout( |
646 | + MAASServerTestCase, AssertStorageConfigMixin): |
647 | + |
648 | + STORAGE_CONFIG = dedent("""\ |
649 | + config: |
650 | + - id: sda |
651 | + name: sda |
652 | + type: disk |
653 | + wipe: superblock |
654 | + ptable: gpt |
655 | + model: QEMU HARDDISK |
656 | + serial: QM00001 |
657 | + - id: sda-part1 |
658 | + name: sda-part1 |
659 | + type: partition |
660 | + number: 1 |
661 | + offset: 4194304B |
662 | + size: 8388608B |
663 | + device: sda |
664 | + wipe: zero |
665 | + flag: prep |
666 | + grub_device: True |
667 | + - id: sda-part2 |
668 | + name: sda-part2 |
669 | + type: partition |
670 | + number: 2 |
671 | + uuid: f74ff260-2a5b-4a36-b1b8-37f746b946bf |
672 | + size: 7507804160B |
673 | + wipe: superblock |
674 | + device: sda |
675 | + - id: sda-part2_format |
676 | + type: format |
677 | + fstype: ext4 |
678 | + label: root |
679 | + uuid: 90a69b22-e281-4c5b-8df9-b09514f27ba1 |
680 | + volume: sda-part2 |
681 | + - id: sda-part2_mount |
682 | + type: mount |
683 | + path: / |
684 | + device: sda-part2_format |
685 | + """) |
686 | + |
687 | + def test__renders_expected_output(self): |
688 | + node = factory.make_Node( |
689 | + status=NODE_STATUS.ALLOCATED, architecture="ppc64el/generic", |
690 | + bios_boot_method="uefi", with_boot_disk=False) |
691 | + boot_disk = factory.make_PhysicalBlockDevice( |
692 | + node=node, size=8 * 1024 ** 3, name="sda", |
693 | + model="QEMU HARDDISK", serial="QM00001") # 8 GiB |
694 | + partition_table = factory.make_PartitionTable( |
695 | + table_type=PARTITION_TABLE_TYPE.GPT, block_device=boot_disk) |
696 | + root_partition = factory.make_Partition( |
697 | + partition_table=partition_table, |
698 | + uuid="f74ff260-2a5b-4a36-b1b8-37f746b946bf", |
699 | + size=(7 * 1024 ** 3) - PARTITION_TABLE_EXTRA_SPACE, |
700 | + bootable=False) |
701 | + factory.make_Filesystem( |
702 | + partition=root_partition, fstype=FILESYSTEM_TYPE.EXT4, |
703 | + uuid="90a69b22-e281-4c5b-8df9-b09514f27ba1", label="root", |
704 | + mount_point="/") |
705 | + node._create_acquired_filesystems() |
706 | + config = compose_curtin_storage_config(node) |
707 | + self.assertStorageConfig(self.STORAGE_CONFIG, config) |
708 | + |
709 | + |
710 | +class TestPower8NoPartitionTableLayout( |
711 | + MAASServerTestCase, AssertStorageConfigMixin): |
712 | + |
713 | + STORAGE_CONFIG = dedent("""\ |
714 | + config: |
715 | + - id: sda |
716 | + name: sda |
717 | + type: disk |
718 | + wipe: superblock |
719 | + ptable: gpt |
720 | + model: QEMU HARDDISK |
721 | + serial: QM00001 |
722 | + - id: sdb |
723 | + name: sdb |
724 | + type: disk |
725 | + wipe: superblock |
726 | + ptable: gpt |
727 | + model: QEMU HARDDISK |
728 | + serial: QM00002 |
729 | + - id: sdb-part1 |
730 | + name: sdb-part1 |
731 | + type: partition |
732 | + number: 1 |
733 | + offset: 4194304B |
734 | + size: 8388608B |
735 | + device: sdb |
736 | + wipe: zero |
737 | + flag: prep |
738 | + grub_device: True |
739 | + - id: sda-part1 |
740 | + name: sda-part1 |
741 | + type: partition |
742 | + number: 1 |
743 | + uuid: f74ff260-2a5b-4a36-b1b8-37f746b946bf |
744 | + offset: 4194304B |
745 | + size: 8573157376B |
746 | + wipe: superblock |
747 | + device: sda |
748 | + - id: sda-part1_format |
749 | + type: format |
750 | + fstype: ext4 |
751 | + label: root |
752 | + uuid: 90a69b22-e281-4c5b-8df9-b09514f27ba1 |
753 | + volume: sda-part1 |
754 | + - id: sda-part1_mount |
755 | + type: mount |
756 | + path: / |
757 | + device: sda-part1_format |
758 | + """) |
759 | + |
760 | + def test__renders_expected_output(self): |
761 | + node = factory.make_Node( |
762 | + status=NODE_STATUS.ALLOCATED, architecture="ppc64el/generic", |
763 | + bios_boot_method="uefi", with_boot_disk=False) |
764 | + root_disk = factory.make_PhysicalBlockDevice( |
765 | + node=node, size=8 * 1024 ** 3, name="sda", |
766 | + model="QEMU HARDDISK", serial="QM00001") # 8 GiB |
767 | + partition_table = factory.make_PartitionTable( |
768 | + table_type=PARTITION_TABLE_TYPE.GPT, block_device=root_disk) |
769 | + boot_disk = factory.make_PhysicalBlockDevice( |
770 | + node=node, size=8 * 1024 ** 3, name="sdb", |
771 | + model="QEMU HARDDISK", serial="QM00002") # 8 GiB |
772 | + node.boot_disk = boot_disk |
773 | + node.save() |
774 | + root_partition = factory.make_Partition( |
775 | + partition_table=partition_table, |
776 | + uuid="f74ff260-2a5b-4a36-b1b8-37f746b946bf", |
777 | + size=( |
778 | + (8 * 1024 ** 3) - PARTITION_TABLE_EXTRA_SPACE - |
779 | + PREP_PARTITION_SIZE), |
780 | + bootable=False) |
781 | + factory.make_Filesystem( |
782 | + partition=root_partition, fstype=FILESYSTEM_TYPE.EXT4, |
783 | + uuid="90a69b22-e281-4c5b-8df9-b09514f27ba1", label="root", |
784 | + mount_point="/") |
785 | + node._create_acquired_filesystems() |
786 | + config = compose_curtin_storage_config(node) |
787 | + self.assertStorageConfig(self.STORAGE_CONFIG, config) |
788 | |
789 | === modified file 'src/maasserver/tests/test_storage_layouts.py' |
790 | --- src/maasserver/tests/test_storage_layouts.py 2015-11-17 23:19:51 +0000 |
791 | +++ src/maasserver/tests/test_storage_layouts.py 2016-02-24 16:23:03 +0000 |
792 | @@ -29,7 +29,10 @@ |
793 | MAX_PARTITION_SIZE_FOR_MBR, |
794 | PARTITION_ALIGNMENT_SIZE, |
795 | ) |
796 | -from maasserver.models.partitiontable import PARTITION_TABLE_EXTRA_SPACE |
797 | +from maasserver.models.partitiontable import ( |
798 | + PARTITION_TABLE_EXTRA_SPACE, |
799 | + PREP_PARTITION_SIZE, |
800 | +) |
801 | from maasserver.storage_layouts import ( |
802 | BcacheStorageLayout, |
803 | BcacheStorageLayoutBase, |
804 | @@ -63,6 +66,20 @@ |
805 | return factory.make_Node(*args, **kwargs) |
806 | |
807 | |
808 | +def make_ppc64el_Node_with_powernv_boot_method(*args, **kwargs): |
809 | + kwargs['bios_boot_method'] = "powernv" |
810 | + kwargs['with_boot_disk'] = False |
811 | + kwargs['architecture'] = "ppc64el/generic" |
812 | + return factory.make_Node(*args, **kwargs) |
813 | + |
814 | + |
815 | +def make_ppc64el_Node_with_uefi_boot_method(*args, **kwargs): |
816 | + kwargs['bios_boot_method'] = "powerkvm" |
817 | + kwargs['with_boot_disk'] = False |
818 | + kwargs['architecture'] = "ppc64el/generic" |
819 | + return factory.make_Node(*args, **kwargs) |
820 | + |
821 | + |
822 | class TestFormHelpers(MAASServerTestCase): |
823 | |
824 | def test_get_storage_layout_choices(self): |
825 | @@ -514,6 +531,66 @@ |
826 | mount_point="/", |
827 | )) |
828 | |
829 | + def test__creates_layout_for_powernv(self): |
830 | + node = make_ppc64el_Node_with_powernv_boot_method() |
831 | + boot_disk = factory.make_PhysicalBlockDevice( |
832 | + node=node, size=LARGE_BLOCK_DEVICE) |
833 | + layout = FlatStorageLayout(node) |
834 | + layout.configure() |
835 | + |
836 | + # Validate partition table. |
837 | + partition_table = boot_disk.get_partitiontable() |
838 | + self.assertEqual(PARTITION_TABLE_TYPE.GPT, partition_table.table_type) |
839 | + |
840 | + # Validate root partition. |
841 | + partitions = partition_table.partitions.order_by('id').all() |
842 | + root_partition = partitions[0] |
843 | + self.assertIsNotNone(root_partition) |
844 | + self.assertEqual( |
845 | + round_size_to_nearest_block( |
846 | + boot_disk.size - PARTITION_TABLE_EXTRA_SPACE - |
847 | + PREP_PARTITION_SIZE, |
848 | + PARTITION_ALIGNMENT_SIZE, |
849 | + False), |
850 | + root_partition.size) |
851 | + self.assertThat( |
852 | + root_partition.get_effective_filesystem(), |
853 | + MatchesStructure.byEquality( |
854 | + fstype=FILESYSTEM_TYPE.EXT4, |
855 | + label="root", |
856 | + mount_point="/", |
857 | + )) |
858 | + |
859 | + def test__creates_layout_for_powerkvm(self): |
860 | + node = make_ppc64el_Node_with_uefi_boot_method() |
861 | + boot_disk = factory.make_PhysicalBlockDevice( |
862 | + node=node, size=LARGE_BLOCK_DEVICE) |
863 | + layout = FlatStorageLayout(node) |
864 | + layout.configure() |
865 | + |
866 | + # Validate partition table. |
867 | + partition_table = boot_disk.get_partitiontable() |
868 | + self.assertEqual(PARTITION_TABLE_TYPE.GPT, partition_table.table_type) |
869 | + |
870 | + # Validate root partition. |
871 | + partitions = partition_table.partitions.order_by('id').all() |
872 | + root_partition = partitions[0] |
873 | + self.assertIsNotNone(root_partition) |
874 | + self.assertEqual( |
875 | + round_size_to_nearest_block( |
876 | + boot_disk.size - PARTITION_TABLE_EXTRA_SPACE - |
877 | + PREP_PARTITION_SIZE, |
878 | + PARTITION_ALIGNMENT_SIZE, |
879 | + False), |
880 | + root_partition.size) |
881 | + self.assertThat( |
882 | + root_partition.get_effective_filesystem(), |
883 | + MatchesStructure.byEquality( |
884 | + fstype=FILESYSTEM_TYPE.EXT4, |
885 | + label="root", |
886 | + mount_point="/", |
887 | + )) |
888 | + |
889 | def test__creates_layout_with_uefi_defaults(self): |
890 | node = make_Node_with_uefi_boot_method() |
891 | boot_disk = factory.make_PhysicalBlockDevice( |
892 | |
893 | === modified file 'src/provisioningserver/boot/powerkvm.py' |
894 | --- src/provisioningserver/boot/powerkvm.py 2015-10-29 16:19:48 +0000 |
895 | +++ src/provisioningserver/boot/powerkvm.py 2016-02-24 16:23:03 +0000 |
896 | @@ -41,7 +41,7 @@ |
897 | class PowerKVMBootMethod(BootMethod): |
898 | |
899 | name = "powerkvm" |
900 | - bios_boot_method = "pxe" |
901 | + bios_boot_method = "powerkvm" |
902 | template_subdir = None |
903 | bootloader_path = "bootppc64.bin" |
904 | bootloader_arches = ['ppc64el'] |
905 | |
906 | === modified file 'src/provisioningserver/boot/powernv.py' |
907 | --- src/provisioningserver/boot/powernv.py 2015-08-14 13:48:59 +0000 |
908 | +++ src/provisioningserver/boot/powernv.py 2016-02-24 16:23:03 +0000 |
909 | @@ -68,7 +68,7 @@ |
910 | class PowerNVBootMethod(BootMethod): |
911 | |
912 | name = "powernv" |
913 | - bios_boot_method = "pxe" |
914 | + bios_boot_method = "powernv" |
915 | template_subdir = "pxe" |
916 | bootloader_path = "pxelinux.0" |
917 | arch_octet = "00:0E" |
Backport self-review: https:/ /code.launchpad .net/~blake- rouse/maas/ fix-power8/ +merge/ 285234