diff --git a/qubesadmin/app.py b/qubesadmin/app.py index d6c71bc..ca764fa 100644 --- a/qubesadmin/app.py +++ b/qubesadmin/app.py @@ -385,6 +385,26 @@ class QubesBase(qubesadmin.base.PropertyHolder): if not ignore_errors: raise + try: + # FIXME: convert to qrexec calls to dom0/GUI VM + appmenus_cmd = \ + ['qvm-appmenus', '--init', '--update', + '--source', src_vm.name, dst_vm.name] + subprocess.check_output(appmenus_cmd, stderr=subprocess.STDOUT) + except OSError: + # this file needs to be python 2.7 compatible, + # so no FileNotFoundError + self.log.error('Failed to clone appmenus, qvm-appmenus missing') + if not ignore_errors: + raise qubesadmin.exc.QubesException( + 'Failed to clone appmenus') + except subprocess.CalledProcessError as e: + self.log.error('Failed to clone appmenus: %s', + e.output.decode()) + if not ignore_errors: + raise qubesadmin.exc.QubesException( + 'Failed to clone appmenus') + except qubesadmin.exc.QubesException: if not ignore_errors: del self.domains[dst_vm.name] diff --git a/qubesadmin/tests/app.py b/qubesadmin/tests/app.py index 5294867..f6375a4 100644 --- a/qubesadmin/tests/app.py +++ b/qubesadmin/tests/app.py @@ -135,6 +135,16 @@ class TC_00_VMCollection(qubesadmin.tests.QubesTestCase): class TC_10_QubesBase(qubesadmin.tests.QubesTestCase): + def setUp(self): + super(TC_10_QubesBase, self).setUp() + self.check_output_patch = mock.patch( + 'subprocess.check_output') + self.check_output_mock = self.check_output_patch.start() + + def tearDown(self): + self.check_output_patch.stop() + super(TC_10_QubesBase, self).tearDown() + def test_010_new_simple(self): self.app.expected_calls[('dom0', 'admin.vm.Create.AppVM', None, b'name=new-vm label=red')] = b'0\x00' @@ -355,6 +365,11 @@ class TC_10_QubesBase(qubesadmin.tests.QubesTestCase): 'test-template', b'name=new-name label=red')] = b'0\x00' new_vm = self.app.clone_vm('test-vm', 'new-name') self.assertEqual(new_vm.name, 'new-name') + self.check_output_mock.assert_called_once_with( + ['qvm-appmenus', '--init', '--update', + '--source', 'test-vm', 'new-name'], + stderr=subprocess.STDOUT + ) self.assertAllCalled() def test_031_clone_object(self): diff --git a/qubesadmin/tests/tools/qvm_create.py b/qubesadmin/tests/tools/qvm_create.py index 644b4fb..70ff4ad 100644 --- a/qubesadmin/tests/tools/qvm_create.py +++ b/qubesadmin/tests/tools/qvm_create.py @@ -19,6 +19,8 @@ # with this program; if not, see . import os import tempfile +import unittest.mock +import subprocess import qubesadmin.tests import qubesadmin.tests.tools @@ -210,7 +212,8 @@ class TC_00_qvm_create(qubesadmin.tests.QubesTestCase): self.assertAllCalled() self.assertTrue(os.path.exists(root_file.name)) - def test_011_standalonevm(self): + @unittest.mock.patch('subprocess.check_output') + def test_011_standalonevm(self, check_output_mock): self.app.expected_calls[('dom0', 'admin.label.List', None, None)] = \ b'0\x00red\nblue\n' self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \ @@ -310,6 +313,10 @@ class TC_00_qvm_create(qubesadmin.tests.QubesTestCase): qubesadmin.tools.qvm_create.main(['-C', 'StandaloneVM', '-t', 'template', '-l', 'red', 'new-vm'], app=self.app) + check_output_mock.assert_called_once_with( + ['qvm-appmenus', '--init', '--update', + '--source', 'template', 'new-vm'], + stderr=subprocess.STDOUT) self.assertAllCalled() def test_012_invalid_label(self): @@ -321,4 +328,3 @@ class TC_00_qvm_create(qubesadmin.tests.QubesTestCase): app=self.app) self.assertIn('red, blue', stderr.getvalue()) self.assertAllCalled() -