From 931ce1a95d488a38720ad564904ae75f555a4442 Mon Sep 17 00:00:00 2001 From: Andre Dietisheim Date: Thu, 23 Nov 2023 20:42:37 +0100 Subject: [PATCH] fix: dont 'fatal IDE error' when cluster is not reachable (#621) Signed-off-by: Andre Dietisheim --- .../application/ApplicationsRootNode.java | 20 +-- .../ApplicationsTreeStructure.java | 122 +++++++++++------- .../openshift/utils/ExceptionUtils.java | 43 ++++++ 3 files changed, 126 insertions(+), 59 deletions(-) create mode 100644 src/main/java/org/jboss/tools/intellij/openshift/utils/ExceptionUtils.java diff --git a/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationsRootNode.java b/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationsRootNode.java index 4cadcc9bb..5243ea599 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationsRootNode.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationsRootNode.java @@ -25,7 +25,6 @@ import com.redhat.devtools.intellij.common.utils.ConfigWatcher; import com.redhat.devtools.intellij.common.utils.ExecHelper; import io.fabric8.kubernetes.api.model.Config; -import org.jboss.tools.intellij.openshift.ui.SwingUtils; import org.jboss.tools.intellij.openshift.utils.ProjectUtils; import org.jboss.tools.intellij.openshift.utils.ToolFactory; import org.jboss.tools.intellij.openshift.utils.helm.Helm; @@ -82,7 +81,9 @@ private CompletableFuture getOdo(BiConsumer whenComplete) { this.odoFuture = ToolFactory.getInstance() .createOdo(project) .thenApply(odo -> (Odo) new ApplicationRootNodeOdo(odo, this)) - .whenComplete((odo, err) -> loadProjectModel(odo, project)) + .whenComplete((odo, err) -> { + loadProjectModel(odo, project); + }) .whenComplete(whenComplete); } return odoFuture; @@ -183,14 +184,14 @@ private void addContext(Odo odo, VirtualFile modulePathFile) { ); } catch (IOException ex) { //filter out some common exception when no logged or no authorizations - if (doNotLogFromMessage(ex.getMessage())) { - LOGGER.error(ex.getLocalizedMessage(), ex); + if (shouldLogMessage(ex.getMessage())) { + LOGGER.warn(ex.getLocalizedMessage(), ex); } } } } - private static boolean doNotLogFromMessage(String message) { + private static boolean shouldLogMessage(String message) { return !(message.contains("Unauthorized") || message.contains("unable to access the cluster: servicebindings.binding.operators.coreos.com") || message.contains("the server has asked for the client to provide credentials") || @@ -198,7 +199,9 @@ private static boolean doNotLogFromMessage(String message) { } public void addContext(String modulePath) { - addContext(getOdo().getNow(null), LocalFileSystem.getInstance().refreshAndFindFileByPath(modulePath)); + addContext( + getOdo().getNow(null), + LocalFileSystem.getInstance().refreshAndFindFileByPath(modulePath)); } private void removeContextFromSettings(String modulePath) { @@ -233,10 +236,7 @@ public void onUpdate(ConfigWatcher source, Config config) { public synchronized void refresh() { resetOdo(); - CompletableFuture - .runAsync(() -> - getOdo((odo, err) -> structure.fireModified(ApplicationsRootNode.this)), - SwingUtils.EXECUTOR_BACKGROUND); + getOdo((odo, err) -> structure.fireModified(ApplicationsRootNode.this)); } @Override diff --git a/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationsTreeStructure.java b/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationsTreeStructure.java index 9680bbb74..75ce15bbe 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationsTreeStructure.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationsTreeStructure.java @@ -20,6 +20,7 @@ import com.redhat.devtools.intellij.common.tree.MutableModelSupport; import io.fabric8.kubernetes.client.KubernetesClientException; import org.jboss.tools.intellij.openshift.Constants; +import org.jboss.tools.intellij.openshift.utils.ExceptionUtils; import org.jboss.tools.intellij.openshift.utils.helm.Helm; import org.jboss.tools.intellij.openshift.utils.odo.Odo; import org.jetbrains.annotations.NotNull; @@ -68,23 +69,24 @@ public Object getApplicationsRoot() { @NotNull @Override public Object @NotNull [] getChildElements(@NotNull Object element) { - Odo odo = root.getOdo().getNow(null); - if (odo != null) { + try { if (element == this) { - return new Object[]{getApplicationsRoot(), registries}; + return new Object[]{root, registries}; } else if (element instanceof ApplicationsRootNode) { - return getCurrentNamespace((ApplicationsRootNode) element, odo); + return getCurrentNamespace((ApplicationsRootNode) element); } else if (element instanceof NamespaceNode) { - return createNamespaceChildren((NamespaceNode) element, odo); + return createNamespaceChildren((NamespaceNode) element); } else if (element instanceof ComponentNode) { - return createComponentChildren((ComponentNode) element, odo); + return createComponentChildren((ComponentNode) element); } else if (element instanceof DevfileRegistriesNode) { - return getRegistries(root, odo); + return getRegistries(root); } else if (element instanceof DevfileRegistryNode) { - return getRegistryComponentTypes((DevfileRegistryNode) element, odo); + return getRegistryComponentTypes((DevfileRegistryNode) element); } else if (element instanceof DevfileRegistryComponentTypeNode) { - return getRegistryComponentTypeStarters((DevfileRegistryComponentTypeNode) element, odo); + return getRegistryComponentTypeStarters((DevfileRegistryComponentTypeNode) element); } + } catch (Exception e) { + return new Object[]{new MessageNode<>(root, root, ExceptionUtils.getMessage(e))}; } return new Object[0]; } @@ -103,9 +105,13 @@ public Object getApplicationsRoot() { } @NotNull - private Object[] createComponentChildren(ComponentNode element, @NotNull Odo odo) { - List urls = getURLs(element); - List bindings = getBindings(element, odo); + private Object[] createComponentChildren(ComponentNode componentNode) { + Odo odo = root.getOdo().getNow(null); + if (odo == null) { + return new Object[] { new MessageNode<>(root, componentNode, "Could not get components") }; + } + List urls = getURLs(componentNode); + List bindings = getBindings(componentNode, odo); return Stream.of(urls, bindings) .filter(item -> !item.isEmpty()) .flatMap(Collection::stream) @@ -113,21 +119,24 @@ private Object[] createComponentChildren(ComponentNode element, @NotNull Odo odo } @NotNull - private Object[] createNamespaceChildren(@NotNull NamespaceNode namespaceNode, @NotNull Odo odo) { + private Object[] createNamespaceChildren(@NotNull NamespaceNode namespaceNode) { List nodes = new ArrayList<>(); - nodes.addAll(getComponents(namespaceNode, odo)); - nodes.addAll(getServices(namespaceNode, odo)); + nodes.addAll(getComponents(namespaceNode)); + nodes.addAll(getServices(namespaceNode)); - Helm helm = namespaceNode.getRoot().getHelm(true).getNow(null); - nodes.addAll(getHelmReleases(namespaceNode, helm)); + nodes.addAll(getHelmReleases(namespaceNode)); return nodes.toArray(); } - private Object[] getCurrentNamespace(ApplicationsRootNode element, @NotNull Odo odo) { + private Object[] getCurrentNamespace(ApplicationsRootNode element) { List namespaces = new ArrayList<>(); try { + Odo odo = root.getOdo().getNow(null); + if (odo == null) { + return new Object[] { new MessageNode<>(element, element, "Could not get current namespace") }; + } String ns = odo.getCurrentNamespace(); if (ns != null) { namespaces.add(new NamespaceNode(element, ns)); @@ -142,58 +151,61 @@ private Object[] getCurrentNamespace(ApplicationsRootNode element, @NotNull Odo return namespaces.toArray(); } - private static MessageNode createErrorNode(ApplicationsRootNode element, Exception e) { + private MessageNode createErrorNode(ParentableNode parent, Exception e) { if (e instanceof KubernetesClientException) { KubernetesClientException kce = (KubernetesClientException) e; if (kce.getCode() == 401) { - return new MessageNode<>(element, element, LOGIN); + return new MessageNode<>(root, parent, LOGIN); } else if (kce.getCause() instanceof NoRouteToHostException) { - return new MessageNode<>(element, element, kce.getCause().getMessage()); + return new MessageNode<>(root, parent, kce.getCause().getMessage()); } else if (kce.getCause().getMessage().contains(Constants.DEFAULT_KUBE_URL)) { - return new MessageNode<>(element, element, LOGIN); + return new MessageNode<>(root, parent, LOGIN); } } - return new MessageNode<>(element, element, "Unable to get namespaces: " + e.getMessage()); + return new MessageNode<>(root, parent, "Could not get namespaces: " + ExceptionUtils.getMessage(e)); } - private List> getComponents(NamespaceNode element, Odo odo) { + private List> getComponents(NamespaceNode namespaceNode) { + Odo odo = root.getOdo().getNow(null); if (odo == null) { - return Collections.emptyList(); + return List.of(new MessageNode<>(root, namespaceNode, "Could not get components")); } List> components = new ArrayList<>(); components.addAll(load( - () -> odo.getComponents(element.getName()).stream() + () -> odo.getComponents(namespaceNode.getName()).stream() .filter(component -> !component.isManagedByHelm()) // dont display helm components - .map(component -> new ComponentNode(element, component)) + .map(component -> new ComponentNode(namespaceNode, component)) .collect(Collectors.toList()), - element, - "Failed to load components")); + namespaceNode, + "Could not get components")); if (components.isEmpty()) { - components.add(new CreateComponentLinkNode(element.getRoot(), element)); + components.add(new CreateComponentLinkNode(namespaceNode.getRoot(), namespaceNode)); } return components; } - private List> getServices(NamespaceNode element, Odo odo) { + private List> getServices(NamespaceNode namespaceNode) { + Odo odo = root.getOdo().getNow(null); if (odo == null) { - return Collections.emptyList(); + return List.of(new MessageNode<>(root, namespaceNode, "Could not get application services")); } - return load(() -> odo.getServices(element.getName()).stream() - .map(si -> new ServiceNode(element, si)) + return load(() -> odo.getServices(namespaceNode.getName()).stream() + .map(si -> new ServiceNode(namespaceNode, si)) .collect(Collectors.toList()), - element, - "Failed to load application services"); + namespaceNode, + "Could not get application services"); } - private List> getHelmReleases(NamespaceNode element, Helm helm) { + private List> getHelmReleases(NamespaceNode namespaceNode) { + Helm helm = namespaceNode.getRoot().getHelm(true).getNow(null); if (helm == null) { - return Collections.emptyList(); + return List.of(new MessageNode<>(root, namespaceNode, "Could not get chart releases")); } return load(() -> helm.list().stream() - .map(release -> new ChartReleaseNode(element, release)) + .map(release -> new ChartReleaseNode(namespaceNode, release)) .collect(Collectors.toList()), - element, - "Failed to load chart releases"); + namespaceNode, + "Could not get chart releases"); } private List> load(Callable>> callable, NamespaceNode namespace, String errorMessage) { @@ -234,7 +246,11 @@ private List getBindings(ComponentNode element, @NotNull Odo odo) { return results; } - private Object[] getRegistries(ApplicationsRootNode root, @NotNull Odo odo) { + private Object[] getRegistries(ApplicationsRootNode root) { + Odo odo = root.getOdo().getNow(null); + if (odo == null) { + return new Object[] { new MessageNode<>(root, root, "Could not get registries") }; + } List result = new ArrayList<>(); try { odo.listDevfileRegistries().forEach(registry -> @@ -246,23 +262,31 @@ private Object[] getRegistries(ApplicationsRootNode root, @NotNull Odo odo) { return result.toArray(); } - private Object[] getRegistryComponentTypes(DevfileRegistryNode element, @NotNull Odo odo) { + private Object[] getRegistryComponentTypes(DevfileRegistryNode registryNode) { + Odo odo = root.getOdo().getNow(null); + if (odo == null) { + return new Object[] { new MessageNode<>(root, registryNode, "Could not get registry component types") }; + } List result = new ArrayList<>(); try { - odo.getComponentTypes(element.getName()).forEach(type -> - result.add(new DevfileRegistryComponentTypeNode(root, element, type))); + odo.getComponentTypes(registryNode.getName()).forEach(type -> + result.add(new DevfileRegistryComponentTypeNode(root, registryNode, type))); } catch (IOException e) { LOGGER.error(e.getLocalizedMessage(), e); } return result.toArray(); } - private Object[] getRegistryComponentTypeStarters(DevfileRegistryComponentTypeNode element, @NotNull Odo odo) { + private Object[] getRegistryComponentTypeStarters(DevfileRegistryComponentTypeNode componentTypeNode) { + Odo odo = root.getOdo().getNow(null); + if (odo == null) { + return new Object[] { new MessageNode<>(root, componentTypeNode, "Could not get registry component starters") }; + } List result = new ArrayList<>(); try { - odo.getComponentTypeInfo(element.getName(), - element.getComponentType().getDevfileRegistry().getName()).getStarters().forEach(starter -> - result.add(new DevfileRegistryComponentTypeStarterNode(element.getRoot(), element, starter))); + odo.getComponentTypeInfo(componentTypeNode.getName(), + componentTypeNode.getComponentType().getDevfileRegistry().getName()).getStarters().forEach(starter -> + result.add(new DevfileRegistryComponentTypeStarterNode(componentTypeNode.getRoot(), componentTypeNode, starter))); } catch (IOException e) { LOGGER.error(e.getLocalizedMessage(), e); } diff --git a/src/main/java/org/jboss/tools/intellij/openshift/utils/ExceptionUtils.java b/src/main/java/org/jboss/tools/intellij/openshift/utils/ExceptionUtils.java new file mode 100644 index 000000000..aed31b182 --- /dev/null +++ b/src/main/java/org/jboss/tools/intellij/openshift/utils/ExceptionUtils.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2023 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package org.jboss.tools.intellij.openshift.utils; + +import java.util.concurrent.CompletionException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ExceptionUtils { + + private static final Pattern PATTERN_COMPLETION_EXCEPTION_MESSAGE = Pattern.compile( + "\"message\": \"([\\s\\S]+?)\"\\n", Pattern.MULTILINE); + + private ExceptionUtils() {} + + public static String getMessage(Exception e) { + if (e instanceof CompletionException) { + return getMessage((CompletionException) e); + } else { + return e.getMessage(); + } + } + + public static String getMessage(CompletionException e) { + if (e.getMessage() == null) { + return null; + } + Matcher matcher = PATTERN_COMPLETION_EXCEPTION_MESSAGE.matcher(e.getMessage()); + if (!matcher.find()) { + return e.getMessage(); + } + return matcher.group(1); + } +} +