From c09f1ffddd278497dc7f1a4ce54413263c15912d Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Mon, 27 Jul 2020 13:47:35 +1000 Subject: [PATCH 1/2] If kube generation fails in dev mode don't fail the build Remote-dev mode does not have a project present. We really need something better so there is no exception, but this should probably be non-fatal in dev mode anyway. Fixes #10975 --- .../deployment/KubernetesProcessor.java | 238 +++++++++--------- 1 file changed, 123 insertions(+), 115 deletions(-) diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesProcessor.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesProcessor.java index bfd87a1a28977..c3ebace490e54 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesProcessor.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/KubernetesProcessor.java @@ -302,130 +302,138 @@ public void build(ApplicationInfoBuildItem applicationInfo, Path artifactPath = outputTarget.getOutputDirectory().resolve( String.format(OUTPUT_ARTIFACT_FORMAT, outputTarget.getBaseName(), packageConfig.runnerSuffix)); - final Map generatedResourcesMap; - // by passing false to SimpleFileWriter, we ensure that no files are actually written during this phase - Project project = createProject(applicationInfo, artifactPath); - final SessionWriter sessionWriter = new SimpleFileWriter(project, false); - final SessionReader sessionReader = new SimpleFileReader( - project.getRoot().resolve("src").resolve("main").resolve("kubernetes"), kubernetesDeploymentTargets - .getEntriesSortedByPriority().stream() - .map(DeploymentTargetEntry::getName).collect(Collectors.toSet())); - sessionWriter.setProject(project); - - if (launchMode.getLaunchMode() != LaunchMode.NORMAL) { - // needed for a fresh run - Session.clearSession(); - } - - final Session session = Session.getSession(new NoopLogger()); - - session.setWriter(sessionWriter); - session.setReader(sessionReader); - - session.feed(Maps.fromProperties(config)); - - //Apply configuration - applyGlobalConfig(session, kubernetesConfig); - - ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC); - - boolean needToForceUpdateImagePullPolicy = needToForceUpdateImagePullPolicy(deploymentTargets, containerImage, - capabilities); - applyConfig(session, project, KUBERNETES, getResourceName(kubernetesConfig, applicationInfo), kubernetesConfig, - now, determineImagePullPolicy(kubernetesConfig, needToForceUpdateImagePullPolicy)); - applyConfig(session, project, MINIKUBE, getResourceName(kubernetesConfig, applicationInfo), kubernetesConfig, - now, ImagePullPolicy.IfNotPresent); - applyConfig(session, project, OPENSHIFT, getResourceName(openshiftConfig, applicationInfo), openshiftConfig, now, - determineImagePullPolicy(openshiftConfig, needToForceUpdateImagePullPolicy)); - applyConfig(session, project, KNATIVE, getResourceName(knativeConfig, applicationInfo), knativeConfig, now, - determineImagePullPolicy(knativeConfig, needToForceUpdateImagePullPolicy)); - - applyKnativeConfig(session, project, getResourceName(knativeConfig, applicationInfo), knativeConfig); - //When S2i is disabled we need to pass that information to dekorate. - //Also we need to make sure that the alternatives (instances of ImageConfiguration) - //are properly configured. - if (!capabilities.isCapabilityPresent(Capabilities.CONTAINER_IMAGE_S2I)) { - session.configurators().add(new Configurator>() { - @Override - public void visit(ImageConfigurationFluent image) { - containerImage.ifPresent(i -> { - String group = ImageUtil.getRepository(i.getImage()).split("/")[0]; - image.withGroup(group); - i.getRegistry().ifPresent(r -> { - image.withRegistry(r); - }); - }); - } - }); - - //JAVA_APP_JAR value is not compatible with our Dockerfiles, so its causing problems - session.resources().decorate(OPENSHIFT, new RemoveEnvVarDecorator("JAVA_APP_JAR")); - session.configurators().add(new Configurator>() { - @Override - public void visit(S2iBuildConfigFluent s2i) { - s2i.withEnabled(false); - } - }); - } - //apply build item configurations to the dekorate session. - applyBuildItems(session, - applicationInfo, - kubernetesConfig, - openshiftConfig, - knativeConfig, - deploymentTargets, - kubernetesAnnotations, - kubernetesLabels, - kubernetesEnvs, - kubernetesRoles, - kubernetesPorts, - baseImage, - containerImage, - command, - kubernetesHealthLivenessPath, - kubernetesHealthReadinessPath); + try { + final Map generatedResourcesMap; + // by passing false to SimpleFileWriter, we ensure that no files are actually written during this phase + Project project = createProject(applicationInfo, artifactPath); + final SessionWriter sessionWriter = new SimpleFileWriter(project, false); + final SessionReader sessionReader = new SimpleFileReader( + project.getRoot().resolve("src").resolve("main").resolve("kubernetes"), kubernetesDeploymentTargets + .getEntriesSortedByPriority().stream() + .map(DeploymentTargetEntry::getName).collect(Collectors.toSet())); + sessionWriter.setProject(project); + + if (launchMode.getLaunchMode() != LaunchMode.NORMAL) { + // needed for a fresh run + Session.clearSession(); + } - // write the generated resources to the filesystem - generatedResourcesMap = session.close(); + final Session session = Session.getSession(new NoopLogger()); + + session.setWriter(sessionWriter); + session.setReader(sessionReader); + + session.feed(Maps.fromProperties(config)); + + //Apply configuration + applyGlobalConfig(session, kubernetesConfig); + + ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC); + + boolean needToForceUpdateImagePullPolicy = needToForceUpdateImagePullPolicy(deploymentTargets, containerImage, + capabilities); + applyConfig(session, project, KUBERNETES, getResourceName(kubernetesConfig, applicationInfo), kubernetesConfig, + now, determineImagePullPolicy(kubernetesConfig, needToForceUpdateImagePullPolicy)); + applyConfig(session, project, MINIKUBE, getResourceName(kubernetesConfig, applicationInfo), kubernetesConfig, + now, ImagePullPolicy.IfNotPresent); + applyConfig(session, project, OPENSHIFT, getResourceName(openshiftConfig, applicationInfo), openshiftConfig, now, + determineImagePullPolicy(openshiftConfig, needToForceUpdateImagePullPolicy)); + applyConfig(session, project, KNATIVE, getResourceName(knativeConfig, applicationInfo), knativeConfig, now, + determineImagePullPolicy(knativeConfig, needToForceUpdateImagePullPolicy)); + + applyKnativeConfig(session, project, getResourceName(knativeConfig, applicationInfo), knativeConfig); + //When S2i is disabled we need to pass that information to dekorate. + //Also we need to make sure that the alternatives (instances of ImageConfiguration) + //are properly configured. + if (!capabilities.isCapabilityPresent(Capabilities.CONTAINER_IMAGE_S2I)) { + session.configurators().add(new Configurator>() { + @Override + public void visit(ImageConfigurationFluent image) { + containerImage.ifPresent(i -> { + String group = ImageUtil.getRepository(i.getImage()).split("/")[0]; + image.withGroup(group); + i.getRegistry().ifPresent(r -> { + image.withRegistry(r); + }); + }); + } + }); - List generatedFileNames = new ArrayList<>(generatedResourcesMap.size()); - for (Map.Entry resourceEntry : generatedResourcesMap.entrySet()) { - Path path = Paths.get(resourceEntry.getKey()); - //We need to ignore the config yml - if (!path.toFile().getParentFile().getName().equals("dekorate")) { - continue; + //JAVA_APP_JAR value is not compatible with our Dockerfiles, so its causing problems + session.resources().decorate(OPENSHIFT, new RemoveEnvVarDecorator("JAVA_APP_JAR")); + session.configurators().add(new Configurator>() { + @Override + public void visit(S2iBuildConfigFluent s2i) { + s2i.withEnabled(false); + } + }); } - String fileName = path.toFile().getName(); - Path targetPath = outputTarget.getOutputDirectory().resolve(KUBERNETES).resolve(fileName); - String relativePath = targetPath.toAbsolutePath().toString().replace(root.toAbsolutePath().toString(), ""); - - resourceEntry.getKey().replace(root.toAbsolutePath().toString(), KUBERNETES); - if (fileName.endsWith(".yml") || fileName.endsWith(".json")) { - String target = fileName.substring(0, fileName.lastIndexOf(".")); - if (!deploymentTargets.contains(target)) { + //apply build item configurations to the dekorate session. + applyBuildItems(session, + applicationInfo, + kubernetesConfig, + openshiftConfig, + knativeConfig, + deploymentTargets, + kubernetesAnnotations, + kubernetesLabels, + kubernetesEnvs, + kubernetesRoles, + kubernetesPorts, + baseImage, + containerImage, + command, + kubernetesHealthLivenessPath, + kubernetesHealthReadinessPath); + + // write the generated resources to the filesystem + generatedResourcesMap = session.close(); + + List generatedFileNames = new ArrayList<>(generatedResourcesMap.size()); + for (Map.Entry resourceEntry : generatedResourcesMap.entrySet()) { + Path path = Paths.get(resourceEntry.getKey()); + //We need to ignore the config yml + if (!path.toFile().getParentFile().getName().equals("dekorate")) { continue; } - } + String fileName = path.toFile().getName(); + Path targetPath = outputTarget.getOutputDirectory().resolve(KUBERNETES).resolve(fileName); + String relativePath = targetPath.toAbsolutePath().toString().replace(root.toAbsolutePath().toString(), ""); + + resourceEntry.getKey().replace(root.toAbsolutePath().toString(), KUBERNETES); + if (fileName.endsWith(".yml") || fileName.endsWith(".json")) { + String target = fileName.substring(0, fileName.lastIndexOf(".")); + if (!deploymentTargets.contains(target)) { + continue; + } + } - generatedFileNames.add(fileName); - generatedResourceProducer.produce( - new GeneratedFileSystemResourceBuildItem( - // we need to make sure we are only passing the relative path to the build item - relativePath, - resourceEntry.getValue().getBytes(StandardCharsets.UTF_8))); - } + generatedFileNames.add(fileName); + generatedResourceProducer.produce( + new GeneratedFileSystemResourceBuildItem( + // we need to make sure we are only passing the relative path to the build item + relativePath, + resourceEntry.getValue().getBytes(StandardCharsets.UTF_8))); + } - if (!generatedFileNames.isEmpty()) { - log.infof("Generated the Kubernetes manifests: '%s' in '%s'", String.join(",", generatedFileNames), - outputTarget.getOutputDirectory() + File.separator + KUBERNETES); - } + if (!generatedFileNames.isEmpty()) { + log.infof("Generated the Kubernetes manifests: '%s' in '%s'", String.join(",", generatedFileNames), + outputTarget.getOutputDirectory() + File.separator + KUBERNETES); + } - try { - if (root != null && root.toFile().exists()) { - FileUtil.deleteDirectory(root); + try { + if (root != null && root.toFile().exists()) { + FileUtil.deleteDirectory(root); + } + } catch (IOException e) { + log.debug("Unable to delete temporary directory " + root, e); } - } catch (IOException e) { - log.debug("Unable to delete temporary directory " + root, e); + } catch (Exception e) { + if (launchMode.getLaunchMode() == LaunchMode.NORMAL) { + throw e; + } + + log.warn("Failed to generate Kubernetes resources", e); } } From 43da52e591d66e1d575759a141788e553848bcc9 Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Mon, 27 Jul 2020 13:49:46 +1000 Subject: [PATCH 2/2] Only register pre-scan step once This was being registered on overy restart, which was causing problems Fixes #10969 --- .../http/runtime/devmode/RemoteSyncHandler.java | 17 +++++------------ .../devmode/VertxHttpHotReplacementSetup.java | 6 ++++++ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/devmode/RemoteSyncHandler.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/devmode/RemoteSyncHandler.java index c60bb3e020abb..28db2f20e4f6a 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/devmode/RemoteSyncHandler.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/devmode/RemoteSyncHandler.java @@ -43,25 +43,18 @@ public class RemoteSyncHandler implements Handler { static volatile int currentSessionCounter; static volatile long currentSessionTimeout; static volatile Throwable remoteProblem; - static boolean checkForChanges; + static volatile boolean checkForChanges; public RemoteSyncHandler(String password, Handler next, HotReplacementContext hotReplacementContext) { this.password = password; this.next = next; this.hotReplacementContext = hotReplacementContext; - hotReplacementContext.addPreScanStep(new Runnable() { - @Override - public void run() { - if (currentSession == null) { - return; - } - doPreScan(); - } - }); } - private void doPreScan() { - + public static void doPreScan() { + if (currentSession == null) { + return; + } synchronized (RemoteSyncHandler.class) { checkForChanges = true; //if there is a current dev request this will unblock it diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/devmode/VertxHttpHotReplacementSetup.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/devmode/VertxHttpHotReplacementSetup.java index e1f5ff9757b44..ebd44fafeaae5 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/devmode/VertxHttpHotReplacementSetup.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/devmode/VertxHttpHotReplacementSetup.java @@ -23,6 +23,12 @@ public class VertxHttpHotReplacementSetup implements HotReplacementSetup { public void setupHotDeployment(HotReplacementContext context) { this.hotReplacementContext = context; VertxHttpRecorder.setHotReplacement(this::handleHotReplacementRequest, hotReplacementContext); + hotReplacementContext.addPreScanStep(new Runnable() { + @Override + public void run() { + RemoteSyncHandler.doPreScan(); + } + }); } @Override