Merge lp:~blake-rouse/maas/fix-power8-1.9 into lp:maas/1.9

Proposed by Blake Rouse
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
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.

To post a comment you must log in.
Revision history for this message
Blake Rouse (blake-rouse) wrote :
review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :
Download full text (1.0 MiB)

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://prodstack-zone-1.clouds.archive.ubuntu.com trusty InRelease
Get:1 http://security.ubuntu.com trusty-security InRelease [65.9 kB]
Get:2 http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-updates InRelease [65.9 kB]
Get:3 http://security.ubuntu.com trusty-security/main Sources [105 kB]
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-backports InRelease
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com trusty Release.gpg
Get:4 http://security.ubuntu.com trusty-security/universe Sources [33.0 kB]
Get:5 http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-updates/main Sources [260 kB]
Get:6 http://security.ubuntu.com trusty-security/main amd64 Packages [427 kB]
Get:7 http://security.ubuntu.com trusty-security/universe amd64 Packages [123 kB]
Hit http://security.ubuntu.com trusty-security/main Translation-en
Hit http://security.ubuntu.com trusty-security/universe Translation-en
Get:8 http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-updates/restricted Sources [5,352 B]
Get:9 http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-updates/universe Sources [150 kB]
Get:10 http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-updates/multiverse Sources [5,547 B]
Get:11 http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-updates/main amd64 Packages [709 kB]
Get:12 http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-updates/restricted amd64 Packages [15.9 kB]
Get:13 http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-updates/universe amd64 Packages [338 kB]
Get:14 http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-updates/multiverse amd64 Packages [13.2 kB]
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-updates/main Translation-en
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-updates/multiverse Translation-en
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-updates/restricted Translation-en
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-updates/universe Translation-en
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-backports/main Sources
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-backports/restricted Sources
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-backports/universe Sources
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-backports/multiverse Sources
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-backports/main amd64 Packages
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-backports/restricted amd64 Packages
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-backports/universe amd64 Packages
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-backports/multiverse amd64 Packages
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-backports/main Translation-en
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-backports/multiverse Translation-en
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com trusty-backports/restricted Translation-en
Hit http://prodstack-zone-1.clouds.archive...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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"

Subscribers

People subscribed via source and target branches