Skip to content

Commit bdbbe5f

Browse files
committed
Merge remote-tracking branch 'origin/pr/475'
* origin/pr/475: storage: volume.resize(): size is an int tools/qvm-volume: resize_volumes() -> resize_volume() storage: centralize shrinking check from qvm-volume to module tools/qvm-volume: use 'resize' in code instead of old 'extend' storage: remove outdated comment about shrinking tests/storage: remove phantom admin.pool.volume.* tests
2 parents 9f939f2 + 49d56e6 commit bdbbe5f

4 files changed

Lines changed: 29 additions & 99 deletions

File tree

qubesadmin/storage.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,13 +264,24 @@ def is_outdated(self) -> bool:
264264
assert self._info is not None
265265
return self._info.get('is_outdated', False) == 'True'
266266

267-
def resize(self, size: object) -> None:
267+
def resize(self, size: int, *, allow_shrink: bool=False) -> None:
268268
"""Resize volume.
269269
270-
Currently only extending is supported.
271-
272270
:param int size: new size in bytes.
273271
"""
272+
273+
if not allow_shrink:
274+
current_size = self.size
275+
if size < current_size:
276+
vol_str = self.vm + ":" + self.name
277+
raise qubesadmin.exc.StoragePoolException(
278+
f"Refusing to shrink volume {vol_str}"
279+
f" from {current_size} to {size} bytes.\n"
280+
f"If you really know what you are doing:"
281+
f" Manually shrink the filesystem on the volume first,"
282+
f" and repartition the volume if it is partitioned."
283+
f" Do this in a VM, not in dom0."
284+
f" Then use 'qvm-volume resize --force {vol_str} {size}'")
274285
self._qubesd_call('Resize', str(size).encode('ascii'))
275286

276287
@property

qubesadmin/tests/storage.py

Lines changed: 2 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ def setUp(self):
3131
super().setUp()
3232
self.vol = qubesadmin.storage.Volume(self.app, vm='test-vm',
3333
vm_name='volname')
34-
self.pool_vol = qubesadmin.storage.Volume(self.app, pool='test-pool',
35-
vid='some-id')
3634

3735
def expect_info(self):
3836
self.app.expected_calls[
@@ -136,6 +134,7 @@ def test_022_revisions_empty(self):
136134
self.assertAllCalled()
137135

138136
def test_030_resize(self):
137+
self.expect_info()
139138
self.app.expected_calls[
140139
('test-vm', 'admin.vm.volume.Resize', 'volname', b'2048')] = \
141140
b'0\x00'
@@ -175,7 +174,7 @@ def test_050_clone(self):
175174
self.assertAllCalled()
176175

177176

178-
class TestPoolVolume(TestVMVolume):
177+
class TestPoolVolume(qubesadmin.tests.QubesTestCase):
179178
def setUp(self):
180179
super().setUp()
181180
self.vol = qubesadmin.storage.Volume(self.app, pool='test-pool',
@@ -190,29 +189,6 @@ def test_000_qubesd_call(self):
190189
b'method_result')
191190
self.assertAllCalled()
192191

193-
def expect_info(self):
194-
self.app.expected_calls[
195-
('dom0', 'admin.pool.volume.Info', 'test-pool', b'some-id')] = \
196-
b'0\x00' \
197-
b'pool=test-pool\n' \
198-
b'vid=some-id\n' \
199-
b'size=1024\n' \
200-
b'usage=512\n' \
201-
b'rw=True\n' \
202-
b'snap_on_start=True\n' \
203-
b'save_on_stop=True\n' \
204-
b'source=\n' \
205-
b'revisions_to_keep=3\n'
206-
207-
def test_001_fetch_info(self):
208-
self.app.expected_calls[
209-
('dom0', 'admin.pool.volume.Info', 'test-pool',
210-
b'some-id')] = \
211-
b'0\x00prop1=val1\nprop2=val2\n'
212-
self.vol._fetch_info()
213-
self.assertEqual(self.vol._info, {'prop1': 'val1', 'prop2': 'val2'})
214-
self.assertAllCalled()
215-
216192
def test_010_pool(self):
217193
# this should _not_ produce any api call, as pool is already known
218194
self.assertEqual(self.vol.pool, 'test-pool')
@@ -223,57 +199,6 @@ def test_011_vid(self):
223199
self.assertEqual(self.vol.vid, 'some-id')
224200
self.assertAllCalled()
225201

226-
def test_021_revisions(self):
227-
self.app.expected_calls[
228-
('dom0', 'admin.pool.volume.ListSnapshots',
229-
'test-pool', b'some-id')] = \
230-
b'0\x00' \
231-
b'snapid1\n' \
232-
b'snapid2\n' \
233-
b'snapid3\n'
234-
self.assertEqual(self.vol.revisions,
235-
['snapid1', 'snapid2', 'snapid3'])
236-
self.assertAllCalled()
237-
238-
def test_022_revisions_empty(self):
239-
self.app.expected_calls[
240-
('dom0', 'admin.pool.volume.ListSnapshots',
241-
'test-pool', b'some-id')] = b'0\x00'
242-
self.assertEqual(self.vol.revisions, [])
243-
self.assertAllCalled()
244-
245-
def test_030_resize(self):
246-
self.app.expected_calls[
247-
('dom0', 'admin.pool.volume.Resize',
248-
'test-pool', b'some-id 2048')] = b'0\x00'
249-
self.vol.resize(2048)
250-
self.assertAllCalled()
251-
252-
def test_031_revert(self):
253-
self.app.expected_calls[
254-
('dom0', 'admin.pool.volume.Revert', 'test-pool',
255-
b'some-id snapid1')] = b'0\x00'
256-
self.vol.revert('snapid1')
257-
self.assertAllCalled()
258-
259-
def test_040_import_data(self):
260-
self.skipTest('admin.pool.volume.Import not supported')
261-
262-
def test_050_clone(self):
263-
self.app.expected_calls[
264-
('dom0', 'admin.pool.volume.CloneFrom', 'test-pool',
265-
b'volid')] = b'0\x00abcdef'
266-
self.app.expected_calls[
267-
('dom0', 'admin.pool.volume.CloneTo', 'test-pool',
268-
b'some-id abcdef')] = b'0\x00'
269-
source_vol = qubesadmin.storage.Volume(self.app, pool='test-pool',
270-
vid='volid')
271-
self.vol.clone(source_vol)
272-
self.assertAllCalled()
273-
274-
def test_050_clone_wrong_volume(self):
275-
self.skipTest('admin.pool.volume.Clone not supported')
276-
277202

278203
class TestPool(qubesadmin.tests.QubesTestCase):
279204
def test_000_list(self):

qubesadmin/tests/tools/qvm_volume.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,8 @@ def test_012_extend_deny_shrink(self):
232232
qubesadmin.tools.qvm_volume.main(
233233
['resize', 'testvm:private', '1GiB'],
234234
app=self.app))
235-
self.assertIn('shrinking of private is disabled', stderr.getvalue())
235+
self.assertIn('Refusing to shrink volume testvm:private',
236+
stderr.getvalue())
236237
self.assertAllCalled()
237238

238239
def test_013_resize_force_shrink(self):

qubesadmin/tools/qvm_volume.py

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -259,20 +259,13 @@ def revert_volume(args):
259259
volume.revert(revision)
260260

261261

262-
def extend_volumes(args):
263-
""" Called by the parser to execute the :program:`qvm-volume extend`
262+
def resize_volume(args):
263+
""" Called by the parser to execute the :program:`qvm-volume resize`
264264
subcommand
265265
"""
266266
volume = args.volume
267267
size = qubesadmin.utils.parse_size(args.size)
268-
if not args.force and size < volume.size:
269-
raise qubesadmin.exc.StoragePoolException(
270-
'For your own safety, shrinking of %s is'
271-
' disabled (%d < %d). If you really know what you'
272-
' are doing, resize filesystem manually first, then use `-f` '
273-
'option.' %
274-
(volume.name, size, volume.size))
275-
volume.resize(size)
268+
volume.resize(size, allow_shrink=args.force)
276269

277270

278271
def init_list_parser(sub_parsers):
@@ -308,18 +301,18 @@ def init_revert_parser(sub_parsers):
308301
revert_parser.set_defaults(func=revert_volume)
309302

310303

311-
def init_extend_parser(sub_parsers):
312-
""" Add 'extend' action related options """
313-
extend_parser = sub_parsers.add_parser(
304+
def init_resize_parser(sub_parsers):
305+
""" Add 'resize' action related options """
306+
resize_parser = sub_parsers.add_parser(
314307
"resize", aliases=('extend', ), help="resize volume for domain")
315-
extend_parser.add_argument(metavar='VM:VOLUME', dest='volume',
308+
resize_parser.add_argument(metavar='VM:VOLUME', dest='volume',
316309
action=qubesadmin.tools.VMVolumeAction)
317-
extend_parser.add_argument('size', help='New size in bytes')
318-
extend_parser.add_argument(
310+
resize_parser.add_argument('size', help='New size in bytes')
311+
resize_parser.add_argument(
319312
'--force', '-f', action='store_true',
320313
help='Force operation, even if new size is smaller than the current '
321314
'one')
322-
extend_parser.set_defaults(func=extend_volumes)
315+
resize_parser.set_defaults(func=resize_volume)
323316

324317

325318
def init_info_parser(sub_parsers):
@@ -403,7 +396,7 @@ def get_parser():
403396
dest='command')
404397
init_info_parser(sub_parsers)
405398
init_config_parser(sub_parsers)
406-
init_extend_parser(sub_parsers)
399+
init_resize_parser(sub_parsers)
407400
init_list_parser(sub_parsers)
408401
init_revert_parser(sub_parsers)
409402
init_import_parser(sub_parsers)

0 commit comments

Comments
 (0)