Skip to content

Commit f8dea94

Browse files
committed
Use admin utils wrappers for vm actions
1 parent 32a14bb commit f8dea94

5 files changed

Lines changed: 53 additions & 57 deletions

File tree

vmupdate/qube_connection.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
# along with this program; if not, write to the Free Software
1919
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
2020
# USA.
21+
22+
import asyncio
2123
import os
2224
import shutil
2325
import signal
@@ -93,14 +95,13 @@ def __exit__(self, exc_type, exc_val, exc_tb):
9395
)
9496

9597
if self.qube.is_running() and not self._initially_running:
98+
wait = False
9699
if self._has_assigned_pci_devices(self.qube):
97100
self.logger.info(
98101
'Waiting for full shutdown %s (PCI devices assigned)',
99102
self.qube.name)
100-
shutdown_domains([self.qube], self.logger)
101-
else:
102-
self.logger.info('Shutdown %s', self.qube.name)
103-
self.qube.shutdown()
103+
wait = True
104+
asyncio.run(shutdown_domains([self.qube], self.logger, wait=wait))
104105

105106
self.__connected = False
106107

vmupdate/tests/test_qube_connection.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@
2323
from vmupdate.qube_connection import QubeConnection
2424

2525

26-
@patch("vmupdate.qube_connection.shutdown_domains")
27-
def test_wait_for_shutdown_when_vm_started_by_update(shutdown_domains):
26+
def test_wait_for_shutdown_when_vm_started_by_update():
2827
vm = Mock()
2928
vm.name = "hvm1"
3029
vm.is_running.side_effect = [False, True]
@@ -38,12 +37,10 @@ def test_wait_for_shutdown_when_vm_started_by_update(shutdown_domains):
3837
show_progress=False, status_notifier=status_notifier):
3938
pass
4039

41-
shutdown_domains.assert_called_once_with([vm], logger)
42-
vm.shutdown.assert_not_called()
40+
vm.shutdown.assert_called_once_with(force=False, wait=True)
4341

4442

45-
@patch("vmupdate.qube_connection.shutdown_domains")
46-
def test_do_not_wait_for_shutdown_without_assigned_pci(shutdown_domains):
43+
def test_do_not_wait_for_shutdown_without_assigned_pci():
4744
vm = Mock()
4845
vm.name = "hvm2"
4946
vm.is_running.side_effect = [False, True]
@@ -57,12 +54,10 @@ def test_do_not_wait_for_shutdown_without_assigned_pci(shutdown_domains):
5754
show_progress=False, status_notifier=status_notifier):
5855
pass
5956

60-
vm.shutdown.assert_called_once_with()
61-
shutdown_domains.assert_not_called()
57+
vm.shutdown.assert_called_once_with(force=False, wait=False)
6258

6359

64-
@patch("vmupdate.qube_connection.shutdown_domains")
65-
def test_do_not_shutdown_if_vm_was_already_running(shutdown_domains):
60+
def test_do_not_shutdown_if_vm_was_already_running():
6661
vm = Mock()
6762
vm.name = "hvm3"
6863
vm.is_running.return_value = True
@@ -77,4 +72,3 @@ def test_do_not_shutdown_if_vm_was_already_running(shutdown_domains):
7772
pass
7873

7974
vm.shutdown.assert_not_called()
80-
shutdown_domains.assert_not_called()

vmupdate/tests/test_vmupdate.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -383,11 +383,9 @@ def test_selection(
383383
@patch("vmupdate.update_manager.UpdateAgentManager")
384384
@patch("multiprocessing.Pool")
385385
@patch("multiprocessing.Manager")
386-
@patch("asyncio.run")
387386
@patch("subprocess.Popen")
388387
def test_restarting(
389388
dummy_subprocess,
390-
arun,
391389
mp_manager,
392390
mp_pool,
393391
agent_mng,
@@ -506,7 +504,6 @@ def test_restarting(
506504

507505
fails = {args: failed[args] for args in failed if failed[args]}
508506
assert not fails
509-
arun.asseert_called()
510507

511508

512509
stat = FinalStatus
@@ -719,7 +716,6 @@ def test_error(
719716
@patch("os.chown")
720717
@patch("logging.FileHandler")
721718
@patch("logging.getLogger")
722-
@patch("asyncio.run")
723719
@pytest.mark.parametrize(
724720
"action, code",
725721
(
@@ -729,7 +725,6 @@ def test_error(
729725
),
730726
)
731727
def test_error_apply(
732-
_arun,
733728
_logger,
734729
_log_file,
735730
_chmod,

vmupdate/utils.py

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,42 @@
2222
from datetime import datetime
2323

2424
import qubesadmin.exc
25-
from qubesadmin.events.utils import wait_for_domain_shutdown
25+
from qubesadmin.utils import shutdown, start
2626
from vmupdate.agent.source.common.exit_codes import EXIT
2727

2828

29-
def shutdown_domains(to_shutdown, log):
29+
async def shutdown_domains(
30+
to_shutdown,
31+
log,
32+
wait: bool = False,
33+
force: bool = False,
34+
):
3035
"""
3136
Try to shut down vms and wait to finish.
3237
"""
3338
ret_code = EXIT.OK
34-
wait_for = []
35-
for vm in to_shutdown:
36-
try:
37-
vm.shutdown(force=True)
38-
wait_for.append(vm)
39-
except qubesadmin.exc.QubesVMError as exc:
40-
log.error(str(exc))
39+
all_failed = []
40+
failed = await shutdown(
41+
domains=to_shutdown, logger=log, wait=wait, force=force
42+
)
43+
for item in failed:
44+
if not item:
45+
continue
46+
for qube in item:
47+
all_failed.append(qube)
4148
ret_code = EXIT.ERR_SHUTDOWN_APP
49+
done = [qube for qube in to_shutdown if qube not in all_failed]
50+
return ret_code, done
4251

43-
asyncio.run(wait_for_domain_shutdown(wait_for))
4452

45-
return ret_code, wait_for
53+
async def restart_vms(to_restart, log):
54+
"""
55+
Try to restart vms.
56+
"""
57+
ret_code, shutdowns = await shutdown_domains(to_restart, log)
58+
if await start(domains=shutdowns, logger=log):
59+
ret_code = EXIT.ERR_START_APP
60+
return ret_code
4661

4762

4863
def get_feature(vm, feature_name, default_value=None):
@@ -84,3 +99,5 @@ def is_stale(vm, expiration_period):
8499
except qubesadmin.exc.QubesDaemonCommunicationError:
85100
pass
86101
return False
102+
103+

vmupdate/vmupdate.py

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,25 @@
44
"""
55

66
import argparse
7+
import asyncio
78
import logging
89
import sys
910
import os
1011
import grp
1112
from typing import Set, Iterable, Dict, Tuple
1213

1314
import qubesadmin
15+
import qubesadmin.utils
1416
import qubesadmin.exc
1517
from vmupdate.agent.source.status import FinalStatus
1618
from vmupdate.agent.source.common.exit_codes import EXIT
17-
from vmupdate.utils import shutdown_domains, get_feature, get_boolean_feature, \
18-
is_stale
19+
from vmupdate.utils import (
20+
shutdown_domains,
21+
restart_vms,
22+
get_feature,
23+
get_boolean_feature,
24+
is_stale,
25+
)
1926
from . import update_manager
2027
from .agent.source.args import AgentArgs
2128

@@ -109,9 +116,9 @@ def main(args=None, app=qubesadmin.Qubes()):
109116
and no_updates
110117
)
111118

112-
ret_code_restart = apply_updates_to_appvm(
119+
ret_code_restart = asyncio.run(apply_updates_to_appvm(
113120
args, independent, templ_statuses, app_statuses, log
114-
)
121+
))
115122

116123
ret_code = max(
117124
ret_code_admin, ret_code_independent, ret_code_appvm, ret_code_restart
@@ -386,7 +393,7 @@ def run_update(
386393
return ret_code, statuses
387394

388395

389-
def apply_updates_to_appvm(
396+
async def apply_updates_to_appvm(
390397
args,
391398
vm_updated: Iterable,
392399
template_statuses: Dict[str, FinalStatus],
@@ -435,7 +442,7 @@ def apply_updates_to_appvm(
435442

436443
# first shutdown templates to apply changes to the root volume
437444
# they are no need to start templates automatically
438-
ret_code, _ = shutdown_domains(templates_to_shutdown, log)
445+
ret_code, _ = await shutdown_domains(templates_to_shutdown, log)
439446

440447
if ret_code != EXIT.OK:
441448
log.error("Shutdown of some templates fails with code %d", ret_code)
@@ -454,11 +461,11 @@ def apply_updates_to_appvm(
454461
)
455462

456463
# both flags `restart` and `apply-to-all` include service vms
457-
ret_code_ = restart_vms(to_restart, log)
464+
ret_code_ = await restart_vms(to_restart, log)
458465
ret_code = max(ret_code, ret_code_)
459466
if args.apply_to_all:
460467
# there is no need to start plain AppVMs automatically
461-
ret_code_, _ = shutdown_domains(to_shutdown, log)
468+
ret_code_, _ = await shutdown_domains(to_shutdown, log)
462469
ret_code = max(ret_code, ret_code_)
463470

464471
return ret_code
@@ -486,23 +493,5 @@ def get_derived_vm_to_apply(templates, derived_statuses):
486493
return to_restart, to_shutdown
487494

488495

489-
490-
def restart_vms(to_restart, log):
491-
"""
492-
Try to restart vms.
493-
"""
494-
ret_code, shutdowns = shutdown_domains(to_restart, log)
495-
496-
# restart shutdown qubes
497-
for vm in shutdowns:
498-
try:
499-
vm.start()
500-
except qubesadmin.exc.QubesVMError as exc:
501-
log.error(str(exc))
502-
ret_code = EXIT.ERR_START_APP
503-
504-
return ret_code
505-
506-
507496
if __name__ == "__main__":
508497
sys.exit(main())

0 commit comments

Comments
 (0)