From 85560c0c9dc750a39b5b5a2f074fea7ff213bc0f Mon Sep 17 00:00:00 2001 From: mickael e Date: Mon, 17 Feb 2020 10:19:10 -0500 Subject: [PATCH] Apply dom0 state in updater --- launcher/sdw_updater_gui/Updater.py | 18 +++++++++++++++ launcher/sdw_updater_gui/UpdaterApp.py | 5 ++++ launcher/tests/test_updater.py | 32 ++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/launcher/sdw_updater_gui/Updater.py b/launcher/sdw_updater_gui/Updater.py index e904eb98..40600eb9 100644 --- a/launcher/sdw_updater_gui/Updater.py +++ b/launcher/sdw_updater_gui/Updater.py @@ -394,6 +394,24 @@ def overall_update_status(results): return UpdateStatus.UPDATES_OK +def apply_dom0_state(): + """ + Applies the dom0 state to ensure dom0 and AppVMs are properly + Configured. This will *not* enforce configuration inside the AppVMs. + Here, we call qubectl directly (instead of through securedrop-admin) to + ensure it is environment-specific. + """ + sdlog.info("Applying dom0 state") + try: + subprocess.check_call(["sudo", "qubesctl", "--show-output", "state.highstate"]) + sdlog.info("Dom0 state applied") + return UpdateStatus.UPDATES_OK + except subprocess.CalledProcessError as e: + sdlog.error("Failed to dom0 state") + sdlog.error(str(e)) + return UpdateStatus.UPDATES_FAILED + + def shutdown_and_start_vms(): """ Power cycles the vms to ensure. we should do them all in one shot to reduce complexity diff --git a/launcher/sdw_updater_gui/UpdaterApp.py b/launcher/sdw_updater_gui/UpdaterApp.py index f0a5bc01..51c52f42 100644 --- a/launcher/sdw_updater_gui/UpdaterApp.py +++ b/launcher/sdw_updater_gui/UpdaterApp.py @@ -278,6 +278,11 @@ def run(self): for vm, progress, result in upgrade_generator: results[vm] = result self.progress_signal.emit(progress) + + # apply dom0 state + result = Updater.apply_dom0_state() + # add to results dict, if it fails it will show error message + results["apply_dom0"] = result.value # reboot vms Updater.shutdown_and_start_vms() diff --git a/launcher/tests/test_updater.py b/launcher/tests/test_updater.py index 19804f2f..ce42e312 100644 --- a/launcher/tests/test_updater.py +++ b/launcher/tests/test_updater.py @@ -826,3 +826,35 @@ def test_last_required_reboot_performed_not_required( result = updater.last_required_reboot_performed() assert result is True assert not mocked_error.called + + +@mock.patch("subprocess.check_call") +@mock.patch("Updater.sdlog.error") +@mock.patch("Updater.sdlog.info") +def test_apply_dom0_state_success(mocked_info, mocked_error, mocked_subprocess): + updater.apply_dom0_state() + log_call_list = [call("Applying dom0 state"), call("Dom0 state applied")] + mocked_subprocess.assert_called_once_with( + ["sudo", "qubesctl", "--show-output", "state.highstate"] + ) + mocked_info.assert_has_calls(log_call_list) + assert not mocked_error.called + + +@mock.patch( + "subprocess.check_call", + side_effect=[subprocess.CalledProcessError(1, "check_call"), "0"], +) +@mock.patch("Updater.sdlog.error") +@mock.patch("Updater.sdlog.info") +def test_apply_dom0_state_failure(mocked_info, mocked_error, mocked_subprocess): + updater.apply_dom0_state() + log_error_calls = [ + call("Failed to dom0 state"), + call("Command 'check_call' returned non-zero exit status 1."), + ] + mocked_subprocess.assert_called_once_with( + ["sudo", "qubesctl", "--show-output", "state.highstate"] + ) + mocked_info.assert_called_once_with("Applying dom0 state") + mocked_error.assert_has_calls(log_error_calls)