From ab2f4fd61b5138e6fa0db101e52fac5d3af27039 Mon Sep 17 00:00:00 2001 From: manusa Date: Fri, 6 Mar 2020 12:12:47 +0100 Subject: [PATCH] refactor: Fixes all problems related with jib logging --- .circleci/config.yml | 4 + CHANGELOG.md | 1 + .../kubernetes/jib/JibServiceUtil.java | 106 +++++++++++++----- samples/spring-boot/pom.xml | 6 +- 4 files changed, 84 insertions(+), 33 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8aa15a20a0..0a3473031c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -151,6 +151,8 @@ jobs: -Dsonar.github.repository=fabric8io/fabric8-maven-plugin \ -Dsonar.github.oauth=${GITHUB_COMMENT_TOKEN} \ -Dsonar.host.url=https://sonarcloud.io \ + -Dsonar.projectKey=io.fabric8:fabric8-maven-plugin-build \ + -Dsonar.organization=default \ -Dsonar.login=${SONARQUBE_TOKEN} else echo "No Sonar PR analysis as this is not a pull request" @@ -171,6 +173,8 @@ jobs: - run: | MAVEN_OPTS="-Xmx3000m" mvn -B clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar \ -Dsonar.host.url=https://sonarcloud.io \ + -Dsonar.projectKey=io.fabric8:fabric8-maven-plugin-build \ + -Dsonar.organization=default \ -Dsonar.login=${SONARQUBE_TOKEN} - save_cache: key: fmp-sonar-{{ checksum "pom.xml" }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 2729adb97d..728934a6ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ Usage: * Fix #1770: Fixed my mistake, remove constructors from OpenshiftBuildConfig which were causing PluginConfigurationException * Fix #1791: Fix NullPointerException in FileDataSecretEnricher (due to recent change in Kubernetes Client Builder null to LinkedHashMap conversion) * Fix: ImageChangeTags not being applied in DeploymentConfig generated by plugin in case of resource fragments. (Issue found in [this](https://stackoverflow.com/questions/60375063) StackOverflow post.) +* Fix #1798: Jib logs display correctly, and support ansi ### 4.4.0 (2020-02-13) * Fix #1572: Support maven --batch-mode option diff --git a/core/src/main/java/io/fabric8/maven/core/service/kubernetes/jib/JibServiceUtil.java b/core/src/main/java/io/fabric8/maven/core/service/kubernetes/jib/JibServiceUtil.java index 6f1f8c9014..0b17e26b01 100644 --- a/core/src/main/java/io/fabric8/maven/core/service/kubernetes/jib/JibServiceUtil.java +++ b/core/src/main/java/io/fabric8/maven/core/service/kubernetes/jib/JibServiceUtil.java @@ -15,7 +15,20 @@ */ package io.fabric8.maven.core.service.kubernetes.jib; -import com.google.cloud.tools.jib.api.*; +import com.google.cloud.tools.jib.api.AbsoluteUnixPath; +import com.google.cloud.tools.jib.api.CacheDirectoryCreationException; +import com.google.cloud.tools.jib.api.Containerizer; +import com.google.cloud.tools.jib.api.Credential; +import com.google.cloud.tools.jib.api.ImageFormat; +import com.google.cloud.tools.jib.api.ImageReference; +import com.google.cloud.tools.jib.api.InvalidImageReferenceException; +import com.google.cloud.tools.jib.api.Jib; +import com.google.cloud.tools.jib.api.JibContainerBuilder; +import com.google.cloud.tools.jib.api.LogEvent; +import com.google.cloud.tools.jib.api.Port; +import com.google.cloud.tools.jib.api.RegistryException; +import com.google.cloud.tools.jib.api.RegistryImage; +import com.google.cloud.tools.jib.api.TarImage; import com.google.cloud.tools.jib.event.events.ProgressEvent; import com.google.cloud.tools.jib.event.events.TimerEvent; import com.google.cloud.tools.jib.event.progress.ProgressEventHandler; @@ -31,6 +44,7 @@ import io.fabric8.maven.docker.util.Logger; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.util.StringUtils; import java.io.File; import java.io.IOException; @@ -41,11 +55,15 @@ import java.util.Objects; import java.util.Optional; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import java.util.function.Consumer; -import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; +import static org.fusesource.jansi.Ansi.ansi; + /** * Class with the static utility methods consumed by JibBuildService. */ @@ -53,29 +71,38 @@ public class JibServiceUtil { private JibServiceUtil() {} + private static final long JIB_EXECUTOR_SHUTDOWN_TIMEOUT_SECONDS = 10L; private static final String DOCKER_REGISTRY = "docker.io"; private static final String BUSYBOX = "busybox:latest"; private static String EMPTY_STRING = ""; private static String TAR_POSTFIX = ".tar"; - static void buildContainer(JibContainerBuilder jibContainerBuilder, TarImage image, Logger logger) { + static void buildContainer(JibContainerBuilder jibContainerBuilder, TarImage image, Logger logger) + throws InterruptedException { + + final ExecutorService jibBuildExecutor = Executors.newCachedThreadPool(); try { jibContainerBuilder.setCreationTime(Instant.now()); jibContainerBuilder.containerize(Containerizer.to(image) + .setExecutorService(jibBuildExecutor) .addEventHandler(LogEvent.class, log(logger)) .addEventHandler(TimerEvent.class, new TimerEventHandler(logger::debug)) - .addEventHandler(ProgressEvent.class, new ProgressEventHandler(logUpdate(logger)))); + .addEventHandler(ProgressEvent.class, new ProgressEventHandler(logUpdate()))); + logUpdateFinished(); } catch (CacheDirectoryCreationException | IOException | ExecutionException | RegistryException ex) { logger.error("Unable to build the image tarball: ", ex); throw new IllegalStateException(ex); } catch (InterruptedException ex) { logger.error("Thread interrupted", ex); - Thread.currentThread().interrupt(); + throw ex; + } finally { + jibBuildExecutor.shutdown(); + jibBuildExecutor.awaitTermination(JIB_EXECUTOR_SHUTDOWN_TIMEOUT_SECONDS, TimeUnit.SECONDS); } } static JibContainerBuilder containerFromImageConfiguration(ImageConfiguration imageConfiguration) - throws InvalidImageReferenceException { + throws InvalidImageReferenceException { final Optional bic = Optional.ofNullable(Objects.requireNonNull(imageConfiguration).getBuildConfiguration()); @@ -124,6 +151,7 @@ static String imageNameFromImageConfiguration(ImageConfiguration imageConfigurat */ public static void jibPush(ImageConfiguration imageConfiguration, MavenProject project, RegistryService.RegistryConfig registryConfig, String outputDirectory, Logger log) throws MojoExecutionException { + BuildImageConfiguration buildImageConfiguration = imageConfiguration.getBuildConfiguration(); String outputDir = prepareAbsoluteOutputDirPath(EMPTY_STRING, project, outputDirectory).getAbsolutePath(); @@ -142,15 +170,17 @@ public static void jibPush(ImageConfiguration imageConfiguration, MavenProject p final String targetImage = new ImageName(imageConfiguration.getName()).getFullName(); pushImage(baseImage, targetImage, pushCredential, log); } else { - tags.stream().filter(Objects::nonNull).forEach(tag -> { + for (String tag : tags.stream().filter(Objects::nonNull).collect(Collectors.toList())) { final String targetImage = new ImageName(imageConfiguration.getName(), tag).getFullName(); pushImage(baseImage, targetImage, pushCredential, log); - }); + } } } catch (InvalidImageReferenceException | IllegalStateException e) { log.error("Exception occurred while pushing the image: %s", imageConfiguration.getName()); throw new MojoExecutionException(e.getMessage(), e); - + } catch (InterruptedException ex) { + log.error("Thread interrupted", ex); + Thread.currentThread().interrupt(); } } @@ -161,7 +191,10 @@ public static void jibPush(ImageConfiguration imageConfiguration, MavenProject p * @param credential * @param logger */ - private static void pushImage(TarImage baseImage, String targetImageName, Credential credential, Logger logger) { + private static void pushImage(TarImage baseImage, String targetImageName, Credential credential, Logger logger) + throws InterruptedException { + + final ExecutorService jibBuildExecutor = Executors.newCachedThreadPool(); try { RegistryImage targetImage = RegistryImage.named(targetImageName); if (credential!= null && !credential.getUsername().isEmpty() && !credential.getPassword().isEmpty()) { @@ -169,12 +202,20 @@ private static void pushImage(TarImage baseImage, String targetImageName, Creden } Jib.from(baseImage).containerize(Containerizer.to(targetImage) - .addEventHandler(LogEvent.class, log(logger)) - .addEventHandler(TimerEvent.class, new TimerEventHandler(logger::debug)) - .addEventHandler(ProgressEvent.class, new ProgressEventHandler(logUpdate(logger)))); - } catch (RegistryException | CacheDirectoryCreationException | InvalidImageReferenceException | IOException | ExecutionException | InterruptedException e) { - logger.error("Exception occured while pushing the image: %s", targetImageName); + .setExecutorService(jibBuildExecutor) + .addEventHandler(LogEvent.class, log(logger)) + .addEventHandler(TimerEvent.class, new TimerEventHandler(logger::debug)) + .addEventHandler(ProgressEvent.class, new ProgressEventHandler(logUpdate()))); + logUpdateFinished(); + } catch (RegistryException | CacheDirectoryCreationException | InvalidImageReferenceException | IOException | ExecutionException e) { + logger.error("Exception occurred while pushing the image: %s", targetImageName); throw new IllegalStateException(e.getMessage(), e); + } catch (InterruptedException ex) { + logger.error("Thread interrupted", ex); + throw ex; + } finally { + jibBuildExecutor.shutdown(); + jibBuildExecutor.awaitTermination(JIB_EXECUTOR_SHUTDOWN_TIMEOUT_SECONDS, TimeUnit.SECONDS); } } @@ -194,24 +235,29 @@ private static Credential getRegistryCredentials(String registry, RegistryServic } private static Consumer log(Logger logger) { - return logEvent -> ((Function>)(le -> { - switch(le.getLevel()) { - case ERROR: - return logger::error; - case WARN: - return logger::warn; - case INFO: - return logger::info; - default: - return logger::debug; + return le -> { + if (le.getLevel() != LogEvent.Level.DEBUG || logger.isVerboseEnabled() || logger.isDebugEnabled()) { + System.out.println(ansi().cursorUpLine(1).eraseLine().a("JIB> ") + .a(StringUtils.rightPad(le.getMessage(), 120)).a("\n")); + } + }; + } + + private static Consumer logUpdate() { + return update -> { + final List progressDisplay = + ProgressDisplayGenerator.generateProgressDisplay(update.getProgress(), update.getUnfinishedLeafTasks()); + if (progressDisplay.size() > 2 && progressDisplay.stream().allMatch(Objects::nonNull)) { + final String progressBar = progressDisplay.get(1); + final String task = progressDisplay.get(2); + System.out.println(ansi().cursorUpLine(1).eraseLine().a("JIB> ").a(progressBar).a(" ").a(task)); } - })).apply(logEvent).accept(logEvent.getMessage()); + }; } - private static Consumer logUpdate(Logger logger) { - return update -> - ProgressDisplayGenerator.generateProgressDisplay(update.getProgress(), update.getUnfinishedLeafTasks()) - .forEach(logger::info); + private static void logUpdateFinished() { + System.out.println(ansi().cursorUpLine(1).eraseLine().a("JIB> ") + .a(StringUtils.rightPad("[==============================] 100.0% complete", 120))); } static String getBaseImage(ImageConfiguration imageConfiguration) { diff --git a/samples/spring-boot/pom.xml b/samples/spring-boot/pom.xml index d02f714ab6..0e21d5f08c 100644 --- a/samples/spring-boot/pom.xml +++ b/samples/spring-boot/pom.xml @@ -23,7 +23,7 @@ fabric8-maven-sample-spring-boot io.fabric8 - 4.4-SNAPSHOT + 4.5-SNAPSHOT jar @@ -89,7 +89,7 @@ io.fabric8 fabric8-maven-plugin - 4.4-SNAPSHOT + ${project.version} @@ -146,7 +146,7 @@ io.fabric8 fabric8-maven-plugin - 4.4-SNAPSHOT + ${project.version} true