diff --git a/craft_providers/base.py b/craft_providers/base.py index c7b3abc0..6602a43b 100644 --- a/craft_providers/base.py +++ b/craft_providers/base.py @@ -979,6 +979,7 @@ def setup( *, executor: Executor, timeout: Optional[float] = TIMEOUT_UNPREDICTABLE, + mount_cache: bool = True, ) -> None: """Prepare base instance for use by the application. @@ -994,6 +995,7 @@ def setup( :param executor: Executor for target container. :param timeout: Timeout in seconds. + :param mount_cache: If true, mount the cache directories. :raises BaseCompatibilityError: if instance is incompatible. :raises BaseConfigurationError: on other unexpected error. @@ -1015,7 +1017,8 @@ def setup( self._update_compatibility_tag(executor=executor) - self._mount_shared_cache_dirs(executor=executor) + if mount_cache: + self._mount_shared_cache_dirs(executor=executor) self._pre_setup_os(executor=executor) self._setup_os(executor=executor) diff --git a/craft_providers/lxd/launcher.py b/craft_providers/lxd/launcher.py index 0d3413a2..205bda4d 100644 --- a/craft_providers/lxd/launcher.py +++ b/craft_providers/lxd/launcher.py @@ -143,7 +143,10 @@ def _create_instance( ) config_timer = InstanceTimer(base_instance) config_timer.start() - base_configuration.setup(executor=base_instance) + + # The base configuration shouldn't mount cache directories because if + # they get deleted, copying the base instance will fail. + base_configuration.setup(executor=base_instance, mount_cache=False) _set_timezone( base_instance, base_instance.project, @@ -219,7 +222,10 @@ def _create_instance( instance.restart() else: instance.start() - base_configuration.wait_until_ready(executor=instance) + # Warmup the instance to ensure we have everything set up. + # There are cases where setup won't do everything to the base instance that + # warmup does to the final instance (such as mounting cache directories). + base_configuration.warmup(executor=instance) def _ensure_project_exists( diff --git a/tests/integration/lxd/test_launcher.py b/tests/integration/lxd/test_launcher.py index f8ee4a6d..3e88b40d 100644 --- a/tests/integration/lxd/test_launcher.py +++ b/tests/integration/lxd/test_launcher.py @@ -55,11 +55,12 @@ def _base_instance( @pytest.fixture() -def base_configuration(): +def base_configuration(tmp_path): """Returns a simple base configuration.""" return ubuntu.BuilddBase( alias=ubuntu.BuilddBaseAlias.JAMMY, hostname="test-hostname", + cache_path=tmp_path / "cache", ) @@ -224,6 +225,10 @@ def test_launch_use_base_instance( # fingerprint the base instance base_instance.start() base_instance.execute_run(["touch", "/base-instance"]) + assert ( + base_instance.execute_run(["ls", "/root/.cache/pip/"], check=False).returncode + == 2 + ) base_instance.stop() # delete the instance so a new instance is created from the base instance @@ -270,6 +275,8 @@ def test_launch_use_base_instance( assert instance_hostname == instance.instance_name + instance.execute_run(["ls", "/root/.cache/pip/"], check=True) + def test_launch_create_base_instance_with_correct_image_description( base_configuration, get_base_instance, instance_name diff --git a/tests/unit/lxd/test_launcher.py b/tests/unit/lxd/test_launcher.py index 67015e5d..0268b746 100644 --- a/tests/unit/lxd/test_launcher.py +++ b/tests/unit/lxd/test_launcher.py @@ -182,7 +182,7 @@ def test_launch_no_base_instance( assert mock_base_configuration.mock_calls == [ call.get_command_environment(), call.setup(executor=fake_instance), - call.wait_until_ready(executor=fake_instance), + call.warmup(executor=fake_instance), ] @@ -247,8 +247,8 @@ def test_launch_use_base_instance( assert mock_base_configuration.mock_calls == [ call.get_command_environment(), call.get_command_environment(), - call.setup(executor=fake_base_instance), - call.wait_until_ready(executor=fake_instance), + call.setup(executor=fake_base_instance, mount_cache=False), + call.warmup(executor=fake_instance), ] @@ -527,8 +527,8 @@ def test_launch_existing_base_instance_invalid( assert mock_base_configuration.mock_calls == [ call.get_command_environment(), call.get_command_environment(), - call.setup(executor=fake_base_instance), - call.wait_until_ready(executor=fake_instance), + call.setup(executor=fake_base_instance, mount_cache=False), + call.warmup(executor=fake_instance), ] @@ -609,7 +609,7 @@ def test_launch_all_opts( assert mock_base_configuration.mock_calls == [ call.get_command_environment(), call.setup(executor=fake_instance), - call.wait_until_ready(executor=fake_instance), + call.warmup(executor=fake_instance), ] @@ -703,7 +703,7 @@ def test_launch_create_project( assert mock_base_configuration.mock_calls == [ call.get_command_environment(), call.setup(executor=fake_instance), - call.wait_until_ready(executor=fake_instance), + call.warmup(executor=fake_instance), ] @@ -846,7 +846,7 @@ def test_launch_with_existing_instance_incompatible_with_auto_clean( call.get_command_environment(), call.warmup(executor=fake_instance), call.setup(executor=fake_instance), - call.wait_until_ready(executor=fake_instance), + call.warmup(executor=fake_instance), ] @@ -940,7 +940,7 @@ def test_launch_with_existing_ephemeral_instance( assert mock_base_configuration.mock_calls == [ call.get_command_environment(), call.setup(executor=fake_instance), - call.wait_until_ready(executor=fake_instance), + call.warmup(executor=fake_instance), ] @@ -1133,8 +1133,8 @@ def test_use_snapshots_deprecated( assert mock_base_configuration.mock_calls == [ call.get_command_environment(), call.get_command_environment(), - call.setup(executor=fake_base_instance), - call.wait_until_ready(executor=fake_instance), + call.setup(executor=fake_base_instance, mount_cache=False), + call.warmup(executor=fake_instance), ]