Ejemplo n.º 1
0
    def pack_charm_in_instance(self, *, bases_index: int, build_on: Base,
                               build_on_index: int) -> str:
        """Pack instance in Charm."""
        charm_name = format_charm_file_name(self.metadata.name,
                                            self.config.bases[bases_index])

        # If building in project directory, use the project path as the working
        # directory. The output charms will be placed in the correct directory
        # without needing retrieval. If outputing to a directory other than the
        # charm project directory, we need to output the charm outside the
        # project directory and can retrieve it when complete.
        cwd = pathlib.Path.cwd()
        if cwd == self.charmdir:
            instance_output_dir = get_managed_environment_project_path()
            pull_charm = False
        else:
            instance_output_dir = get_managed_environment_home_path()
            pull_charm = True

        cmd = ["charmcraft", "pack", "--bases-index", str(bases_index)]

        if message_handler.mode == message_handler.VERBOSE:
            cmd.append("--verbose")
        elif message_handler.mode == message_handler.QUIET:
            cmd.append("--quiet")

        logger.info(f"Packing charm {charm_name!r}...")
        with launched_environment(
                charm_name=self.metadata.name,
                project_path=self.charmdir,
                base=build_on,
                bases_index=bases_index,
                build_on_index=build_on_index,
        ) as instance:
            try:
                instance.execute_run(
                    cmd,
                    check=True,
                    cwd=instance_output_dir.as_posix(),
                )
            except subprocess.CalledProcessError as error:
                capture_logs_from_instance(instance)
                raise CommandError(
                    f"Failed to build charm for bases index '{bases_index}'."
                ) from error

            if pull_charm:
                try:
                    instance.pull_file(
                        source=instance_output_dir / charm_name,
                        destination=cwd / charm_name,
                    )
                except FileNotFoundError as error:
                    raise CommandError(
                        "Unexpected error retrieving charm from instance."
                    ) from error

        return charm_name
Ejemplo n.º 2
0
def test_capture_logs_from_instance_not_found(
    emitter, mock_instance, mock_namedtemporaryfile, tmp_path
):
    fake_log = pathlib.Path(mock_namedtemporaryfile.return_value.name)
    mock_instance.pull_file.side_effect = FileNotFoundError()

    providers.capture_logs_from_instance(mock_instance)

    assert mock_instance.mock_calls == [
        mock.call.pull_file(source=pathlib.Path("/tmp/charmcraft.log"), destination=fake_log),
    ]
    emitter.assert_trace("No logs found in instance.")
Ejemplo n.º 3
0
def test_capture_logs_from_instance_not_found(mock_executor, mock_logger,
                                              mock_mkstemp, tmp_path):
    fake_log = tmp_path / "x.log"
    mock_mkstemp.return_value = (None, str(fake_log))
    mock_executor.pull_file.side_effect = FileNotFoundError()

    providers.capture_logs_from_instance(mock_executor)

    assert mock_executor.mock_calls == [
        mock.call.pull_file(source=pathlib.Path("/tmp/charmcraft.log"),
                            destination=fake_log),
    ]
    assert mock_logger.mock_calls == [
        mock.call.debug("No logs found in instance.")
    ]
Ejemplo n.º 4
0
def test_capture_logs_from_instance(mock_executor, mock_logger, mock_mkstemp,
                                    tmp_path):
    fake_log = tmp_path / "x.log"
    mock_mkstemp.return_value = (None, str(fake_log))

    fake_log_data = "some\nlog data\nhere"
    fake_log.write_text(fake_log_data)

    providers.capture_logs_from_instance(mock_executor)

    assert mock_executor.mock_calls == [
        mock.call.pull_file(source=pathlib.Path("/tmp/charmcraft.log"),
                            destination=fake_log),
    ]
    assert mock_logger.mock_calls == [
        mock.call.debug("Logs captured from managed instance:\n%s",
                        fake_log_data)
    ]
Ejemplo n.º 5
0
def test_capture_logs_from_instance(emitter, mock_instance, mock_namedtemporaryfile, tmp_path):
    fake_log = pathlib.Path(mock_namedtemporaryfile.return_value.name)
    fake_log_data = "some\nlog data\nhere"
    fake_log.write_text(fake_log_data)

    providers.capture_logs_from_instance(mock_instance)

    assert mock_instance.mock_calls == [
        mock.call.pull_file(source=pathlib.Path("/tmp/charmcraft.log"), destination=fake_log),
    ]
    emitter.assert_interactions(
        [
            mock.call("trace", "Logs captured from managed instance:"),
            mock.call("trace", ":: some"),
            mock.call("trace", ":: log data"),
            mock.call("trace", ":: here"),
        ]
    )
    assert mock_namedtemporaryfile.mock_calls == [
        mock.call(delete=False, prefix="charmcraft-"),
        mock.call().close(),
    ]
Ejemplo n.º 6
0
    def pack_charm_in_instance(self, *, bases_index: int, build_on: Base,
                               build_on_index: int) -> str:
        """Pack instance in Charm."""
        charm_name = format_charm_file_name(self.metadata.name,
                                            self.config.bases[bases_index])

        # If building in project directory, use the project path as the working
        # directory. The output charms will be placed in the correct directory
        # without needing retrieval. If outputing to a directory other than the
        # charm project directory, we need to output the charm outside the
        # project directory and can retrieve it when complete.
        cwd = pathlib.Path.cwd()
        if cwd == self.charmdir:
            instance_output_dir = env.get_managed_environment_project_path()
            pull_charm = False
        else:
            instance_output_dir = env.get_managed_environment_home_path()
            pull_charm = True

        cmd = ["charmcraft", "pack", "--bases-index", str(bases_index)]

        if emit.get_mode() == EmitterMode.VERBOSE:
            cmd.append("--verbose")
        elif emit.get_mode() == EmitterMode.QUIET:
            cmd.append("--quiet")
        elif emit.get_mode() == EmitterMode.TRACE:
            cmd.append("--trace")

        if self.debug:
            cmd.append("--debug")

        if self.shell:
            cmd.append("--shell")

        if self.shell_after:
            cmd.append("--shell-after")

        emit.progress(f"Launching environment to pack for base {build_on}")
        with self.provider.launched_environment(
                charm_name=self.metadata.name,
                project_path=self.charmdir,
                base=build_on,
                bases_index=bases_index,
                build_on_index=build_on_index,
        ) as instance:
            emit.progress("Packing the charm")
            try:
                with emit.open_stream(f"Running {cmd}") as stream:
                    instance.execute_run(
                        cmd,
                        check=True,
                        cwd=instance_output_dir,
                        stdout=stream,
                        stderr=stream,
                    )
            except subprocess.CalledProcessError as error:
                capture_logs_from_instance(instance)
                raise CommandError(
                    f"Failed to build charm for bases index '{bases_index}'."
                ) from error

            if pull_charm:
                try:
                    instance.pull_file(
                        source=instance_output_dir / charm_name,
                        destination=cwd / charm_name,
                    )
                except FileNotFoundError as error:
                    raise CommandError(
                        "Unexpected error retrieving charm from instance."
                    ) from error

        emit.progress("Charm packed ok")
        return charm_name