Merge lp:~oddbloke/cloud-init/lp1460715 into lp:~cloud-init-dev/cloud-init/trunk

Proposed by Dan Watkins
Status: Merged
Merge reported by: Scott Moser
Merged at revision: not available
Proposed branch: lp:~oddbloke/cloud-init/lp1460715
Merge into: lp:~cloud-init-dev/cloud-init/trunk
Diff against target: 135 lines (+76/-8)
2 files modified
cloudinit/config/cc_disk_setup.py (+8/-8)
tests/unittests/test_handler/test_handler_disk_setup.py (+68/-0)
To merge this branch: bzr merge lp:~oddbloke/cloud-init/lp1460715
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Needs Fixing
cloud-init Commiters Pending
Review via email: mp+274897@code.launchpad.net

Commit message

[cc_disk_setup] Use sectors to resize MBR disks

The version of sfdisk in wily (and onwards) only accepts sectors as a valid disk size. As such, this refactors the MBR code path in cc_disk_setup to use sectors.

Description of the change

X-CPC-Summary-Skip: 1

To post a comment you must log in.
Revision history for this message
Scott Moser (smoser) wrote :

some comments inline.
other thing.. it seems like it would make sense to partition assuming sectors of 4096 bytes. just to ensure alignment or to round all partition sizes to 1MB or even 4MB.

if the user has just given us such course grained data as percentage, it seems we have some wiggle room to work with and should try to do same things.

for reference it seems that /sys/block/sda/queue/hw_sector_size has sector sizes. i'm not sure that i'd bother caring though wether there was 512 or 4096 there. I'm thinking just easiest to never partition in smaller units than 4096.

Revision history for this message
Dan Watkins (oddbloke) :
Revision history for this message
Scott Moser (smoser) wrote :

Dan and I discussed some and both of us were not sure if sfdisk's sectors were physical or logical sectors.

I did some testing with kvm and it turns out it uses logical sectors.
That unit is the same you'd get back from 'blockdev --getss' that value can also be read from /sys/

see http://paste.ubuntu.com/12864114/ for exampe (note, it didn't do one with 512/4096, but other tests do verify that logical is what is used).

lp:~oddbloke/cloud-init/lp1460715 updated
1152. By Dan Watkins

Switch to using sectors for MBR disk setup.

Revision history for this message
Dan Watkins (oddbloke) wrote :

Right, I've updated the patch to use blockdev to find the size and sector size, which allows us to calculate the size of a disk in sectors.

I've tested this on wily and trusty, and it worked in both cases.

Revision history for this message
Scott Moser (smoser) wrote :

I'd like to read /sys if we can. blockdev is fine, but that costs us 2 subprocesses for information that we could conceivably read.

one last comment i should have added for reference later was that an example qemu command line where we provide all the sizes is like:

qemu-system-x86_64 -enable-kvm -drive file=/tmp/tmp.uCSmIFVSuA/disk.img,if=none,id=disk_img_1,format=qcow2 -device virtio-blk-pci,bootindex=1,scsi=off,drive=disk_img_1,id=virtio-disk-1, -drive file=/tmp/tmp.uCSmIFVSuA/extra.img,if=none,id=disk_img_2,format=raw -device virtio-blk-pci,bootindex=2,scsi=off,drive=disk_img_2,id=virtio-disk-2,physical_block_size=4096,logical_block_size=4096,min_io_size=4096,opt_io_size=4096, -device virtio-net-pci,netdev=net00 -netdev type=user,id=net00 -m 768 -echr 0x05 -nographic

Revision history for this message
Scott Moser (smoser) wrote :

Dan,
I'm ok to go with blockdev usage for now.
Could you set a nice commit message on this MP?

Revision history for this message
Dan Watkins (oddbloke) wrote :

Nice commit message set.

Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Scott Moser (smoser) wrote :

Merged with some updates at git commit 18203bf101dc04c28b53a92cd95c8be88959c428
https://git.launchpad.net/cloud-init/commit/18203bf101dc04c28b53a92cd95c8be88959c428

Revision history for this message
Scott Moser (smoser) wrote :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cloudinit/config/cc_disk_setup.py'
2--- cloudinit/config/cc_disk_setup.py 2015-07-22 19:14:33 +0000
3+++ cloudinit/config/cc_disk_setup.py 2015-10-20 09:28:10 +0000
4@@ -16,12 +16,13 @@
5 #
6 # You should have received a copy of the GNU General Public License
7 # along with this program. If not, see <http://www.gnu.org/licenses/>.
8-from cloudinit.settings import PER_INSTANCE
9-from cloudinit import util
10 import logging
11 import os
12 import shlex
13
14+from cloudinit import util
15+from cloudinit.settings import PER_INSTANCE
16+
17 frequency = PER_INSTANCE
18
19 # Define the commands to use
20@@ -343,14 +344,13 @@
21
22
23 def get_mbr_hdd_size(device):
24- size_cmd = [SFDISK_CMD, '--show-size', device]
25- size = None
26 try:
27- size, _err = util.subp(size_cmd)
28+ size_in_bytes, _ = util.subp([BLKDEV_CMD, '--getsize64', device])
29+ sector_size, _ = util.subp([BLKDEV_CMD, '--getss', device])
30 except Exception as e:
31 raise Exception("Failed to get %s size\n%s" % (device, e))
32
33- return int(size.strip())
34+ return int(size_in_bytes) / int(sector_size)
35
36
37 def get_gpt_hdd_size(device):
38@@ -492,7 +492,7 @@
39 raise Exception("Partition was incorrectly defined: %s" % part)
40 percent, part_type = part
41
42- part_size = int((float(size) * (float(percent) / 100)) / 1024)
43+ part_size = int(float(size) * (float(percent) / 100))
44
45 if part_num == last_part_num:
46 part_definition.append(",,%s" % part_type)
47@@ -596,7 +596,7 @@
48 types, i.e. gpt
49 """
50 # Create the partitions
51- prt_cmd = [SFDISK_CMD, "--Linux", "-uM", device]
52+ prt_cmd = [SFDISK_CMD, device]
53 try:
54 util.subp(prt_cmd, data="%s\n" % layout)
55 except Exception as e:
56
57=== modified file 'tests/unittests/test_handler/test_handler_disk_setup.py'
58--- tests/unittests/test_handler/test_handler_disk_setup.py 2015-03-18 13:32:54 +0000
59+++ tests/unittests/test_handler/test_handler_disk_setup.py 2015-10-20 09:28:10 +0000
60@@ -1,3 +1,5 @@
61+import random
62+
63 from cloudinit.config import cc_disk_setup
64 from ..helpers import ExitStack, mock, TestCase
65
66@@ -28,3 +30,69 @@
67 self.enumerate_disk.return_value = (mock.MagicMock() for _ in range(1))
68 self.check_fs.return_value = (mock.MagicMock(), None, mock.MagicMock())
69 self.assertFalse(cc_disk_setup.is_disk_used(mock.MagicMock()))
70+
71+
72+class TestGetMbrHddSize(TestCase):
73+
74+ def setUp(self):
75+ super(TestGetMbrHddSize, self).setUp()
76+ self.patches = ExitStack()
77+ self.subp = self.patches.enter_context(
78+ mock.patch.object(cc_disk_setup.util, 'subp'))
79+
80+ def _configure_subp_mock(self, hdd_size_in_bytes, sector_size_in_bytes):
81+ def _subp(cmd, *args, **kwargs):
82+ self.assertEqual(3, len(cmd))
83+ if '--getsize64' in cmd:
84+ return hdd_size_in_bytes, None
85+ elif '--getss' in cmd:
86+ return sector_size_in_bytes, None
87+ raise Exception('Unexpected blockdev command called')
88+
89+ self.subp.side_effect = _subp
90+
91+ def _test_for_sector_size(self, sector_size):
92+ size_in_bytes = random.randint(10000, 10000000) * 512
93+ size_in_sectors = size_in_bytes / sector_size
94+ self._configure_subp_mock(size_in_bytes, sector_size)
95+ self.assertEqual(size_in_sectors,
96+ cc_disk_setup.get_mbr_hdd_size('/dev/sda1'))
97+
98+ def test_size_for_512_byte_sectors(self):
99+ self._test_for_sector_size(512)
100+
101+ def test_size_for_1024_byte_sectors(self):
102+ self._test_for_sector_size(1024)
103+
104+ def test_size_for_2048_byte_sectors(self):
105+ self._test_for_sector_size(2048)
106+
107+ def test_size_for_4096_byte_sectors(self):
108+ self._test_for_sector_size(4096)
109+
110+
111+class TestGetPartitionMbrLayout(TestCase):
112+
113+ def test_single_partition_using_boolean(self):
114+ self.assertEqual('0,',
115+ cc_disk_setup.get_partition_mbr_layout(1000, True))
116+
117+ def test_single_partition_using_list(self):
118+ disk_size = random.randint(1000000, 1000000000000)
119+ self.assertEqual(
120+ ',,83',
121+ cc_disk_setup.get_partition_mbr_layout(disk_size, [100]))
122+
123+ def test_half_and_half(self):
124+ disk_size = random.randint(1000000, 1000000000000)
125+ expected_partition_size = int(float(disk_size) / 2)
126+ self.assertEqual(
127+ ',{0},83\n,,83'.format(expected_partition_size),
128+ cc_disk_setup.get_partition_mbr_layout(disk_size, [50, 50]))
129+
130+ def test_thirds_with_different_partition_type(self):
131+ disk_size = random.randint(1000000, 1000000000000)
132+ expected_partition_size = int(float(disk_size) * 0.33)
133+ self.assertEqual(
134+ ',{0},83\n,,82'.format(expected_partition_size),
135+ cc_disk_setup.get_partition_mbr_layout(disk_size, [33, [66, 82]]))