Enable caching in qvm-ls and qvm-prefs
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
This commit is contained in:
		
							parent
							
								
									79c7392424
								
							
						
					
					
						commit
						c081ed8c82
					
				| @ -29,11 +29,9 @@ class TC_00_qubes_prefs(qubesadmin.tests.QubesTestCase): | |||||||
|             ('dom0', 'admin.property.List', None, None)] = \ |             ('dom0', 'admin.property.List', None, None)] = \ | ||||||
|             b'0\x00prop1\nprop2\n' |             b'0\x00prop1\nprop2\n' | ||||||
|         self.app.expected_calls[ |         self.app.expected_calls[ | ||||||
|             ('dom0', 'admin.property.Get', 'prop1', None)] = \ |             ('dom0', 'admin.property.GetAll', None, None)] = \ | ||||||
|             b'0\x00default=True type=str value1' |             b'0\x00prop1 default=True type=str value1\n' \ | ||||||
|         self.app.expected_calls[ |             b'prop2 default=False type=str value2\n' | ||||||
|             ('dom0', 'admin.property.Get', 'prop2', None)] = \ |  | ||||||
|             b'0\x00default=False type=str value2' |  | ||||||
|         with qubesadmin.tests.tools.StdoutBuffer() as stdout: |         with qubesadmin.tests.tools.StdoutBuffer() as stdout: | ||||||
|             self.assertEqual(0, qubesadmin.tools.qubes_prefs.main([], app=self.app)) |             self.assertEqual(0, qubesadmin.tools.qubes_prefs.main([], app=self.app)) | ||||||
|         self.assertEqual(stdout.getvalue(), |         self.assertEqual(stdout.getvalue(), | ||||||
|  | |||||||
| @ -278,42 +278,34 @@ class TC_90_List_with_qubesd_calls(qubesadmin.tests.QubesTestCase): | |||||||
|             b'0\x00vm1 class=AppVM state=Running\n' \ |             b'0\x00vm1 class=AppVM state=Running\n' \ | ||||||
|             b'template1 class=TemplateVM state=Halted\n' \ |             b'template1 class=TemplateVM state=Halted\n' \ | ||||||
|             b'sys-net class=AppVM state=Running\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 = { |         props = { | ||||||
|             'label': b'type=label green', |             'label': 'type=label green', | ||||||
|             'template': b'type=vm template1', |             'template': 'type=vm template1', | ||||||
|             'netvm': b'type=vm sys-net', |             'netvm': 'type=vm sys-net', | ||||||
| #           'virt_mode': b'type=str pv', | #           'virt_mode': b'type=str pv', | ||||||
|         } |         } | ||||||
|         for key, value in props.items(): |  | ||||||
|         self.app.expected_calls[ |         self.app.expected_calls[ | ||||||
|                 ('vm1', 'admin.vm.property.Get', key, None)] = \ |             ('vm1', 'admin.vm.property.GetAll', None, None)] = \ | ||||||
|                 b'0\x00default=True ' + value |             b'0\x00' + ''.join( | ||||||
| 
 |                 '{} default=True {}\n'.format(key, value) | ||||||
|         # setup template1 |                 for key, value in props.items()).encode() | ||||||
|         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 |  | ||||||
| 
 | 
 | ||||||
|         # setup sys-net |         # setup sys-net | ||||||
|         props['label'] = b'type=label red' |         props['label'] = 'type=label red' | ||||||
|         for key, value in props.items(): |  | ||||||
|         self.app.expected_calls[ |         self.app.expected_calls[ | ||||||
|                 ('sys-net', 'admin.vm.property.Get', key, None)] = \ |             ('sys-net', 'admin.vm.property.GetAll', None, None)] = \ | ||||||
|                 b'0\x00default=True ' + value |             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: |         with qubesadmin.tests.tools.StdoutBuffer() as stdout: | ||||||
|             qubesadmin.tools.qvm_ls.main([], app=self.app) |             qubesadmin.tools.qvm_ls.main([], app=self.app) | ||||||
| @ -337,22 +329,24 @@ class TC_90_List_with_qubesd_calls(qubesadmin.tests.QubesTestCase): | |||||||
|             ('sys-net', 'admin.vm.CurrentState', None, None)] = \ |             ('sys-net', 'admin.vm.CurrentState', None, None)] = \ | ||||||
|             b'0\x00power_state=Running' |             b'0\x00power_state=Running' | ||||||
|         props = { |         props = { | ||||||
|             'label': b'type=label green', |             'label': 'type=label green', | ||||||
|             'template': b'type=vm template1', |             'template': 'type=vm template1', | ||||||
|             'netvm': b'type=vm sys-net', |             'netvm': 'type=vm sys-net', | ||||||
| #           'virt_mode': b'type=str pv', | #           'virt_mode': b'type=str pv', | ||||||
|         } |         } | ||||||
|         for key, value in props.items(): |  | ||||||
|         self.app.expected_calls[ |         self.app.expected_calls[ | ||||||
|                 ('vm1', 'admin.vm.property.Get', key, None)] = \ |             ('vm1', 'admin.vm.property.GetAll', None, None)] = \ | ||||||
|                 b'0\x00default=True ' + value |             b'0\x00' + ''.join( | ||||||
|  |                 '{} default=True {}\n'.format(key, value) | ||||||
|  |                 for key, value in props.items()).encode() | ||||||
| 
 | 
 | ||||||
|         # setup sys-net |         # setup sys-net | ||||||
|         props['label'] = b'type=label red' |         props['label'] = 'type=label red' | ||||||
|         for key, value in props.items(): |  | ||||||
|         self.app.expected_calls[ |         self.app.expected_calls[ | ||||||
|                 ('sys-net', 'admin.vm.property.Get', key, None)] = \ |             ('sys-net', 'admin.vm.property.GetAll', None, None)] = \ | ||||||
|                 b'0\x00default=True ' + value |             b'0\x00' + ''.join( | ||||||
|  |                 '{} default=True {}\n'.format(key, value) | ||||||
|  |                 for key, value in props.items()).encode() | ||||||
| 
 | 
 | ||||||
|         with qubesadmin.tests.tools.StdoutBuffer() as stdout: |         with qubesadmin.tests.tools.StdoutBuffer() as stdout: | ||||||
|             qubesadmin.tools.qvm_ls.main(['vm1', 'sys-net'], app=self.app) |             qubesadmin.tools.qvm_ls.main(['vm1', 'sys-net'], app=self.app) | ||||||
|  | |||||||
| @ -33,11 +33,9 @@ class TC_00_qvm_prefs(qubesadmin.tests.QubesTestCase): | |||||||
|             ('dom0', 'admin.vm.property.List', None, None)] = \ |             ('dom0', 'admin.vm.property.List', None, None)] = \ | ||||||
|             b'0\x00prop1\nprop2\n' |             b'0\x00prop1\nprop2\n' | ||||||
|         self.app.expected_calls[ |         self.app.expected_calls[ | ||||||
|             ('dom0', 'admin.vm.property.Get', 'prop1', None)] = \ |             ('dom0', 'admin.vm.property.GetAll', None, None)] = \ | ||||||
|             b'0\x00default=True type=str value1' |             b'0\x00prop1 default=True type=str value1\n' \ | ||||||
|         self.app.expected_calls[ |             b'prop2 default=False type=str value2\n' | ||||||
|             ('dom0', 'admin.vm.property.Get', 'prop2', None)] = \ |  | ||||||
|             b'0\x00default=False type=str value2' |  | ||||||
|         with qubesadmin.tests.tools.StdoutBuffer() as stdout: |         with qubesadmin.tests.tools.StdoutBuffer() as stdout: | ||||||
|             self.assertEqual(0, qubesadmin.tools.qvm_prefs.main([ |             self.assertEqual(0, qubesadmin.tools.qvm_prefs.main([ | ||||||
|                 'dom0'], app=self.app)) |                 'dom0'], app=self.app)) | ||||||
|  | |||||||
| @ -664,6 +664,10 @@ def main(args=None, app=None): | |||||||
|         parser.print_error(str(e)) |         parser.print_error(str(e)) | ||||||
|         return 1 |         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: |     if args.raw_list: | ||||||
|         args.raw_data = True |         args.raw_data = True | ||||||
|         args.fields = 'name' |         args.fields = 'name' | ||||||
|  | |||||||
| @ -93,6 +93,9 @@ def process_actions(parser, args, target): | |||||||
|         return 0 |         return 0 | ||||||
| 
 | 
 | ||||||
|     if args.property is None: |     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() |         properties = target.property_list() | ||||||
|         width = max(len(prop) for prop in properties) |         width = max(len(prop) for prop in properties) | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Marek Marczykowski-Górecki
						Marek Marczykowski-Górecki