Beispiel #1
0
 def create_built_configuration(self,
                                configuration_args: Dict = None
                                ) -> DockerBuildConfiguration:
     if configuration_args is None:
         configuration_args = {}
     _, configuration = self.create_docker_setup(**configuration_args)
     build_result = DockerBuilder((configuration,), checksum_calculator_factory=lambda: self.checksum_calculator) \
         .build(configuration)
     assert len(build_result) == 1
     assert not self.is_uploaded(configuration)
     return configuration
Beispiel #2
0
    def setUp(self):
        super().setUp()
        self._captured_main = CaptureWrapBuilder(
            capture_stdout=True,
            capture_exceptions=lambda e: isinstance(
                e, SystemExit) and e.code == 0).build(main)

        self.build_configurations = BuildConfigurationContainer[
            DockerBuildConfiguration](self.create_docker_setup()[1]
                                      for _ in range(3))
        self.run_configuration = Configuration(self.build_configurations)

        self.pre_built_configuration = list(self.build_configurations)[0]
        builder = DockerBuilder(self.build_configurations)
        build_result = builder.build(self.pre_built_configuration)
        assert len(build_result) == 1
        self.run_configuration.checksum_storage = MemoryChecksumStorage({
            self.pre_built_configuration.identifier:
            builder.checksum_calculator.calculate_checksum(
                self.pre_built_configuration)
        })
 def setUp(self):
     super().setUp()
     self.checksum_storage = MemoryChecksumStorage()
     self.docker_builder = DockerBuilder(checksum_retriever=self.checksum_storage)
Beispiel #4
0
def main(cli_arguments: List[str], stdin_content: Optional[str] = None):
    """
    Entrypoint.
    :param cli_arguments: arguments passed in via the CLI
    :param stdin_content: content written on stdin
    :raises SystemExit: always raised
    """
    cli_configuration = parse_cli_configuration(cli_arguments)
    configuration = read_configuration(
        cli_configuration.configuration_location)

    if cli_configuration.log_verbosity:
        logging.getLogger(PACKAGE_NAME).setLevel(
            cli_configuration.log_verbosity)

    logger.debug(
        f"Checksum storage: {configuration.checksum_storage.__class__.__name__}"
    )
    if isinstance(configuration.checksum_storage,
                  MemoryChecksumStorage) and stdin_content:
        logger.info("Reading checksums from stdin")
        configuration.checksum_storage.set_all_checksums(
            json.loads(stdin_content))

    docker_builder = DockerBuilder(
        managed_build_configurations=configuration.docker_build_configurations,
        checksum_retriever=configuration.checksum_storage)
    build_results = docker_builder.build_all()

    docker_client = docker.from_env()
    try:
        build_configurations_to_upload = list(build_results.keys())
        for build_configuration in configuration.docker_build_configurations:
            if build_configuration.always_upload and build_configuration not in build_configurations_to_upload:
                # build configuration was not just rebuilt but we want to tag it, so pull it from the registries
                # before tagging
                for docker_registry in configuration.docker_registries:
                    repository_location = docker_registry.get_repository_location(
                        build_configuration.name)
                    auth_config = None
                    if docker_registry.username is not None and docker_registry.password is not None:
                        auth_config = {
                            "username": docker_registry.username,
                            "password": docker_registry.password
                        }
                    logger.info(f"Pulling image from {repository_location}")
                    try:
                        docker_client.images.pull(repository_location,
                                                  auth_config=auth_config)
                    except APIError:
                        logger.info(
                            f"Could not pull from {repository_location}")
                        continue
                    logger.info(
                        f"Pulled {repository_location}, tagging it with local {build_configuration.identifier}"
                    )
                    docker_client.api.tag(
                        repository_location,
                        repository=build_configuration.identifier)

                # since always_upload is set, add this build configuration to the list of configs to upload
                build_configurations_to_upload.append(build_configuration)
    finally:
        docker_client.close()

    if len(configuration.docker_registries) == 0:
        logger.info(
            "No Docker registries defined so will not upload images (or update checksums in store)"
        )
    else:
        for repository in configuration.docker_registries:
            with DockerUploader(configuration.checksum_storage,
                                repository) as uploader:
                for build_configuration in build_configurations_to_upload:
                    uploader.upload(build_configuration)

    all_built: Dict[str, str] = {}
    built_now: Dict[str, str] = {}
    for build_configuration in configuration.docker_build_configurations:
        checksum = docker_builder.checksum_calculator.calculate_checksum(
            build_configuration)
        all_built[build_configuration.identifier] = checksum
        if build_configuration in build_results:
            built_now[build_configuration.identifier] = checksum

    output = built_now
    if not cli_configuration.output_built_only:
        logger.info(f"Build results: %s" % json.dumps(built_now))
        output = all_built
    print(json.dumps(output))

    exit(0)
class TestDockerBuilder(TestWithDockerBuildConfiguration):
    """
    Tests for `DockerBuilder`.
    """
    def setUp(self):
        super().setUp()
        self.checksum_storage = MemoryChecksumStorage()
        self.docker_builder = DockerBuilder(checksum_retriever=self.checksum_storage)

    def test_build_when_dockerfile_is_invalid(self):
        _, configuration = self.create_docker_setup(commands=["invalid"])
        self.docker_builder.managed_build_configurations.add(configuration)
        self.assertRaises(InvalidDockerfileBuildError, self.docker_builder.build, configuration)

    def test_build_when_build_fails(self):
        _, configuration = self.create_docker_setup(commands=[f"{RUN_DOCKER_COMMAND} exit 1"])
        self.docker_builder.managed_build_configurations.add(configuration)
        self.assertRaises(BuildStepError, self.docker_builder.build, configuration)

    def test_build_when_from_image_is_not_managed(self):
        _, configuration = self.create_docker_setup()
        assert configuration.identifier not in \
               itertools.chain(*(image.tags for image in self.docker_client.images.list()))
        self.assertRaises(UnmanagedBuildError, self.docker_builder.build, configuration)

    def test_build_when_from_image_is_managed(self):
        configurations = self.create_dependent_docker_build_configurations(4)
        self.docker_builder.managed_build_configurations.add_all(configurations)
        self.docker_builder.managed_build_configurations.add(self.create_docker_setup()[1])

        build_results = self.docker_builder.build(configurations[-1])
        self.assertCountEqual(
            {configuration: configuration.identifier for configuration in configurations}, build_results)

    def test_build_when_circular_dependency(self):
        configurations = [
            self.create_docker_setup(image_name=EXAMPLE_IMAGE_NAME_1, from_image_name=EXAMPLE_IMAGE_NAME_2)[1],
            self.create_docker_setup(image_name=EXAMPLE_IMAGE_NAME_2, from_image_name=EXAMPLE_IMAGE_NAME_1)[1]]
        self.docker_builder.managed_build_configurations.add_all(configurations)
        self.assertRaises(CircularDependencyBuildError, self.docker_builder.build_all)

    def test_build_when_up_to_date(self):
        _, configuration = self.create_docker_setup()
        self.docker_builder.managed_build_configurations.add(configuration)
        self.checksum_storage.set_checksum(
            configuration.identifier, self.docker_builder.checksum_calculator.calculate_checksum(configuration))

        build_results = self.docker_builder.build(configuration)
        self.assertEqual(0, len(build_results))

    def test_build_all_when_none_managed(self):
        built = self.docker_builder.build_all()
        self.assertEqual(0, len(built))

    def test_build_all_when_one_fails(self):
        configurations = self.create_dependent_docker_build_configurations(4)
        configurations += [self.create_docker_setup(commands=[f"{RUN_DOCKER_COMMAND} exit 1"])[1]]
        self.docker_builder.managed_build_configurations.add_all(configurations)
        self.assertRaises(BuildStepError, self.docker_builder.build_all)

    def test_build_all_when_managed(self):
        configurations = self.create_dependent_docker_build_configurations(4)
        self.docker_builder.managed_build_configurations.add_all(configurations)

        build_results = self.docker_builder.build_all()
        self.assertCountEqual(
            {configuration: configuration.identifier for configuration in configurations}, build_results)

    def test_build_all_when_some_up_to_date(self):
        import logging
        logging.getLogger().setLevel(logging.DEBUG)
        configurations = self.create_dependent_docker_build_configurations(4)
        self.docker_builder.managed_build_configurations.add_all(configurations)

        build_results = self.docker_builder.build(configurations[1])
        assert len(build_results) == 2

        for configuration in build_results.keys():
            checksum = self.docker_builder.checksum_calculator.calculate_checksum(configuration)
            self.checksum_storage.set_checksum(configuration.identifier, checksum)

        build_results = self.docker_builder.build_all()
        self.assertCountEqual(configurations[2:], build_results)

    def test_build_when_from_image_updated(self):
        configurations = self.create_dependent_docker_build_configurations(2)
        self.docker_builder.managed_build_configurations.add_all(configurations)

        build_results = self.docker_builder.build_all()
        assert len(build_results) == 2

        for configuration in build_results.keys():
            checksum = self.docker_builder.checksum_calculator.calculate_checksum(configuration)
            self.checksum_storage.set_checksum(configuration.identifier, checksum)

        parent_image = configurations[0]

        with open(parent_image.dockerfile_location, "a") as file:
            file.write(f"{RUN_DOCKER_COMMAND} echo 1")
        parent_image.reload()

        build_results = self.docker_builder.build_all()
        self.assertEqual(2, len(build_results))