From 157ad6a55e61ec65dfa85d84248b0536d5c9be1c Mon Sep 17 00:00:00 2001 From: Andre Dietisheim Date: Tue, 3 Dec 2024 18:40:03 +0100 Subject: [PATCH] fix: bump kubernetes-client to 7.0.0 (#921) Signed-off-by: Andre Dietisheim --- gradle/libs.versions.toml | 2 +- .../intellij/openshift/utils/OdoCluster.java | 9 +- .../openshift/utils/ToolFactoryTest.java | 18 +- .../utils/helm/HelmCliSearchTest.java | 32 +-- .../openshift/utils/helm/HelmCliTest.java | 16 +- .../openshift/utils/odo/OdoCliTest.java | 45 ++-- .../utils/odo/OdoKubernetesClientTest.java | 11 +- .../openshift/actions/HelmAction.java | 2 +- .../intellij/openshift/actions/OcAction.java | 17 +- .../project/ChangeActiveProjectAction.java | 6 + .../application/ApplicationsRootNode.java | 68 ++++-- .../ApplicationsTreeStructure.java | 4 +- .../tools/intellij/openshift/utils/Cli.java | 50 +--- .../openshift/utils/ClientAwareCli.java | 23 ++ .../utils/KubernetesClientFactory.java | 66 ++++++ .../intellij/openshift/utils/ToolFactory.java | 54 ++--- .../openshift/utils/helm/HelmCli.java | 7 +- .../intellij/openshift/utils/oc/OcCli.java | 22 +- .../intellij/openshift/utils/odo/OdoCli.java | 57 +++-- .../ApplicationTreeModelConfigUpdateTest.java | 218 ++++++++++-------- 20 files changed, 419 insertions(+), 308 deletions(-) create mode 100644 src/main/java/org/jboss/tools/intellij/openshift/utils/ClientAwareCli.java create mode 100644 src/main/java/org/jboss/tools/intellij/openshift/utils/KubernetesClientFactory.java diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7cc53a6b6..2a58146dc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] # libraries junit = "4.13.2" -openshift-client = "6.12.0" +openshift-client = "7.0.0" devtools-common = "1.9.7-SNAPSHOT" keycloak = "24.0.5" jsonwebtoken = "0.12.6" diff --git a/src/it/java/org/jboss/tools/intellij/openshift/utils/OdoCluster.java b/src/it/java/org/jboss/tools/intellij/openshift/utils/OdoCluster.java index cb0ff71ec..74cb3100d 100644 --- a/src/it/java/org/jboss/tools/intellij/openshift/utils/OdoCluster.java +++ b/src/it/java/org/jboss/tools/intellij/openshift/utils/OdoCluster.java @@ -10,19 +10,18 @@ ******************************************************************************/ package org.jboss.tools.intellij.openshift.utils; -import org.jboss.tools.intellij.openshift.utils.oc.Oc; - import java.io.IOException; +import org.jboss.tools.intellij.openshift.utils.oc.Oc; public class OdoCluster { public static final OdoCluster INSTANCE = new OdoCluster(); - private static final String CLUSTER_URL = System.getenv("CLUSTER_URL"); + public static final String CLUSTER_URL = System.getenv("CLUSTER_URL"); - private static final String CLUSTER_USER = System.getenv("CLUSTER_USER"); + public static final String CLUSTER_USER = System.getenv("CLUSTER_USER"); - private static final String CLUSTER_PASSWORD = System.getenv("CLUSTER_PASSWORD"); + public static final String CLUSTER_PASSWORD = System.getenv("CLUSTER_PASSWORD"); public void login(Oc oc) throws IOException { if (CLUSTER_URL != null && !oc.getMasterUrl().toString().startsWith(CLUSTER_URL)) { diff --git a/src/it/java/org/jboss/tools/intellij/openshift/utils/ToolFactoryTest.java b/src/it/java/org/jboss/tools/intellij/openshift/utils/ToolFactoryTest.java index ca332e5a1..c71bdfe4f 100644 --- a/src/it/java/org/jboss/tools/intellij/openshift/utils/ToolFactoryTest.java +++ b/src/it/java/org/jboss/tools/intellij/openshift/utils/ToolFactoryTest.java @@ -11,30 +11,38 @@ package org.jboss.tools.intellij.openshift.utils; import com.intellij.testFramework.fixtures.BasePlatformTestCase; +import io.fabric8.kubernetes.client.KubernetesClient; +import java.util.concurrent.ExecutionException; import org.jboss.tools.intellij.openshift.utils.ToolFactory.Tool; import org.jboss.tools.intellij.openshift.utils.helm.Helm; import org.jboss.tools.intellij.openshift.utils.oc.Oc; import org.jboss.tools.intellij.openshift.utils.odo.Odo; import org.jboss.tools.intellij.openshift.utils.odo.OdoDelegate; -import java.util.concurrent.ExecutionException; - public class ToolFactoryTest extends BasePlatformTestCase { + private KubernetesClient client; + + @Override + protected void setUp() throws Exception { + super.setUp(); + this.client = new KubernetesClientFactory().create(); + } + public void testGetOdo() throws ExecutionException, InterruptedException { - Tool tool = ToolFactory.getInstance().createOdo(getProject()).get(); + Tool tool = ToolFactory.getInstance().createOdo(client, getProject()).get(); Odo odo = tool.get(); assertNotNull(odo); } public void testGetHelm() throws ExecutionException, InterruptedException { - Tool tool = ToolFactory.getInstance().createHelm(getProject()).get(); + Tool tool = ToolFactory.getInstance().createHelm().get(); Helm helm = tool.get(); assertNotNull(helm); } public void testGetOc() throws ExecutionException, InterruptedException { - Tool tool = ToolFactory.getInstance().createOc(getProject()).get(); + Tool tool = ToolFactory.getInstance().createOc(client).get(); Oc oc = tool.get(); assertNotNull(oc); } diff --git a/src/it/java/org/jboss/tools/intellij/openshift/utils/helm/HelmCliSearchTest.java b/src/it/java/org/jboss/tools/intellij/openshift/utils/helm/HelmCliSearchTest.java index ea413c4e9..d95bb5651 100644 --- a/src/it/java/org/jboss/tools/intellij/openshift/utils/helm/HelmCliSearchTest.java +++ b/src/it/java/org/jboss/tools/intellij/openshift/utils/helm/HelmCliSearchTest.java @@ -16,22 +16,22 @@ public class HelmCliSearchTest extends HelmCliTest { - public void testSearch_should_list_all_charts() throws IOException { - // given openshift a repo was added to helm - // when - List charts = helm.search(); - // then - assertFalse(charts.isEmpty()); - } + public void testSearch_should_list_all_charts() throws IOException { + // given openshift a repo was added to helm + // when + List charts = helm.search(); + // then + assertFalse(charts.isEmpty()); + } - public void testSearch_should_list_kuberos() throws IOException { - // given openshift repo was added to helm - String id = Charts.CHART_KUBEROS; - // when - List charts = helm.search(id); - // then - boolean found = charts.stream().anyMatch((Chart chart) -> chart.getName().contains(id)); - assertTrue(found); - } + public void testSearch_should_list_kuberos() throws IOException { + // given openshift repo was added to helm + String id = Charts.CHART_KUBEROS; + // when + List charts = helm.search(id); + // then + boolean found = charts.stream().anyMatch((Chart chart) -> chart.getName().contains(id)); + assertTrue(found); + } } diff --git a/src/it/java/org/jboss/tools/intellij/openshift/utils/helm/HelmCliTest.java b/src/it/java/org/jboss/tools/intellij/openshift/utils/helm/HelmCliTest.java index 732c4a67e..c4fb6f920 100644 --- a/src/it/java/org/jboss/tools/intellij/openshift/utils/helm/HelmCliTest.java +++ b/src/it/java/org/jboss/tools/intellij/openshift/utils/helm/HelmCliTest.java @@ -11,6 +11,9 @@ package org.jboss.tools.intellij.openshift.utils.helm; import com.intellij.testFramework.fixtures.BasePlatformTestCase; +import io.fabric8.kubernetes.client.KubernetesClient; +import java.util.Random; +import org.jboss.tools.intellij.openshift.utils.KubernetesClientFactory; import org.jboss.tools.intellij.openshift.utils.OdoCluster; import org.jboss.tools.intellij.openshift.utils.ToolFactory; import org.jboss.tools.intellij.openshift.utils.ToolFactory.Tool; @@ -18,30 +21,29 @@ import org.jboss.tools.intellij.openshift.utils.odo.Odo; import org.jboss.tools.intellij.openshift.utils.odo.OdoDelegate; -import java.util.Random; - public abstract class HelmCliTest extends BasePlatformTestCase { protected Helm helm; - + private KubernetesClient client; private final String projectName = "prj-" + new Random().nextInt(); @Override protected void setUp() throws Exception { super.setUp(); - Tool odoTool = ToolFactory.getInstance().createOdo(getProject()).get(); - Tool ocTool = ToolFactory.getInstance().createOc(getProject()).get(); + this.client = new KubernetesClientFactory().create(); + Tool odoTool = ToolFactory.getInstance().createOdo(client, getProject()).get(); + Tool ocTool = ToolFactory.getInstance().createOc(client).get(); Odo odo = odoTool.get(); OdoCluster.INSTANCE.login(ocTool.get()); odo.createProject(projectName); - Tool helmTool = ToolFactory.getInstance().createHelm(getProject()).get(); + Tool helmTool = ToolFactory.getInstance().createHelm().get(); this.helm = helmTool.get(); Charts.addRepository(Charts.REPOSITORY_STABLE, helm); } @Override protected void tearDown() throws Exception { - Tool tool = ToolFactory.getInstance().createOdo(getProject()).getNow(null); + Tool tool = ToolFactory.getInstance().createOdo(client, getProject()).getNow(null); if (tool != null) { tool.get().deleteProject(projectName); } diff --git a/src/it/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCliTest.java b/src/it/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCliTest.java index 402310f5a..f01d0d5bb 100644 --- a/src/it/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCliTest.java +++ b/src/it/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCliTest.java @@ -14,8 +14,16 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.testFramework.fixtures.BasePlatformTestCase; import com.redhat.devtools.intellij.common.utils.MessagesHelper; +import io.fabric8.kubernetes.client.KubernetesClient; +import java.io.File; +import java.io.IOException; +import java.util.Random; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; import org.jboss.tools.intellij.openshift.tree.application.ApplicationRootNodeOdo; import org.jboss.tools.intellij.openshift.tree.application.ApplicationsRootNode; +import org.jboss.tools.intellij.openshift.utils.KubernetesClientFactory; import org.jboss.tools.intellij.openshift.utils.OdoCluster; import org.jboss.tools.intellij.openshift.utils.ToolFactory; import org.junit.After; @@ -23,13 +31,6 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import java.io.File; -import java.io.IOException; -import java.util.Random; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; - import static org.awaitility.Awaitility.with; import static org.jboss.tools.intellij.openshift.Constants.PLUGIN_FOLDER; import static org.mockito.Mockito.mock; @@ -64,18 +65,14 @@ public abstract class OdoCliTest extends BasePlatformTestCase { protected static final String REGISTRY_PREFIX = "reg"; private TestDialog previousTestDialog; + private KubernetesClient client; @Before public void init() throws Exception { - previousTestDialog = MessagesHelper.setTestDialog(TestDialog.OK); - ToolFactory.getInstance().createOc(getProject()).whenComplete((ocTool, throwable) -> { - try { - OdoCluster.INSTANCE.login(ocTool.get()); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - odo = getOdo().get(); + this.previousTestDialog = MessagesHelper.setTestDialog(TestDialog.OK); + this.client = new KubernetesClientFactory().create(); + loginCluster(); + this.odo = createOdo(client).get(); } @After @@ -83,15 +80,25 @@ public void cleanup() { MessagesHelper.setTestDialog(previousTestDialog); } - private CompletableFuture getOdo() { + private void loginCluster() { + ToolFactory.getInstance().createOc(client).whenComplete((ocTool, throwable) -> { + try { + OdoCluster.INSTANCE.login(ocTool.get()); + } catch (IOException e) { + throw new RuntimeException("Could not log into " + OdoCluster.CLUSTER_URL + " as user " + OdoCluster.CLUSTER_USER, e); + } + }); + } + + private CompletableFuture createOdo(KubernetesClient client) { return ToolFactory.getInstance() - .createOdo(getProject()) + .createOdo(client, getProject()) .thenApply(tool -> new ApplicationRootNodeOdo(tool.get(), false, rootNode, processHelper)); } protected void createProject(String project) throws IOException, ExecutionException, InterruptedException { odo.createProject(project); - odo = getOdo().get(); + odo = createOdo(client).get(); } protected void createComponent(String project, String component, String starter, String projectPath) throws IOException, ExecutionException, InterruptedException { diff --git a/src/it/java/org/jboss/tools/intellij/openshift/utils/odo/OdoKubernetesClientTest.java b/src/it/java/org/jboss/tools/intellij/openshift/utils/odo/OdoKubernetesClientTest.java index eebe03a4e..0a1118c49 100644 --- a/src/it/java/org/jboss/tools/intellij/openshift/utils/odo/OdoKubernetesClientTest.java +++ b/src/it/java/org/jboss/tools/intellij/openshift/utils/odo/OdoKubernetesClientTest.java @@ -27,10 +27,6 @@ import io.fabric8.openshift.api.model.ProjectList; import io.fabric8.openshift.client.OpenShiftClient; import io.fabric8.openshift.client.dsl.ProjectOperation; -import org.jboss.tools.intellij.openshift.utils.Cli; -import org.junit.Before; -import org.junit.Test; - import java.io.IOException; import java.net.HttpURLConnection; import java.net.MalformedURLException; @@ -40,7 +36,9 @@ import java.util.List; import java.util.Map; import java.util.function.Function; -import java.util.function.Supplier; +import org.jboss.tools.intellij.openshift.utils.Cli; +import org.junit.Before; +import org.junit.Test; import static org.fest.assertions.Assertions.assertThat; import static org.mockito.ArgumentMatchers.anyString; @@ -256,11 +254,10 @@ private OdoCli createOdo(KubernetesClient kubernetesClient, OpenShiftClient open MessageBus bus = mock(MessageBus.class); doReturn(connection) .when(bus).connect(); - Supplier kubernetesClientFactory = () -> kubernetesClient; Function openShiftClientFactory = client -> openShiftClient; Function> envVarFactory = url -> new HashMap<>(); Cli.TelemetryReport telemetryReport = mock(Cli.TelemetryReport.class); - return new OdoCli(project, command, bus, kubernetesClientFactory, openShiftClientFactory, envVarFactory, telemetryReport); + return new OdoCli(command, project, kubernetesClient, bus, openShiftClientFactory, envVarFactory, telemetryReport); } private static R mockResource(String name, Class clazz) { diff --git a/src/main/java/org/jboss/tools/intellij/openshift/actions/HelmAction.java b/src/main/java/org/jboss/tools/intellij/openshift/actions/HelmAction.java index b8ce0851c..c302a5c72 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/actions/HelmAction.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/actions/HelmAction.java @@ -57,7 +57,7 @@ public void actionPerformed(AnActionEvent anActionEvent, TreePath[] path, Object protected Helm getHelm(AnActionEvent anActionEvent) { try { - return ActionUtils.getApplicationRootNode(anActionEvent).getHelm(true); + return ActionUtils.getApplicationRootNode(anActionEvent).getHelm(); } catch (Exception e) { LOGGER.warn("Could not get helm: {}", e.getMessage(), e); return null; diff --git a/src/main/java/org/jboss/tools/intellij/openshift/actions/OcAction.java b/src/main/java/org/jboss/tools/intellij/openshift/actions/OcAction.java index fadc9c68f..633029833 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/actions/OcAction.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/actions/OcAction.java @@ -28,16 +28,17 @@ protected OcAction(Class... filters) { @Override public void actionPerformed(AnActionEvent anActionEvent, TreePath path, Object selected) { setTelemetrySender(new TelemetrySender(PREFIX_ACTION + getTelemetryActionName())); - ActionUtils.getApplicationRootNode(anActionEvent).getOcTool().whenComplete( - (ocTool, throwable) -> { - if (ocTool != null) { - Oc oc = ocTool.get(); - if (oc != null) { - this.actionPerformedOnSelectedObject(anActionEvent, getElement(selected), oc); + ActionUtils.getApplicationRootNode(anActionEvent).getOcTool() + .whenComplete( + (ocTool, throwable) -> { + if (ocTool != null) { + Oc oc = ocTool.get(); + if (oc != null) { + this.actionPerformedOnSelectedObject(anActionEvent, getElement(selected), oc); + } } } - } - ); + ); } public abstract void actionPerformedOnSelectedObject(AnActionEvent anActionEvent, Object selected, @NotNull Oc oc); diff --git a/src/main/java/org/jboss/tools/intellij/openshift/actions/project/ChangeActiveProjectAction.java b/src/main/java/org/jboss/tools/intellij/openshift/actions/project/ChangeActiveProjectAction.java index 497c0bcf0..61ef6dea4 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/actions/project/ChangeActiveProjectAction.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/actions/project/ChangeActiveProjectAction.java @@ -10,6 +10,7 @@ ******************************************************************************/ package org.jboss.tools.intellij.openshift.actions.project; +import com.intellij.openapi.actionSystem.ActionUpdateThread; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.progress.ProgressIndicator; @@ -189,4 +190,9 @@ public void run() { ); } } + + @Override + public @NotNull ActionUpdateThread getActionUpdateThread() { + return ActionUpdateThread.BGT; + } } 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 76d78fdb7..d5faf159e 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,15 +25,18 @@ import com.redhat.devtools.intellij.common.utils.ConfigHelper; 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.client.Config; +import io.fabric8.kubernetes.client.KubernetesClient; import java.io.File; import java.io.IOException; -import java.nio.file.Paths; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.Future; import org.jboss.tools.intellij.openshift.actions.NotificationUtils; +import org.jboss.tools.intellij.openshift.utils.KubernetesClientFactory; import org.jboss.tools.intellij.openshift.utils.ProjectUtils; import org.jboss.tools.intellij.openshift.utils.ToolFactory; import org.jboss.tools.intellij.openshift.utils.ToolFactory.Tool; @@ -59,14 +62,13 @@ public class ApplicationsRootNode private CompletableFuture> helmFuture; private CompletableFuture> ocFuture; private boolean logged; - private Config config; + private KubernetesClient client; private final OdoProcessHelper processHelper; public ApplicationsRootNode(Project project, ApplicationsTreeStructure structure, Disposable parent) { this.project = project; this.structure = structure; initConfigWatcher(); - this.config = loadConfig(); registerProjectListener(project); this.processHelper = new OdoProcessHelper(); Disposer.register(parent, this); @@ -91,7 +93,7 @@ private CompletableFuture doGetOdo() { if (odoFuture == null) { this.odoFuture = ReadAction.compute(() -> ToolFactory.getInstance() - .createOdo(project) + .createOdo(getClient(), project) .thenApply(tool -> { ApplicationRootNodeOdo odo = new ApplicationRootNodeOdo(tool.get(), tool.isDownloaded(), this, processHelper); loadProjectModel(odo, project); @@ -111,23 +113,36 @@ public CompletableFuture getOdo() { }); } - public void resetOdo() { + private void disposeClientAwareCLIs() { + safeCancel(odoFuture); this.odoFuture = null; + safeCancel(ocFuture); + this.ocFuture = null; + } + + private void safeCancel(Future future) { + if (future != null) { + try { + future.cancel(true); + } catch (CompletionException e) { + // swallowing intentionally + } + } } public CompletableFuture> getOcTool() { if (ocFuture == null) { - this.ocFuture = ToolFactory.getInstance().createOc(project); + this.ocFuture = ToolFactory.getInstance().createOc(getClient()); } return ocFuture; } - public CompletableFuture> getHelmTool(boolean notify) { + private CompletableFuture> getHelmTool() { if (helmFuture == null) { this.helmFuture = ToolFactory.getInstance() - .createHelm(project) + .createHelm() .whenComplete((tool, err) -> { - if (notify && tool.isDownloaded()) { + if (tool.isDownloaded()) { structure.fireModified(this); } }); @@ -135,8 +150,8 @@ public CompletableFuture> getHelmTool(boolean notify) { return helmFuture; } - public Helm getHelm(boolean notify) { - Tool tool = getHelmTool(notify).getNow(null); + public Helm getHelm() { + Tool tool = getHelmTool().getNow(null); if (tool == null) { return null; } @@ -148,11 +163,7 @@ public Project getProject() { } protected void initConfigWatcher() { - ExecHelper.submit(new ConfigWatcher(Paths.get(ConfigHelper.getKubeConfigPath()), this)); - } - - protected Config loadConfig() { - return ConfigHelper.safeLoadKubeConfig(); + ExecHelper.submit(new ConfigWatcher(this)); } public Map getLocalComponents() { @@ -247,15 +258,16 @@ protected void registerProjectListener(Project project) { } @Override - public void onUpdate(ConfigWatcher source, Config config) { - if (!ConfigHelper.areEqual(config, this.config)) { - this.config = config; + public void onUpdate(Config updated) { + Config current = getClient().getConfiguration(); + if (!ConfigHelper.areEqual(current, updated)) { + this.client = createClient(updated); refresh(); } } public synchronized void refresh() { - resetOdo(); + disposeClientAwareCLIs(); doGetOdo().whenComplete((odo, err) -> structure.fireModified(ApplicationsRootNode.this) ); @@ -303,6 +315,18 @@ public ApplicationsRootNode getRoot() { @Override public void dispose() { - resetOdo(); + disposeClientAwareCLIs(); } + + protected KubernetesClient getClient() { + if (client == null) { + this.client = createClient(Config.autoConfigure(null)); + } + return client; + } + + protected KubernetesClient createClient(Config config) { + return new KubernetesClientFactory().apply(config); + } + } 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 683f21a4f..9d1cfb47a 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 @@ -170,7 +170,7 @@ private Object getCurrentNamespace(ApplicationsRootNode element) { } private Object[] createHelmRepositoriesChildren(HelmRepositoriesNode parent) { - Helm helm = root.getHelm(true); + Helm helm = root.getHelm(); if (helm == null) { return new Object[]{new MessageNode<>(root, parent, "Could not list repositories: Helm binary missing.")}; } @@ -229,7 +229,7 @@ private List> getServices(NamespaceNode namespaceNode, Odo odo) { } private List> getHelmReleases(NamespaceNode namespaceNode) { - Helm helm = namespaceNode.getRoot().getHelm(true); + Helm helm = namespaceNode.getRoot().getHelm(); if (helm == null) { return List.of(new MessageNode<>(root, namespaceNode, "Could not get chart releases")); } diff --git a/src/main/java/org/jboss/tools/intellij/openshift/utils/Cli.java b/src/main/java/org/jboss/tools/intellij/openshift/utils/Cli.java index ec54da966..d40d58894 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/utils/Cli.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/utils/Cli.java @@ -14,35 +14,15 @@ import com.intellij.util.messages.MessageBus; import com.redhat.devtools.intellij.common.kubernetes.ClusterHelper; import com.redhat.devtools.intellij.common.kubernetes.ClusterInfo; -import com.redhat.devtools.intellij.common.ssl.IDEATrustManager; -import com.redhat.devtools.intellij.common.utils.ConfigHelper; import com.redhat.devtools.intellij.common.utils.NetworkUtils; import com.redhat.devtools.intellij.telemetry.core.configuration.TelemetryConfiguration; import com.redhat.devtools.intellij.telemetry.core.service.TelemetryMessageBuilder; -import io.fabric8.kubernetes.client.Config; import io.fabric8.kubernetes.client.KubernetesClient; -import io.fabric8.kubernetes.client.KubernetesClientBuilder; -import io.fabric8.kubernetes.client.http.HttpClient; -import io.fabric8.kubernetes.client.internal.SSLUtils; -import java.io.IOException; import java.net.URISyntaxException; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateException; -import java.security.spec.InvalidKeySpecException; -import java.util.Arrays; import java.util.Collections; -import java.util.List; import java.util.Map; import java.util.function.Function; -import java.util.function.Supplier; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509ExtendedTrustManager; -import javax.net.ssl.X509TrustManager; import org.jetbrains.annotations.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import static org.jboss.tools.intellij.openshift.telemetry.TelemetryService.IS_OPENSHIFT; import static org.jboss.tools.intellij.openshift.telemetry.TelemetryService.KUBERNETES_VERSION; @@ -52,34 +32,10 @@ public class Cli { - private static final Logger LOGGER = LoggerFactory.getLogger(Cli.class); + protected final String command; - protected final KubernetesClient client; - - protected Cli(Supplier kubernetesClientFactory) { - this.client = kubernetesClientFactory.get(); - } - - public static final class KubernetesClientFactory implements Supplier { - - @Override - public KubernetesClient get() { - String current = ConfigHelper.getCurrentContextName(); - Config config = Config.autoConfigure(current); - return new KubernetesClientBuilder().withConfig(config).withHttpClientBuilderConsumer(builder -> setSslContext(builder, config)).build(); - } - - private void setSslContext(HttpClient.Builder builder, Config config) { - try { - X509TrustManager externalTrustManager = new IDEATrustManager().configure(List.of(Arrays.stream(SSLUtils.trustManagers(config)) - .filter(X509ExtendedTrustManager.class::isInstance) - .map(X509ExtendedTrustManager.class::cast).toArray(X509ExtendedTrustManager[]::new))); - builder.sslContext(SSLUtils.keyManagers(config), List.of(externalTrustManager).toArray(new TrustManager[0])); - } catch (CertificateException | NoSuchAlgorithmException | KeyStoreException | IOException | - UnrecoverableKeyException | InvalidKeySpecException e) { - LOGGER.error(e.getMessage(), e); - } - } + protected Cli(String command) { + this.command = command; } public static final class EnvVarFactory implements Function> { diff --git a/src/main/java/org/jboss/tools/intellij/openshift/utils/ClientAwareCli.java b/src/main/java/org/jboss/tools/intellij/openshift/utils/ClientAwareCli.java new file mode 100644 index 000000000..9ffb027fc --- /dev/null +++ b/src/main/java/org/jboss/tools/intellij/openshift/utils/ClientAwareCli.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2024 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 io.fabric8.kubernetes.client.KubernetesClient; + +public class ClientAwareCli extends Cli{ + + protected final KubernetesClient client; + + protected ClientAwareCli(String command, KubernetesClient client) { + super(command); + this.client = client; + } +} diff --git a/src/main/java/org/jboss/tools/intellij/openshift/utils/KubernetesClientFactory.java b/src/main/java/org/jboss/tools/intellij/openshift/utils/KubernetesClientFactory.java new file mode 100644 index 000000000..797b46a6b --- /dev/null +++ b/src/main/java/org/jboss/tools/intellij/openshift/utils/KubernetesClientFactory.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2024 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 com.redhat.devtools.intellij.common.ssl.IDEATrustManager; +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.KubernetesClientBuilder; +import io.fabric8.kubernetes.client.http.HttpClient; +import io.fabric8.kubernetes.client.internal.SSLUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509ExtendedTrustManager; +import javax.net.ssl.X509TrustManager; +import java.io.IOException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.security.spec.InvalidKeySpecException; +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; + +public class KubernetesClientFactory implements Function { + + private static final Logger LOGGER = LoggerFactory.getLogger(KubernetesClientFactory.class); + + public KubernetesClient create() { + return create(null); + } + + public KubernetesClient create(String context) { + return apply(Config.autoConfigure(context)); + } + + @Override + public KubernetesClient apply(Config config) { + return new KubernetesClientBuilder() + .withConfig(config) + .withHttpClientBuilderConsumer(builder -> setSslContext(builder, config)) + .build(); + } + + private void setSslContext(HttpClient.Builder builder, Config config) { + try { + X509TrustManager externalTrustManager = new IDEATrustManager().configure(List.of(Arrays.stream(SSLUtils.trustManagers(config)) + .filter(X509ExtendedTrustManager.class::isInstance) + .map(X509ExtendedTrustManager.class::cast).toArray(X509ExtendedTrustManager[]::new))); + builder.sslContext(SSLUtils.keyManagers(config), List.of(externalTrustManager).toArray(new TrustManager[0])); + } catch (CertificateException | NoSuchAlgorithmException | KeyStoreException | IOException | + UnrecoverableKeyException | InvalidKeySpecException e) { + LOGGER.error(e.getMessage(), e); + } + } +} diff --git a/src/main/java/org/jboss/tools/intellij/openshift/utils/ToolFactory.java b/src/main/java/org/jboss/tools/intellij/openshift/utils/ToolFactory.java index d84f8242a..e4b306644 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/utils/ToolFactory.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/utils/ToolFactory.java @@ -12,6 +12,7 @@ import com.intellij.openapi.project.Project; import com.redhat.devtools.intellij.common.utils.DownloadHelper; +import io.fabric8.kubernetes.client.KubernetesClient; import org.jboss.tools.intellij.openshift.utils.helm.Helm; import org.jboss.tools.intellij.openshift.utils.helm.HelmCli; import org.jboss.tools.intellij.openshift.utils.oc.Oc; @@ -21,7 +22,7 @@ import java.net.URL; import java.util.concurrent.CompletableFuture; -import java.util.function.BiFunction; +import java.util.function.Function; public class ToolFactory { @@ -36,23 +37,21 @@ public static ToolFactory getInstance() { return INSTANCE; } - private final Factory odo = new Factory<>("odo", OdoCli::new); - private final Factory helm = new Factory<>("helm", (project, command) -> new HelmCli(command)); - private final Factory oc = new Factory<>("oc", (project, command) -> new OcCli(command)); + private ToolFactory() {} - private ToolFactory() { + public CompletableFuture> createOdo(KubernetesClient client, Project project) { + return new Downloadable("odo") + .downloadAndCreate(commandName -> new OdoCli(commandName, project, client)); } - public CompletableFuture> createOdo(Project project) { - return odo.create(project); + public CompletableFuture> createHelm() { + return new Downloadable("helm") + .downloadAndCreate(commandName -> new HelmCli(commandName)); } - public CompletableFuture> createHelm(Project project) { - return helm.create(project); - } - - public CompletableFuture> createOc(Project project) { - return oc.create(project); + public CompletableFuture> createOc(KubernetesClient client) { + return new Downloadable("helm") + .downloadAndCreate(commandName -> new OcCli(commandName, client)); } public static class Tool { @@ -73,31 +72,26 @@ public boolean isDownloaded() { } } - private static class Factory { + private static class Downloadable { private final String name; private final URL url = ToolFactory.class.getResource(TOOLS_JSON); - private final BiFunction toolFactory; - - private Factory(String name, BiFunction toolFactory) { + private Downloadable(String name) { this.name = name; - this.toolFactory = toolFactory; - } - - private CompletableFuture> create(Project project) { - return create(name, toolFactory, project); } - private CompletableFuture> create(String name, BiFunction toolFactory, Project project) { - return DownloadHelper.getInstance().downloadIfRequiredAsync(name, url).thenApply(toolInstance -> { - if (toolInstance != null) { - return new Tool<>(toolFactory.apply(project, toolInstance.getCommand()), toolInstance.isDownloaded()); - } else { - return null; - } - }); + private CompletableFuture> downloadAndCreate(Function factory) { + return DownloadHelper.getInstance() + .downloadIfRequiredAsync(name, url) + .thenApply(toolInstance -> { + if (toolInstance != null) { + return new Tool<>(factory.apply(toolInstance.getCommand()), toolInstance.isDownloaded()); + } else { + return null; + } + }); } } } diff --git a/src/main/java/org/jboss/tools/intellij/openshift/utils/helm/HelmCli.java b/src/main/java/org/jboss/tools/intellij/openshift/utils/helm/HelmCli.java index 461540612..4f0b0cbc4 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/utils/helm/HelmCli.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/utils/helm/HelmCli.java @@ -23,6 +23,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.jboss.tools.intellij.openshift.telemetry.TelemetryService; +import org.jboss.tools.intellij.openshift.utils.Cli; import org.jboss.tools.intellij.openshift.utils.Serialization; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,14 +32,12 @@ import static org.jboss.tools.intellij.openshift.Constants.HOME_FOLDER; import static org.jboss.tools.intellij.openshift.telemetry.TelemetryService.asyncSend; -public class HelmCli implements Helm { +public class HelmCli extends Cli implements Helm { private static final Logger LOGGER = LoggerFactory.getLogger(HelmCli.class); - private final String command; - public HelmCli(String command) { - this.command = command; + super(command); } @Override diff --git a/src/main/java/org/jboss/tools/intellij/openshift/utils/oc/OcCli.java b/src/main/java/org/jboss/tools/intellij/openshift/utils/oc/OcCli.java index c07543330..c59a9cad4 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/utils/oc/OcCli.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/utils/oc/OcCli.java @@ -14,50 +14,46 @@ import com.intellij.util.messages.MessageBus; import com.redhat.devtools.intellij.common.utils.ExecHelper; import io.fabric8.kubernetes.client.KubernetesClient; -import org.jboss.tools.intellij.openshift.utils.Cli; -import org.jetbrains.annotations.NotNull; - import java.io.File; import java.io.IOException; import java.net.URL; import java.util.Map; import java.util.function.Function; -import java.util.function.Supplier; +import org.jboss.tools.intellij.openshift.utils.Cli; +import org.jboss.tools.intellij.openshift.utils.ClientAwareCli; +import org.jetbrains.annotations.NotNull; import static org.jboss.tools.intellij.openshift.Constants.HOME_FOLDER; -public class OcCli extends Cli implements Oc { +public class OcCli extends ClientAwareCli implements Oc { - private final String command; private final Map envVars; - public OcCli(String command) { + public OcCli(String command, KubernetesClient client) { this(command, + client, ApplicationManager.getApplication().getMessageBus(), - new Cli.KubernetesClientFactory(), new Cli.EnvVarFactory(), new Cli.TelemetryReport()); } public OcCli( String command, + KubernetesClient client, MessageBus bus, - Supplier kubernetesClientFactory, Function> envVarFactory, Cli.TelemetryReport telemetryReport) { - super(kubernetesClientFactory); - this.command = command; + super(command, client); this.envVars = envVarFactory.apply(String.valueOf(client.getMasterUrl())); initTelemetry(telemetryReport, bus); } - private void initTelemetry(TelemetryReport telemetryReport, MessageBus bus) { + private void initTelemetry(Cli.TelemetryReport telemetryReport, MessageBus bus) { telemetryReport.addTelemetryVars(envVars); telemetryReport.subscribe(bus, envVars); telemetryReport.report(client); } - private static void execute(@NotNull File workingDirectory, String command, Map envs, String... args) throws IOException { ExecHelper.executeWithResult(command, true, workingDirectory, envs, args); } diff --git a/src/main/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCli.java b/src/main/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCli.java index ebb77cfc9..17319e443 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCli.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/utils/odo/OdoCli.java @@ -18,9 +18,11 @@ import com.intellij.execution.process.ProcessEvent; import com.intellij.execution.process.ProcessHandler; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.Strings; import com.intellij.util.messages.MessageBus; +import com.redhat.devtools.intellij.common.kubernetes.ClusterHelper; import com.redhat.devtools.intellij.common.utils.ExecHelper; import io.fabric8.kubernetes.api.Pluralize; import io.fabric8.kubernetes.api.model.ConfigMap; @@ -37,15 +39,6 @@ import io.fabric8.openshift.client.OpenShiftClient; import io.fabric8.openshift.client.dsl.OpenShiftOperatorHubAPIGroupDSL; import io.fabric8.openshift.client.impl.OpenShiftOperatorHubAPIGroupClient; -import org.jboss.tools.intellij.openshift.KubernetesLabels; -import org.jboss.tools.intellij.openshift.utils.Cli; -import org.jboss.tools.intellij.openshift.utils.KubernetesClientExceptionUtils; -import org.jboss.tools.intellij.openshift.utils.Serialization; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -57,14 +50,22 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.BinaryOperator; import java.util.function.Function; -import java.util.function.Supplier; +import org.jboss.tools.intellij.openshift.KubernetesLabels; +import org.jboss.tools.intellij.openshift.utils.Cli; +import org.jboss.tools.intellij.openshift.utils.ClientAwareCli; +import org.jboss.tools.intellij.openshift.utils.KubernetesClientExceptionUtils; +import org.jboss.tools.intellij.openshift.utils.Serialization; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import static io.fabric8.openshift.client.OpenShiftClient.BASE_API_GROUP; import static org.jboss.tools.intellij.openshift.Constants.HOME_FOLDER; import static org.jboss.tools.intellij.openshift.Constants.OCP3_CONFIG_NAMESPACE; import static org.jboss.tools.intellij.openshift.Constants.OCP3_WEBCONSOLE_CONFIG_MAP_NAME; @@ -74,7 +75,7 @@ import static org.jboss.tools.intellij.openshift.Constants.OCP4_CONSOLE_URL_KEY_NAME; import static org.jboss.tools.intellij.openshift.Constants.PLUGIN_FOLDER; -public class OdoCli extends Cli implements OdoDelegate { +public class OdoCli extends ClientAwareCli implements OdoDelegate { private static final Logger LOGGER = LoggerFactory.getLogger(OdoCli.class); @@ -86,7 +87,6 @@ public class OdoCli extends Cli implements OdoDelegate { private static final String NAMESPACE_FIELD = "namespace"; private static final String SPEC_FIELD = "spec"; private final com.intellij.openapi.project.Project project; - private final String command; private final OpenShiftClient openshiftClient; private final Map envVars; private final AtomicBoolean swaggerLoaded = new AtomicBoolean(); @@ -94,26 +94,25 @@ public class OdoCli extends Cli implements OdoDelegate { private JSonParser swagger; private CompletableFuture isPodmanPresent; - public OdoCli(com.intellij.openapi.project.Project project, String command) { - this(project, - command, + public OdoCli(String command, Project project, KubernetesClient client) { + this(command, + project, + client, ApplicationManager.getApplication().getMessageBus(), - new Cli.KubernetesClientFactory(), new OpenShiftClientFactory(), new Cli.EnvVarFactory(), new Cli.TelemetryReport()); } protected OdoCli( - com.intellij.openapi.project.Project project, String command, + Project project, + KubernetesClient client, MessageBus bus, - Supplier kubernetesClientFactory, Function openshiftClientFactory, Function> envVarFactory, Cli.TelemetryReport telemetryReport) { - super(kubernetesClientFactory); - this.command = command; + super(command, client); this.project = project; this.openshiftClient = openshiftClientFactory.apply(client); this.envVars = envVarFactory.apply(String.valueOf(client.getMasterUrl())); @@ -773,7 +772,19 @@ private boolean isPodmanPresent() { LOGGER.warn(e.getLocalizedMessage(), e); return false; } - }, runnable -> ApplicationManager.getApplication().executeOnPooledThread(runnable)); + }, getExecutor()); + } + + private static @NotNull Executor getExecutor() { + Executor executor = (Runnable runnable) -> { + if (ApplicationManager.getApplication() != null) { + ApplicationManager.getApplication().executeOnPooledThread(runnable); + } else { + // unit-test mode without application + runnable.run(); + } + }; + return executor; } private static final class OpenShiftClientFactory implements Function { @@ -781,7 +792,7 @@ private static final class OpenShiftClientFactory implements Function contexts) { Config config = mock(Config.class); - doReturn(contextName).when(config).getCurrentContext(); - NamedContext namedContext = createNamedContext(contextName, context); - doReturn(Arrays.asList(namedContext)).when(config).getContexts(); - - if (authInfo != null) { - NamedAuthInfo namedAuthInfo = mock(NamedAuthInfo.class); - doReturn(user).when(namedAuthInfo).getName(); - doReturn(authInfo).when(namedAuthInfo).getUser(); - doReturn(Arrays.asList(namedAuthInfo)).when(config).getUsers(); - } + doReturn(token) + .when(config).getAutoOAuthToken(); + doReturn(current) + .when(config).getCurrentContext(); + doReturn(contexts) + .when(config).getContexts(); return config; } - private NamedContext createNamedContext(String contextName, Context context) { - NamedContext namedContext = mock(NamedContext.class); - doReturn(contextName).when(namedContext).getName(); - doReturn(context).when(namedContext).getContext(); - return namedContext; - } - - private Context createContext() { - return createContext(null, null); + private NamedContext createNamedContext(NamedContext namedContext) { + Context context = namedContext.getContext(); + return createNamedContext(namedContext.getName(), context.getCluster(), context.getNamespace(), context.getUser()); } - private Context createContext(String user, String cluster) { + private NamedContext createNamedContext(String name, String cluster, String namespace, String user) { Context context = mock(Context.class); - if (!StringUtil.isEmptyOrSpaces(user)) { - doReturn(user).when(context).getUser(); - } - if (!StringUtil.isEmptyOrSpaces(cluster)) { - doReturn(cluster).when(context).getCluster(); - } - return context; + doReturn(cluster) + .when(context).getCluster(); + doReturn(namespace) + .when(context).getNamespace(); + doReturn(user) + .when(context).getUser(); + + NamedContext namedContext = mock(NamedContext.class); + doReturn(name) + .when(namedContext).getName(); + doReturn(context) + .when(namedContext).getContext(); + return namedContext; } - private AuthInfo createAuthInfo(String token) { - AuthInfo authInfo = mock(AuthInfo.class); - doReturn(token).when(authInfo).getToken(); - return authInfo; + private KubernetesClient createKubernetesClient(Config config) throws MalformedURLException { + KubernetesClient client = mock(KubernetesClient.class); + doReturn(new URL("https://starwars.com")) // avoid "invalid master url" exception + .when(client).getMasterUrl(); + doReturn(config) + .when(client).getConfiguration(); + return client; } }