diff --git a/subiquity/server/controllers/filesystem.py b/subiquity/server/controllers/filesystem.py index b9f091dd..b792426c 100644 --- a/subiquity/server/controllers/filesystem.py +++ b/subiquity/server/controllers/filesystem.py @@ -20,6 +20,7 @@ import json import logging import os import pathlib +import subprocess import time from typing import Any, Callable, Dict, List, Optional, Union @@ -1532,6 +1533,15 @@ class FilesystemController(SubiquityController, FilesystemManipulator): async def _pre_shutdown(self): if not self.reset_partition_only: - await self.app.command_runner.run(["umount", "--recursive", "/target"]) + # /target is mounted only if the installation was actually started. + try: + await self.app.command_runner.run(["mountpoint", "/target"]) + except subprocess.CalledProcessError: + log.debug( + "/target does not exist or is not mounted," + " skipping call to umount --recursive" + ) + else: + await self.app.command_runner.run(["umount", "--recursive", "/target"]) if len(self.model._all(type="zpool")) > 0: await self.app.command_runner.run(["zpool", "export", "-a"]) diff --git a/subiquity/server/controllers/tests/test_filesystem.py b/subiquity/server/controllers/tests/test_filesystem.py index cf6cb6bb..a48e82d8 100644 --- a/subiquity/server/controllers/tests/test_filesystem.py +++ b/subiquity/server/controllers/tests/test_filesystem.py @@ -14,6 +14,7 @@ # along with this program. If not, see . import copy +import subprocess import uuid from unittest import IsolatedAsyncioTestCase, mock @@ -89,6 +90,7 @@ class TestSubiquityControllerFilesystem(IsolatedAsyncioTestCase): def setUp(self): self.app = make_app() self.app.opts.bootloader = "UEFI" + self.app.command_runner = mock.AsyncMock() self.app.report_start_event = mock.Mock() self.app.report_finish_event = mock.Mock() self.app.prober = mock.Mock() @@ -343,6 +345,32 @@ class TestSubiquityControllerFilesystem(IsolatedAsyncioTestCase): self.assertTrue(self.fsc.locked_probe_data) handler.assert_called_once() + async def test__pre_shutdown_install_started(self): + self.fsc.reset_partition_only = False + run = mock.patch.object(self.app.command_runner, "run") + _all = mock.patch.object(self.fsc.model, "_all") + with run as mock_run, _all: + await self.fsc._pre_shutdown() + mock_run.assert_has_calls( + [ + mock.call(["mountpoint", "/target"]), + mock.call(["umount", "--recursive", "/target"]), + ] + ) + self.assertEqual(len(mock_run.mock_calls), 2) + + async def test__pre_shutdown_install_not_started(self): + async def fake_run(cmd, **kwargs): + if cmd == ["mountpoint", "/target"]: + raise subprocess.CalledProcessError(cmd=cmd, returncode=1) + + self.fsc.reset_partition_only = False + run = mock.patch.object(self.app.command_runner, "run", side_effect=fake_run) + _all = mock.patch.object(self.fsc.model, "_all") + with run as mock_run, _all: + await self.fsc._pre_shutdown() + mock_run.assert_called_once_with(["mountpoint", "/target"]) + class TestGuided(IsolatedAsyncioTestCase): boot_expectations = [