Skip to content

Commit

Permalink
Enable caching in qvm-ls and qvm-prefs
Browse files Browse the repository at this point in the history
Both tools issue a large number of Admin API calls and greatly benefit
from a cache filled with a single per-vm Admin API call
(admin.vm.property.GetAll). In case of qvm-ls, this also saves multiple
admin.vm.CurrentState calls (power state is given in the admin.vm.List
response too).

QubesOS/qubes-issues#3293
  • Loading branch information
marmarek committed Apr 20, 2020
1 parent c946b80 commit a56aca7
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 53 deletions.
8 changes: 3 additions & 5 deletions qubesadmin/tests/tools/qubes_prefs.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,9 @@ def test_000_list(self):
('dom0', 'admin.property.List', None, None)] = \
b'0\x00prop1\nprop2\n'
self.app.expected_calls[
('dom0', 'admin.property.Get', 'prop1', None)] = \
b'0\x00default=True type=str value1'
self.app.expected_calls[
('dom0', 'admin.property.Get', 'prop2', None)] = \
b'0\x00default=False type=str value2'
('dom0', 'admin.property.GetAll', None, None)] = \
b'0\x00prop1 default=True type=str value1\n' \
b'prop2 default=False type=str value2\n'
with qubesadmin.tests.tools.StdoutBuffer() as stdout:
self.assertEqual(0, qubesadmin.tools.qubes_prefs.main([], app=self.app))
self.assertEqual(stdout.getvalue(),
Expand Down
78 changes: 36 additions & 42 deletions qubesadmin/tests/tools/qvm_ls.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,42 +278,34 @@ def test_100_list_with_status(self):
b'0\x00vm1 class=AppVM state=Running\n' \
b'template1 class=TemplateVM state=Halted\n' \
b'sys-net class=AppVM state=Running\n'
self.app.expected_calls[
('vm1', 'admin.vm.CurrentState', None, None)] = \
b'0\x00power_state=Running'
self.app.expected_calls[
('sys-net', 'admin.vm.CurrentState', None, None)] = \
b'0\x00power_state=Running'
self.app.expected_calls[
('template1', 'admin.vm.CurrentState', None, None)] = \
b'0\x00power_state=Halted'
props = {
'label': b'type=label green',
'template': b'type=vm template1',
'netvm': b'type=vm sys-net',
'label': 'type=label green',
'template': 'type=vm template1',
'netvm': 'type=vm sys-net',
# 'virt_mode': b'type=str pv',
}
for key, value in props.items():
self.app.expected_calls[
('vm1', 'admin.vm.property.Get', key, None)] = \
b'0\x00default=True ' + value

# setup template1
props['label'] = b'type=label black'
for key, value in props.items():
self.app.expected_calls[
('template1', 'admin.vm.property.Get', key, None)] = \
b'0\x00default=True ' + value
self.app.expected_calls[
('template1', 'admin.vm.property.Get', 'template', None)] = \
b'' # request refused - no such property
('vm1', 'admin.vm.property.GetAll', None, None)] = \
b'0\x00' + ''.join(
'{} default=True {}\n'.format(key, value)
for key, value in props.items()).encode()

# setup sys-net
props['label'] = b'type=label red'
for key, value in props.items():
self.app.expected_calls[
('sys-net', 'admin.vm.property.Get', key, None)] = \
b'0\x00default=True ' + value
props['label'] = 'type=label red'
self.app.expected_calls[
('sys-net', 'admin.vm.property.GetAll', None, None)] = \
b'0\x00' + ''.join(
'{} default=True {}\n'.format(key, value)
for key, value in props.items()).encode()

# setup template1
props['label'] = 'type=label black'
del props['template']
self.app.expected_calls[
('template1', 'admin.vm.property.GetAll', None, None)] = \
b'0\x00' + ''.join(
'{} default=True {}\n'.format(key, value)
for key, value in props.items()).encode()

with qubesadmin.tests.tools.StdoutBuffer() as stdout:
qubesadmin.tools.qvm_ls.main([], app=self.app)
Expand All @@ -337,22 +329,24 @@ def test_101_list_selected(self):
('sys-net', 'admin.vm.CurrentState', None, None)] = \
b'0\x00power_state=Running'
props = {
'label': b'type=label green',
'template': b'type=vm template1',
'netvm': b'type=vm sys-net',
'label': 'type=label green',
'template': 'type=vm template1',
'netvm': 'type=vm sys-net',
# 'virt_mode': b'type=str pv',
}
for key, value in props.items():
self.app.expected_calls[
('vm1', 'admin.vm.property.Get', key, None)] = \
b'0\x00default=True ' + value
self.app.expected_calls[
('vm1', 'admin.vm.property.GetAll', None, None)] = \
b'0\x00' + ''.join(
'{} default=True {}\n'.format(key, value)
for key, value in props.items()).encode()

# setup sys-net
props['label'] = b'type=label red'
for key, value in props.items():
self.app.expected_calls[
('sys-net', 'admin.vm.property.Get', key, None)] = \
b'0\x00default=True ' + value
props['label'] = 'type=label red'
self.app.expected_calls[
('sys-net', 'admin.vm.property.GetAll', None, None)] = \
b'0\x00' + ''.join(
'{} default=True {}\n'.format(key, value)
for key, value in props.items()).encode()

with qubesadmin.tests.tools.StdoutBuffer() as stdout:
qubesadmin.tools.qvm_ls.main(['vm1', 'sys-net'], app=self.app)
Expand Down
10 changes: 4 additions & 6 deletions qubesadmin/tests/tools/qvm_prefs.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,9 @@ def test_000_list(self):
('dom0', 'admin.vm.property.List', None, None)] = \
b'0\x00prop1\nprop2\n'
self.app.expected_calls[
('dom0', 'admin.vm.property.Get', 'prop1', None)] = \
b'0\x00default=True type=str value1'
self.app.expected_calls[
('dom0', 'admin.vm.property.Get', 'prop2', None)] = \
b'0\x00default=False type=str value2'
('dom0', 'admin.vm.property.GetAll', None, None)] = \
b'0\x00prop1 default=True type=str value1\n' \
b'prop2 default=False type=str value2\n'
with qubesadmin.tests.tools.StdoutBuffer() as stdout:
self.assertEqual(0, qubesadmin.tools.qvm_prefs.main([
'dom0'], app=self.app))
Expand All @@ -46,7 +44,7 @@ def test_000_list(self):
'prop2 - value2\n')
with qubesadmin.tests.tools.StdoutBuffer() as stdout:
self.assertEqual(0, qubesadmin.tools.qvm_prefs.main([
'dom0','--hide-default'], app=self.app))
'dom0', '--hide-default'], app=self.app))
self.assertEqual(stdout.getvalue(),
'prop2 - value2\n')
self.assertAllCalled()
Expand Down
4 changes: 4 additions & 0 deletions qubesadmin/tools/qvm_ls.py
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,10 @@ def main(args=None, app=None):
parser.print_error(str(e))
return 1

# fetch all the properties with one Admin API call, instead of issuing
# one call per property
args.app.cache_enabled = True

if args.raw_list:
args.raw_data = True
args.fields = 'name'
Expand Down
3 changes: 3 additions & 0 deletions qubesadmin/tools/qvm_prefs.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ def process_actions(parser, args, target):
return 0

if args.property is None:
# fetch all the properties with one Admin API call, instead of issuing
# one call per property
args.app.cache_enabled = True
properties = target.property_list()
width = max(len(prop) for prop in properties)

Expand Down

0 comments on commit a56aca7

Please sign in to comment.