Skip to content

Commit

Permalink
fix: refreshing tree upon config change or kubeconfig removal (#595) (#…
Browse files Browse the repository at this point in the history
…610)

* fix: refreshing tree upon config change or kubeconfig removal (#595)

Signed-off-by: Andre Dietisheim <[email protected]>

* display default-/first namespace if current doesnt exist

Signed-off-by: Andre Dietisheim <[email protected]>

* correct type of parent to CreateComponentLinkNode

Signed-off-by: Andre Dietisheim <[email protected]>

* fix: dont 'fatal IDE error' when cluster is not reachable (#621)

Signed-off-by: Andre Dietisheim <[email protected]>

---------

Signed-off-by: Andre Dietisheim <[email protected]>
  • Loading branch information
adietish authored Nov 24, 2023
1 parent f9de414 commit d9e585b
Show file tree
Hide file tree
Showing 31 changed files with 438 additions and 348 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ intellij {
'com.intellij.css',
'yaml',
'com.redhat.devtools.intellij.telemetry:1.0.0.44',
'com.redhat.devtools.intellij.kubernetes:1.2.0.271'
'com.redhat.devtools.intellij.kubernetes:1.2.1.277'
]
updateSinceUntilBuild = false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@
public class ToolFactoryTest extends BasePlatformTestCase {

public void testGetOdo() throws ExecutionException, InterruptedException {
Odo odo = ToolFactory.getInstance().getOdo(getProject()).get();
Odo odo = ToolFactory.getInstance().createOdo(getProject()).get();
assertNotNull(odo);
}

public void testGetHelm() throws ExecutionException, InterruptedException {
Helm helm = ToolFactory.getInstance().getHelm(getProject()).get();
Helm helm = ToolFactory.getInstance().createHelm(getProject()).get();
assertNotNull(helm);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ public abstract class HelmCliTest extends BasePlatformTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
Odo odo = ToolFactory.getInstance().getOdo(getProject()).get();
Odo odo = ToolFactory.getInstance().createOdo(getProject()).get();
OdoCluster.INSTANCE.login(odo);
this.helm = ToolFactory.getInstance().getHelm(getProject()).get();
this.helm = ToolFactory.getInstance().createHelm(getProject()).get();
Charts.addRepository(Charts.REPOSITORY_STABLE, helm);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ public abstract class OdoCliTest extends BasePlatformTestCase {
protected void setUp() throws Exception {
super.setUp();
previousTestDialog = MessagesHelper.setTestDialog(TestDialog.OK);
odo = ToolFactory.getInstance().getOdo(getProject()).get();
odo = ToolFactory.getInstance().createOdo(getProject()).get();
if (odo.listDevfileRegistries().stream().noneMatch(c -> c.getName().equals(REGISTRY_NAME)))
odo.createDevfileRegistry(REGISTRY_NAME, REGISTRY_URL, null);

if (CLUSTER_URL != null && !odo.getMasterUrl().toString().startsWith(CLUSTER_URL)) {
odo.login(CLUSTER_URL, CLUSTER_USER, CLUSTER_PASSWORD.toCharArray(), null);
odo = ToolFactory.getInstance().getOdo(getProject()).get();
odo = ToolFactory.getInstance().createOdo(getProject()).get();
}
}

Expand All @@ -80,9 +80,7 @@ protected void tearDown() throws Exception {

protected void createProject(String project) throws IOException, ExecutionException, InterruptedException {
odo.createProject(project);
// need to refresh kubernetes client with the correct namespace
ToolFactory.getInstance().resetOdo();
odo = ToolFactory.getInstance().getOdo(getProject()).get();
odo = ToolFactory.getInstance().createOdo(getProject()).get();
}

protected void createComponent(String project, String component, ComponentFeature feature) throws IOException, ExecutionException, InterruptedException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@
******************************************************************************/
package org.jboss.tools.intellij.openshift.actions;

import com.intellij.ide.util.treeView.NodeDescriptor;
import org.jboss.tools.intellij.openshift.tree.application.ApplicationsRootNode;
import org.jboss.tools.intellij.openshift.tree.application.ComponentNode;
import org.jboss.tools.intellij.openshift.tree.application.ParentableNode;
import org.jboss.tools.intellij.openshift.tree.application.ProcessingNode;
import org.jboss.tools.intellij.openshift.tree.application.StructureAwareNode;

import javax.swing.tree.DefaultMutableTreeNode;

public class NodeUtils {

private NodeUtils() {
Expand Down Expand Up @@ -55,4 +60,23 @@ public static void fireModified(StructureAwareNode node) {
public static void fireRemoved(StructureAwareNode node) {
node.getStructure().fireRemoved(node);
}

public static ApplicationsRootNode getRoot(Object selected) {
ProcessingNode node = getElement(selected);
if (!(node instanceof ParentableNode<?>)) {
return null;
}
return ((ParentableNode<?>) node).getRoot();
}

public static <T> T getElement(Object selected) {
if (selected instanceof DefaultMutableTreeNode) {
selected = ((DefaultMutableTreeNode)selected).getUserObject();
}
if (selected instanceof NodeDescriptor) {
selected = ((NodeDescriptor)selected).getElement();
}
return (T) selected;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,37 +10,47 @@
******************************************************************************/
package org.jboss.tools.intellij.openshift.actions.cluster;

import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.progress.ProgressIndicator;
import com.redhat.devtools.intellij.common.actions.StructureTreeAction;
import org.jboss.tools.intellij.openshift.actions.NodeUtils;
import org.jboss.tools.intellij.openshift.telemetry.TelemetryService;
import org.jboss.tools.intellij.openshift.tree.application.ApplicationsRootNode;
import org.jboss.tools.intellij.openshift.tree.application.ProcessingNode;
import org.jboss.tools.intellij.openshift.tree.application.ParentableNode;

import javax.swing.tree.TreePath;

import static org.jboss.tools.intellij.openshift.actions.ActionUtils.runWithProgress;
import static org.jboss.tools.intellij.openshift.actions.NodeUtils.clearProcessing;
import static org.jboss.tools.intellij.openshift.actions.NodeUtils.setProcessing;
import static org.jboss.tools.intellij.openshift.telemetry.TelemetryService.PREFIX_ACTION;

public class RefreshAction extends StructureTreeAction {
public RefreshAction() {
super(ApplicationsRootNode.class);
}

public static void execute(ParentableNode<?> node) {
RefreshAction action = (RefreshAction) ActionManager.getInstance().getAction(RefreshAction.class.getName());
action.doActionPerformed(node.getRoot());
}

@Override
public void actionPerformed(AnActionEvent anActionEvent, TreePath path, Object selected) {
doActionPerformed(NodeUtils.getRoot(selected));
}

public void doActionPerformed(ApplicationsRootNode root) {
if (root == null) {
return;
}
runWithProgress((ProgressIndicator progress) -> {
ProcessingNode node = getElement(selected);
setProcessing("Refreshing ", node);
root.refresh();
TelemetryService.instance().getBuilder()
.action(PREFIX_ACTION + "refresh cluster")
.success()
.send();
clearProcessing(node);
},
"Refresh...",
getEventProject(anActionEvent));
"Refreshing...",
root.getProject());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
import com.redhat.devtools.intellij.common.utils.UIHelper;
import org.jboss.tools.intellij.openshift.actions.NodeUtils;
import org.jboss.tools.intellij.openshift.actions.OdoAction;
import org.jboss.tools.intellij.openshift.tree.application.BaseNode;
import org.jboss.tools.intellij.openshift.tree.application.ComponentNode;
import org.jboss.tools.intellij.openshift.tree.application.NamespaceNode;
import org.jboss.tools.intellij.openshift.tree.application.ParentableNode;
import org.jboss.tools.intellij.openshift.ui.binding.BindingDetailDialog;
import org.jboss.tools.intellij.openshift.utils.odo.Binding;
import org.jboss.tools.intellij.openshift.utils.odo.Component;
Expand Down Expand Up @@ -99,7 +99,7 @@ private static String getServiceName(List<Service> services) {
null));
}

private void linkService(Service service, Component component, ParentableNode<?> namespaceNode, Odo odo, Project project) throws IOException {
private void linkService(Service service, Component component, BaseNode<?> namespaceNode, Odo odo, Project project) throws IOException {
Notification notification = notify("Linking component to service " + service.getName());
String target = service.getName() + '/' + service.getKind() + "." + service.getApiVersion();
Binding binding = odo.link(namespaceNode.getName(), component.getPath(), component.getName(), target);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ public List<String> getNamespaces() throws IOException {
}

@Override
public String getNamespace() throws IOException {
return delegate.getNamespace();
public String getCurrentNamespace() throws IOException {
return delegate.getCurrentNamespace();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +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 io.fabric8.kubernetes.api.model.NamedContext;
import io.fabric8.kubernetes.client.internal.KubeConfigUtils;
import org.apache.commons.codec.binary.StringUtils;
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;
Expand All @@ -44,10 +41,12 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;

import static org.jboss.tools.intellij.openshift.Constants.GROUP_DISPLAY_ID;

public class ApplicationsRootNode implements ModuleListener, ConfigWatcher.Listener, StructureAwareNode, ProcessingNode {
public class ApplicationsRootNode
implements ModuleListener, ConfigWatcher.Listener, ProcessingNode, StructureAwareNode, ParentableNode<ApplicationsRootNode> {

private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationsRootNode.class);
private final Project project;
Expand All @@ -65,7 +64,7 @@ public ApplicationsRootNode(Project project, ApplicationsTreeStructure structure
this.project = project;
this.structure = structure;
initConfigWatcher();
config = loadConfig();
this.config = loadConfig();
registerProjectListener(project);
}

Expand All @@ -77,31 +76,34 @@ public void setLogged(boolean logged) {
this.logged = logged;
}

public CompletableFuture<Odo> getOdo() {
return getOdo(true);
}

public CompletableFuture<Odo> getOdo(boolean notify) {
private CompletableFuture<Odo> getOdo(BiConsumer<Odo, Throwable> whenComplete) {
if (odoFuture == null) {
this.odoFuture = ToolFactory.getInstance()
.getOdo(project)
.createOdo(project)
.thenApply(odo -> (Odo) new ApplicationRootNodeOdo(odo, this))
.whenComplete((odo, err) -> {
loadProjectModel(odo, project);
if (notify) {
structure.fireModified(this);
}
});
.whenComplete((odo, err) -> loadProjectModel(odo, project))
.whenComplete(whenComplete);
}
return odoFuture;
}

public CompletableFuture<Odo> getOdo() {
return getOdo((odo, err) -> structure.fireModified(this));
}

public void resetOdo() {
this.odoFuture = null;
}

public CompletableFuture<Helm> getHelm(boolean notify) {
if (helmFuture == null) {
this.helmFuture = ToolFactory.getInstance()
.getHelm(project)
.whenComplete((odo, err) ->
structure.fireModified(this)
.createHelm(project)
.whenComplete((odo, err) -> {
if (notify) {
structure.fireModified(this);
}
}
);
}
return helmFuture;
Expand Down Expand Up @@ -180,22 +182,24 @@ 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") ||
message.contains("connect: no route to host"));
}

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) {
Expand All @@ -222,46 +226,15 @@ protected void registerProjectListener(Project project) {

@Override
public void onUpdate(ConfigWatcher source, Config config) {
if (hasContextChanged(config, this.config)) {
if (!ConfigHelper.areEqual(config, this.config)) {
this.config = config;
refresh();
}
this.config = config;
}

private boolean hasContextChanged(Config newConfig, Config currentConfig) {
NamedContext currentContext = KubeConfigUtils.getCurrentContext(currentConfig);
NamedContext newContext = KubeConfigUtils.getCurrentContext(newConfig);
return hasServerChanged(newContext, currentContext)
|| hasNewToken(newContext, newConfig, currentContext, currentConfig);
}

private boolean hasServerChanged(NamedContext newContext, NamedContext currentContext) {
return newContext == null
|| currentContext == null
|| !StringUtils.equals(currentContext.getContext().getCluster(), newContext.getContext().getCluster())
|| !StringUtils.equals(currentContext.getContext().getUser(), newContext.getContext().getUser())
|| !StringUtils.equals(currentContext.getContext().getNamespace(), newContext.getContext().getNamespace());
}

private boolean hasNewToken(NamedContext newContext, Config newConfig, NamedContext currentContext, Config currentConfig) {
if (newContext == null) {
return false;
}
if (currentContext == null) {
return true;
}
String newToken = KubeConfigUtils.getUserToken(newConfig, newContext.getContext());
if (newToken == null) {
// logout, do not refresh, LogoutAction already refreshes
return false;
}
String currentToken = KubeConfigUtils.getUserToken(currentConfig, currentContext.getContext());
return !StringUtils.equals(newToken, currentToken);
}

public void refresh() {
ToolFactory.getInstance().resetOdo();
getOdo().thenAccept(odo -> structure.fireModified(this));
public synchronized void refresh() {
resetOdo();
getOdo((odo, err) -> structure.fireModified(ApplicationsRootNode.this));
}

@Override
Expand All @@ -270,28 +243,37 @@ public ApplicationsTreeStructure getStructure() {
}

@Override
public void startProcessing(String message) {
public synchronized void startProcessing(String message) {
this.processingNode.startProcessing(message);
}

@Override
public void stopProcessing() {
public synchronized void stopProcessing() {
this.processingNode.stopProcessing();
}

@Override
public boolean isProcessing() {
public synchronized boolean isProcessing() {
return processingNode.isProcessing();
}

@Override
public boolean isProcessingStopped() {
public synchronized boolean isProcessingStopped() {
return processingNode.isProcessingStopped();
}

@Override
public String getProcessingMessage() {
public String getMessage() {
return processingNode.getMessage();
}

@Override
public ApplicationsRootNode getParent() {
return this;
}

@Override
public ApplicationsRootNode getRoot() {
return this;
}
}
Loading

0 comments on commit d9e585b

Please sign in to comment.