Skip to content

Commit

Permalink
tools/qvm-volume: add showing and setting 'ephemeral' property
Browse files Browse the repository at this point in the history
  • Loading branch information
marmarek committed Oct 9, 2021
1 parent 4b9fe24 commit 39cff4b
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 2 deletions.
6 changes: 6 additions & 0 deletions doc/manpages/qvm-volume.rst
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ Set property of given volume. Properties currently possible to change:
should be keep. At each qube shutdown its previous state is saved in new
revision, and the oldest revisions are remove so that only
`revisions_to_keep` are left. Set to `0` to not leave any previous versions.
- `ephemeral` - should the volume be encrypted with en ephemeral key? This can
be enabled only on a volume with `save_on_stop=False` and `snap_on_start=True`
- which is only `volatile` volume. When set, it provides a bit more
anti-forensics protection against attacker with access to the LUKS disk key.
In majority of use cases, it only degrades performance due to additional
encryption level.

aliases: c, set, s

Expand Down
65 changes: 65 additions & 0 deletions qubesadmin/tests/tools/qvm_volume.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,21 @@ def test_032_set_invalid(self):
app=self.app))
self.assertAllCalled()

def test_033_set_ephemeral(self):
self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \
b'0\x00testvm class=AppVM state=Running\n'
self.app.expected_calls[
('testvm', 'admin.vm.volume.List', None, None)] = \
b'0\x00root\nprivate\nvolatile\n'
self.app.expected_calls[
('testvm', 'admin.vm.volume.Set.ephemeral', 'volatile',
b'True')] = b'0\x00'
self.assertEqual(0,
qubesadmin.tools.qvm_volume.main(
['set', 'testvm:volatile', 'ephemeral', 'True'],
app=self.app))
self.assertAllCalled()

def test_040_info(self):
self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \
b'0\x00testvm class=AppVM state=Running\n'
Expand All @@ -377,6 +392,7 @@ def test_040_info(self):
b'save_on_stop=True\n' \
b'snap_on_start=False\n' \
b'revisions_to_keep=3\n' \
b'ephemeral=False\n' \
b'is_outdated=False\n'
self.app.expected_calls[
('testvm', 'admin.vm.volume.ListSnapshots', 'private', None)] = \
Expand All @@ -398,6 +414,7 @@ def test_040_info(self):
'size 2147483648\n'
'usage 10000000\n'
'revisions_to_keep 3\n'
'ephemeral False\n'
'is_outdated False\n'
'Available revisions (for revert):\n'
' 200101010000\n'
Expand All @@ -422,6 +439,7 @@ def test_041_info_no_revisions(self):
b'save_on_stop=False\n' \
b'snap_on_start=True\n' \
b'revisions_to_keep=0\n' \
b'ephemeral=True\n' \
b'is_outdated=False\n'
self.app.expected_calls[
('testvm', 'admin.vm.volume.ListSnapshots', 'root', None)] = \
Expand All @@ -440,6 +458,7 @@ def test_041_info_no_revisions(self):
'size 2147483648\n'
'usage 10000000\n'
'revisions_to_keep 0\n'
'ephemeral True\n'
'is_outdated False\n'
'Available revisions (for revert): none\n')
self.assertAllCalled()
Expand Down Expand Up @@ -490,6 +509,52 @@ def test_043_info_revisions_only(self):
'200301010000\n')
self.assertAllCalled()

def test_044_info_no_ephemeral(self):
self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \
b'0\x00testvm class=AppVM state=Running\n'
self.app.expected_calls[
('testvm', 'admin.vm.volume.List', None, None)] = \
b'0\x00root\nprivate\n'
self.app.expected_calls[
('testvm', 'admin.vm.volume.Info', 'private', None)] = \
b'0\x00pool=lvm\n' \
b'vid=qubes_dom0/vm-testvm-private\n' \
b'size=2147483648\n' \
b'usage=10000000\n' \
b'rw=True\n' \
b'source=\n' \
b'save_on_stop=True\n' \
b'snap_on_start=False\n' \
b'revisions_to_keep=3\n' \
b'is_outdated=False\n'
self.app.expected_calls[
('testvm', 'admin.vm.volume.ListSnapshots', 'private', None)] = \
b'0\x00200101010000\n200201010000\n200301010000\n'
with qubesadmin.tests.tools.StdoutBuffer() as stdout:
self.assertEqual(0,
qubesadmin.tools.qvm_volume.main(['info', 'testvm:private'],
app=self.app))
output = stdout.getvalue()
# travis...
output = output.replace('\nsource\n', '\nsource \n')
self.assertEqual(output,
'pool lvm\n'
'vid qubes_dom0/vm-testvm-private\n'
'rw True\n'
'source \n'
'save_on_stop True\n'
'snap_on_start False\n'
'size 2147483648\n'
'usage 10000000\n'
'revisions_to_keep 3\n'
'ephemeral False\n'
'is_outdated False\n'
'Available revisions (for revert):\n'
' 200101010000\n'
' 200201010000\n'
' 200301010000\n')
self.assertAllCalled()

def test_050_import_file(self):
self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \
b'0\x00testvm class=AppVM state=Running\n'
Expand Down
4 changes: 2 additions & 2 deletions qubesadmin/tools/qvm_volume.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def info_volume(args):
volume = args.volume
info_items = (
'pool', 'vid', 'rw', 'source', 'save_on_stop',
'snap_on_start', 'size', 'usage', 'revisions_to_keep')
'snap_on_start', 'size', 'usage', 'revisions_to_keep', 'ephemeral')
if args.property:
if args.property == 'revisions':
for rev in volume.revisions:
Expand Down Expand Up @@ -131,7 +131,7 @@ def info_volume(args):
def config_volume(args):
""" Change property of selected volume """
volume = args.volume
if not args.property in ('rw', 'revisions_to_keep'):
if args.property not in ('rw', 'revisions_to_keep', 'ephemeral'):
raise qubesadmin.exc.QubesNoSuchPropertyError(
'Invalid property: {}'.format(args.property))
setattr(volume, args.property, args.value)
Expand Down

0 comments on commit 39cff4b

Please sign in to comment.