Merge ~dbungert/curtin:ntfs into curtin:master

Proposed by Dan Bungert
Status: Merged
Approved by: Dan Bungert
Approved revision: 07442bc3a62fb78df096e5f717077270fde2e123
Merge reported by: Server Team CI bot
Merged at revision: not available
Proposed branch: ~dbungert/curtin:ntfs
Merge into: curtin:master
Diff against target: 158 lines (+60/-8)
3 files modified
curtin/commands/block_meta_v2.py (+5/-0)
doc/topics/storage.rst (+1/-1)
tests/integration/test_block_meta.py (+54/-7)
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve
Olivier Gayot Approve
Michael Hudson-Doyle Approve
Review via email: mp+420513@code.launchpad.net

Commit message

block/v2: resize of ntfs

To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :

Nice and easy.

review: Approve
Revision history for this message
Olivier Gayot (ogayot) :
review: Approve
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/curtin/commands/block_meta_v2.py b/curtin/commands/block_meta_v2.py
2index c1e3630..2efff25 100644
3--- a/curtin/commands/block_meta_v2.py
4+++ b/curtin/commands/block_meta_v2.py
5@@ -60,6 +60,10 @@ def resize_ext(path, size):
6 util.subp(['resize2fs', path, f'{size_k}k'])
7
8
9+def resize_ntfs(path, size):
10+ util.subp(['ntfsresize', '-s', str(size), path])
11+
12+
13 def perform_resize(kname, size, direction):
14 path = block.kname_to_path(kname)
15 fstype = _get_volume_fstype(path)
16@@ -73,6 +77,7 @@ resizers = {
17 'ext2': resize_ext,
18 'ext3': resize_ext,
19 'ext4': resize_ext,
20+ 'ntfs': resize_ntfs,
21 }
22
23
24diff --git a/doc/topics/storage.rst b/doc/topics/storage.rst
25index e6dd13a..aa5ad13 100644
26--- a/doc/topics/storage.rst
27+++ b/doc/topics/storage.rst
28@@ -445,7 +445,7 @@ If the ``preserve`` flag is set to true, curtin will adjust the size of the
29 partition to the new size. When adjusting smaller, the size of the contents
30 must permit that. When adjusting larger, there must already be a gap beyond
31 the partition in question.
32-Resize is supported on filesystems of types ext2, ext3, ext4.
33+Resize is supported on filesystems of types ext2, ext3, ext4, ntfs.
34
35 **name**: *<name>*
36
37diff --git a/tests/integration/test_block_meta.py b/tests/integration/test_block_meta.py
38index be69bc0..76a974b 100644
39--- a/tests/integration/test_block_meta.py
40+++ b/tests/integration/test_block_meta.py
41@@ -6,9 +6,11 @@ import json
42 import sys
43 import yaml
44 import os
45+import re
46
47 from curtin import block, udev, util
48
49+from curtin.commands.block_meta import _get_volume_fstype
50 from curtin.commands.block_meta_v2 import ONE_MIB_BYTES
51
52 from tests.unittests.helpers import CiTestCase
53@@ -35,9 +37,7 @@ def loop_dev(image, sector_size=512):
54 PartData = namedtuple("PartData", ('number', 'offset', 'size'))
55
56
57-def _get_filesystem_size(dev, part_action, fstype='ext4'):
58- if fstype not in ('ext2', 'ext3', 'ext4'):
59- raise Exception(f'_get_filesystem_size: no support for {fstype}')
60+def _get_ext_size(dev, part_action):
61 num = part_action['number']
62 cmd = ['dumpe2fs', '-h', f'{dev}p{num}']
63 out = util.subp(cmd, capture=True)[0]
64@@ -49,6 +49,37 @@ def _get_filesystem_size(dev, part_action, fstype='ext4'):
65 return int(block_count) * int(block_size)
66
67
68+def _get_ntfs_size(dev, part_action):
69+ num = part_action['number']
70+ cmd = ['ntfsresize',
71+ '--no-action',
72+ '--force', # needed post-resize, which otherwise demands a CHKDSK
73+ '--info', f'{dev}p{num}']
74+ out = util.subp(cmd, capture=True)[0]
75+ # Sample input:
76+ # Current volume size: 41939456 bytes (42 MB)
77+ volsize_matcher = re.compile(r'^Current volume size: ([0-9]+) bytes')
78+ for line in out.splitlines():
79+ m = volsize_matcher.match(line)
80+ if m:
81+ return int(m.group(1))
82+ raise Exception('ntfs volume size not found')
83+
84+
85+_get_fs_sizers = {
86+ 'ext2': _get_ext_size,
87+ 'ext3': _get_ext_size,
88+ 'ext4': _get_ext_size,
89+ 'ntfs': _get_ntfs_size,
90+}
91+
92+
93+def _get_filesystem_size(dev, part_action, fstype='ext4'):
94+ if fstype not in _get_fs_sizers.keys():
95+ raise Exception(f'_get_filesystem_size: no support for {fstype}')
96+ return _get_fs_sizers[fstype](dev, part_action)
97+
98+
99 def _get_extended_partition_size(dev, num):
100 # sysfs reports extended partitions as having 1K size
101 # sfdisk seems to have a better idea
102@@ -139,6 +170,17 @@ class TestBlockMeta(IntegrationTestCase):
103 with self.open_file_on_part(dev, part_action, 'r') as fp:
104 self.assertEqual(self.data, fp.read())
105
106+ def check_fssize(self, dev, part_action, fstype, expected):
107+ tolerance = 0
108+ if fstype == 'ntfs':
109+ # Per ntfsresize manpage, the actual fs size is at least one sector
110+ # less than requested.
111+ # In these tests it has been consistently 7 sectors fewer.
112+ tolerance = 512 * 10
113+ actual_fssize = _get_filesystem_size(dev, part_action, fstype)
114+ diff = expected - actual_fssize
115+ self.assertTrue(0 <= diff <= tolerance, f'difference of {diff}')
116+
117 def run_bm(self, config, *args, **kwargs):
118 config_path = self.tmp_path('config.yaml')
119 with open(config_path, 'w') as fp:
120@@ -481,13 +523,13 @@ class TestBlockMeta(IntegrationTestCase):
121 fstype=fstype)
122 self.run_bm(config.render())
123 with loop_dev(img) as dev:
124+ self.assertEqual(fstype, _get_volume_fstype(f'{dev}p1'))
125 self.create_data(dev, p1)
126 self.assertEqual(
127 summarize_partitions(dev), [
128 PartData(number=1, offset=1 << 20, size=start),
129 ])
130- fs_size = _get_filesystem_size(dev, p1, fstype)
131- self.assertEqual(start, fs_size)
132+ self.check_fssize(dev, p1, fstype, start)
133
134 config.set_preserve()
135 p1['resize'] = True
136@@ -499,8 +541,7 @@ class TestBlockMeta(IntegrationTestCase):
137 summarize_partitions(dev), [
138 PartData(number=1, offset=1 << 20, size=end),
139 ])
140- fs_size = _get_filesystem_size(dev, p1, fstype)
141- self.assertEqual(end, fs_size)
142+ self.check_fssize(dev, p1, fstype, end)
143
144 def test_resize_up_ext2(self):
145 self._do_test_resize(40, 80, 'ext2')
146@@ -520,6 +561,12 @@ class TestBlockMeta(IntegrationTestCase):
147 def test_resize_down_ext4(self):
148 self._do_test_resize(80, 40, 'ext4')
149
150+ def test_resize_up_ntfs(self):
151+ self._do_test_resize(40, 80, 'ntfs')
152+
153+ def test_resize_down_ntfs(self):
154+ self._do_test_resize(80, 40, 'ntfs')
155+
156 def test_resize_logical(self):
157 img = self.tmp_path('image.img')
158 config = StorageConfigBuilder(version=2)

Subscribers

People subscribed via source and target branches