From e6427f97dc02c87535ef9647e3d728106f6c3bc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marta=20Marczykowska-G=C3=B3recka?= Date: Wed, 18 Jul 2018 23:50:54 +0200 Subject: [PATCH 1/3] Helper function that lists where a given VM is used A helper function to list vm's usage added to the utils. --- qubesadmin/utils.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/qubesadmin/utils.py b/qubesadmin/utils.py index edaac11..4e0a4e9 100644 --- a/qubesadmin/utils.py +++ b/qubesadmin/utils.py @@ -115,3 +115,29 @@ def updates_vms_status(qvm_collection): # "mixed" return None return status + +# Helper function that returns a list of all the places a given VM is used in. +# Output is a list of tuples (property_holder, property_name), with None as +# property_holder for global properties + + +def vm_usage(app, reference_vm): + + result = [] + + global_properties = ['default_dispvm', 'default_netvm', + 'default_template', 'clockvm', 'updatevm'] + + for prop in global_properties: + if reference_vm == getattr(app, prop, None): + result.append([None, prop]) + + vm_properties = ['template', 'netvm', 'default_dispvm'] + + for vm in app.domains: + for prop in vm_properties: + if reference_vm == getattr(vm, prop, None) and \ + not vm.property_is_default(prop): + result.append([vm, prop]) + + return result From f9564ffa2bb58a901fcb93456f30cf835c3887f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marta=20Marczykowska-G=C3=B3recka?= Date: Thu, 19 Jul 2018 19:52:22 +0200 Subject: [PATCH 2/3] Added tests and minor correction to vm_usage helper function Now the function returns a list of tuples, not a list of lists. --- qubesadmin/tests/utils.py | 105 ++++++++++++++++++++++++++++++++++++++ qubesadmin/utils.py | 4 +- 2 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 qubesadmin/tests/utils.py diff --git a/qubesadmin/tests/utils.py b/qubesadmin/tests/utils.py new file mode 100644 index 0000000..9e8ea54 --- /dev/null +++ b/qubesadmin/tests/utils.py @@ -0,0 +1,105 @@ +# -*- encoding: utf8 -*- +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2017 Marek Marczykowski-Górecki +# +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with this program; if not, see . +import unittest +import qubesadmin.tests +import qubesadmin.utils + + +class TestVMUsage(qubesadmin.tests.QubesTestCase): + def setUp(self): + super(TestVMUsage, self).setUp() + + self.app.expected_calls[ + ('dom0', 'admin.vm.List', None, None)] = \ + b'0\x00vm1 class=AppVM state=Running\n' \ + b'template1 class=TemplateVM state=Halted\n' \ + b'template2 class=TemplateVM state=Running\n' \ + b'vm2 class=AppVM state=Running\n' \ + b'sys-net class=AppVM state=Running\n' \ + b'sys-firewall class=AppVM state=Running\n' + + self.global_properties = ['default_dispvm', 'default_netvm', + 'default_template', 'clockvm', 'updatevm'] + + for prop in self.global_properties: + self.app.expected_calls[ + ('dom0', 'admin.property.Get', prop, None)] = \ + b'0\x00default=True type=vm vm2' + + self.vms = ['vm1', 'vm2', 'sys-net', 'sys-firewall', + 'template1', 'template2'] + self.vm_properties = ['template', 'netvm', 'default_dispvm'] + + for vm in self.vms: + for prop in self.vm_properties: + if not prop.startswith('template') or \ + not vm.startswith('template'): + self.app.expected_calls[ + (vm, 'admin.vm.property.Get', prop, None)] = \ + b'0\x00default=False type=vm template1' + else: + self.app.expected_calls[ + (vm, 'admin.vm.property.Get', prop, None)] = \ + b'2\0QubesNoSuchPropertyError\0\0invalid property\0' + + def test_00_only_global(self): + result = qubesadmin.utils.vm_usage(self.app, self.app.domains['vm2']) + + self.assertListEqual(result, + [(None, prop) for prop in self.global_properties], + "Incorrect global properties listed.") + + def test_01_only_vm(self): + result = qubesadmin.utils.vm_usage( + self.app, self.app.domains['template1']) + + self.assertCountEqual( + result, + [(vm, prop) for vm in self.vms for prop in self.vm_properties + if (not vm.startswith('template') + or not prop.startswith('template'))], + "Incorrect VM properties listed.") + + def test_02_empty(self): + result = qubesadmin.utils.vm_usage(self.app, self.app.domains['vm1']) + + self.assertListEqual(result, [], "Incorrect use found.") + + def test_03_access_error(self): + self.app.expected_calls[ + ('dom0', 'admin.property.Get', 'default_dispvm', None)] = b'' + + result = qubesadmin.utils.vm_usage(self.app, self.app.domains['vm1']) + + self.assertListEqual(result, [], "Incorrect use found.") + + def test_04_defaults(self): + self.app.expected_calls[ + ('vm2', 'admin.vm.property.Get', 'netvm', None)] = \ + b'0\x00default=True type=vm sys-net' + + self.app.expected_calls[ + ('vm1', 'admin.vm.property.Get', 'netvm', None)] = \ + b'0\x00default=False type=vm sys-net' + + result = qubesadmin.utils.vm_usage(self.app, + self.app.domains['sys-net']) + + self.assertListEqual(result, [(self.app.domains['vm1'], 'netvm')]) diff --git a/qubesadmin/utils.py b/qubesadmin/utils.py index 4e0a4e9..9c15a4f 100644 --- a/qubesadmin/utils.py +++ b/qubesadmin/utils.py @@ -130,7 +130,7 @@ def vm_usage(app, reference_vm): for prop in global_properties: if reference_vm == getattr(app, prop, None): - result.append([None, prop]) + result.append((None, prop)) vm_properties = ['template', 'netvm', 'default_dispvm'] @@ -138,6 +138,6 @@ def vm_usage(app, reference_vm): for prop in vm_properties: if reference_vm == getattr(vm, prop, None) and \ not vm.property_is_default(prop): - result.append([vm, prop]) + result.append((vm, prop)) return result From ca848ca7bd07dfb6c2135c4767b0e6536cd9a430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marta=20Marczykowska-G=C3=B3recka?= Date: Thu, 19 Jul 2018 20:06:00 +0200 Subject: [PATCH 3/3] Name change of vm dependencies helper function As per @marmarek's request. Also docstrings. --- qubesadmin/tests/utils.py | 22 +++++++++++----------- qubesadmin/utils.py | 10 +++++----- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/qubesadmin/tests/utils.py b/qubesadmin/tests/utils.py index 9e8ea54..04833e2 100644 --- a/qubesadmin/tests/utils.py +++ b/qubesadmin/tests/utils.py @@ -60,25 +60,25 @@ class TestVMUsage(qubesadmin.tests.QubesTestCase): b'2\0QubesNoSuchPropertyError\0\0invalid property\0' def test_00_only_global(self): - result = qubesadmin.utils.vm_usage(self.app, self.app.domains['vm2']) + result = qubesadmin.utils.vm_dependencies(self.app, self.app.domains['vm2']) self.assertListEqual(result, [(None, prop) for prop in self.global_properties], "Incorrect global properties listed.") def test_01_only_vm(self): - result = qubesadmin.utils.vm_usage( + result = qubesadmin.utils.vm_dependencies( self.app, self.app.domains['template1']) - self.assertCountEqual( - result, - [(vm, prop) for vm in self.vms for prop in self.vm_properties - if (not vm.startswith('template') - or not prop.startswith('template'))], + self.assertSetEqual( + set(result), + set([(vm, prop) for vm in self.vms for prop in self.vm_properties + if (not vm.startswith('template') + or not prop.startswith('template'))]), "Incorrect VM properties listed.") def test_02_empty(self): - result = qubesadmin.utils.vm_usage(self.app, self.app.domains['vm1']) + result = qubesadmin.utils.vm_dependencies(self.app, self.app.domains['vm1']) self.assertListEqual(result, [], "Incorrect use found.") @@ -86,7 +86,7 @@ class TestVMUsage(qubesadmin.tests.QubesTestCase): self.app.expected_calls[ ('dom0', 'admin.property.Get', 'default_dispvm', None)] = b'' - result = qubesadmin.utils.vm_usage(self.app, self.app.domains['vm1']) + result = qubesadmin.utils.vm_dependencies(self.app, self.app.domains['vm1']) self.assertListEqual(result, [], "Incorrect use found.") @@ -99,7 +99,7 @@ class TestVMUsage(qubesadmin.tests.QubesTestCase): ('vm1', 'admin.vm.property.Get', 'netvm', None)] = \ b'0\x00default=False type=vm sys-net' - result = qubesadmin.utils.vm_usage(self.app, - self.app.domains['sys-net']) + result = qubesadmin.utils.vm_dependencies(self.app, + self.app.domains['sys-net']) self.assertListEqual(result, [(self.app.domains['vm1'], 'netvm')]) diff --git a/qubesadmin/utils.py b/qubesadmin/utils.py index 9c15a4f..ccb3134 100644 --- a/qubesadmin/utils.py +++ b/qubesadmin/utils.py @@ -116,12 +116,12 @@ def updates_vms_status(qvm_collection): return None return status -# Helper function that returns a list of all the places a given VM is used in. -# Output is a list of tuples (property_holder, property_name), with None as -# property_holder for global properties - -def vm_usage(app, reference_vm): +def vm_dependencies(app, reference_vm): + '''Helper function that returns a list of all the places a given VM is used + in. Output is a list of tuples (property_holder, property_name), with None + as property_holder for global properties + ''' result = []