Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: bump kubernetes-client to 7.0.0 (#794) #796

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ org.gradle.configuration-cache=true
org.gradle.caching=true

kotlin.daemon.jvm.options=-Xmx2g
org.gradle.jvmargs=-Xmx2g
org.gradle.jvmargs=-Xmx2g

4 changes: 2 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[versions]
# libraries
kubernetes-client = "6.12.0"
kubernetes-client = "7.0.0"
devtools-common = "1.9.7-SNAPSHOT"
jackson-core = "2.17.0"
commons-lang3 = "3.12.0"
Expand All @@ -19,7 +19,7 @@ kotlinJvm = "2.0.20"
[libraries]
openshift-client = { group = "io.fabric8", name = "openshift-client", version.ref = "kubernetes-client" }
kubernetes-client = { group = "io.fabric8", name = "kubernetes-client", version.ref = "kubernetes-client" }
kubernetes-model = { group = "io.fabric8", name = "kubernetes-model", version.ref = "kubernetes-client" }
kubernetes-model = { group = "io.fabric8", name = "kubernetes-model-core", version.ref = "kubernetes-client" }
kubernetes-model-common = { group = "io.fabric8", name = "kubernetes-model-common", version.ref = "kubernetes-client" }
kubernetes-httpclient-okhttp = { group = "io.fabric8", name = "kubernetes-httpclient-okhttp", version.ref = "kubernetes-client" }
devtools-common = { group = "com.redhat.devtools.intellij", name = "intellij-common", version.ref = "devtools-common" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ package com.redhat.devtools.intellij.kubernetes.model

import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.logger
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 com.redhat.devtools.intellij.kubernetes.model.client.ClientAdapter
Expand All @@ -30,7 +29,6 @@ import com.redhat.devtools.intellij.kubernetes.telemetry.TelemetryService.PROP_O
import io.fabric8.kubernetes.api.model.HasMetadata
import io.fabric8.kubernetes.client.Config
import io.fabric8.kubernetes.client.KubernetesClient
import java.nio.file.Paths
import java.util.concurrent.CompletionException
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.read
Expand Down Expand Up @@ -83,11 +81,13 @@ open class AllContexts(
namespace: String?,
context: String?
) -> ClientAdapter<out KubernetesClient>
= { namespace, context -> ClientAdapter.Factory.create(namespace, context) }
= { namespace, config ->
ClientAdapter.Factory.create(namespace, config)
}
) : IAllContexts {

init {
watchKubeConfig()
watchKubeConfigs()
}

private val lock = ReentrantReadWriteLock()
Expand Down Expand Up @@ -148,7 +148,8 @@ open class AllContexts(
) : IActiveContext<out HasMetadata, out KubernetesClient>? {
lock.write {
try {
replaceClient(newClient, this.client.get())
client.get()?.close()
client.set(newClient)
newClient.config.save().join()
current?.close()
clearAllContexts() // causes reload of all contexts when accessed afterwards
Expand Down Expand Up @@ -204,13 +205,6 @@ open class AllContexts(
}
}

private fun replaceClient(new: ClientAdapter<out KubernetesClient>, old: ClientAdapter<out KubernetesClient>?)
: ClientAdapter<out KubernetesClient> {
old?.close()
this.client.set(new)
return new
}

private fun createActiveContext(client: ClientAdapter<out KubernetesClient>?)
: IActiveContext<out HasMetadata, out KubernetesClient>? {
if (client == null) {
Expand Down Expand Up @@ -241,8 +235,7 @@ open class AllContexts(
}
}

protected open fun watchKubeConfig() {
val path = Paths.get(Config.getKubeconfigFilename())
protected open fun watchKubeConfigs() {
/**
* [ConfigWatcher] cannot add/remove listeners nor can it get closed (and stop the [java.nio.file.WatchService]).
* We therefore have to create a single instance in here rather than using it in a shielded/private way within
Expand All @@ -251,16 +244,16 @@ open class AllContexts(
* The latter gets closed/recreated whenever the context changes in
* [com.redhat.devtools.intellij.kubernetes.model.client.KubeConfigAdapter].
*/
val watcher = ConfigWatcher(path) { _, config: io.fabric8.kubernetes.api.model.Config? -> onKubeConfigChanged(config) }
val watcher = ConfigWatcher { config: Config? -> onKubeConfigChanged(config) }
runAsync(watcher::run)
}

protected open fun onKubeConfigChanged(fileConfig: io.fabric8.kubernetes.api.model.Config?) {
protected open fun onKubeConfigChanged(updated: Config?) {
lock.read {
fileConfig ?: return
updated ?: return
val client = client.get() ?: return
val clientConfig = client.config.configuration
if (ConfigHelper.areEqual(fileConfig, clientConfig)) {
val existing = client.config
if (existing.isEqualConfig(updated)) {
return
}
this.client.reset() // create new client when accessed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ open class OSClientAdapter(client: OpenShiftClient, private val kubeClient: Kube

override val config by lazy {
// openshift client configuration does not have kube config entries
ClientConfig(kubeClient)
ClientConfig(kubeClient.configuration)
}

override fun isOpenShift(): Boolean {
Expand All @@ -56,47 +56,31 @@ open class KubeClientAdapter(client: KubernetesClient) :
abstract class ClientAdapter<C : KubernetesClient>(private val fabric8Client: C) {

companion object Factory {

fun create(
namespace: String? = null,
context: String? = null,
clientBuilder: KubernetesClientBuilder = KubernetesClientBuilder(),
trustManagerProvider: ((toIntegrate: List<X509ExtendedTrustManager>) -> X509TrustManager)
= IDEATrustManager()::configure
clientBuilder: KubernetesClientBuilder? = null,
externalTrustManagerProvider: ((toIntegrate: List<X509ExtendedTrustManager>) -> X509TrustManager)? = null
): ClientAdapter<out KubernetesClient> {
val config = Config.autoConfigure(context)
return create(namespace, config, clientBuilder, trustManagerProvider)
}

fun create(
namespace: String? = null,
config: Config,
clientBuilder: KubernetesClientBuilder,
externalTrustManagerProvider: (toIntegrate: List<X509ExtendedTrustManager>) -> X509TrustManager
= IDEATrustManager()::configure
): ClientAdapter<out KubernetesClient> {
setNamespace(namespace, config)
val kubeClient = clientBuilder
val builder = clientBuilder ?: KubernetesClientBuilder()
val trustManager = externalTrustManagerProvider ?: IDEATrustManager()::configure
val kubeClient = builder
.withConfig(config)
.withHttpClientBuilderConsumer { builder ->
setSslContext(builder, config, externalTrustManagerProvider)
.withHttpClientBuilderConsumer { httpClientBuilder ->
setSslContext(httpClientBuilder, config, trustManager)
}
.build()
return if (isOpenShift(kubeClient)) {
return if (ClusterHelper.isOpenShift(kubeClient)) {
val osClient = kubeClient.adapt(NamespacedOpenShiftClient::class.java)
OSClientAdapter(osClient, kubeClient)
} else {
KubeClientAdapter(kubeClient)
}
}

private fun isOpenShift(client: KubernetesClient): Boolean {
return try {
ClusterHelper.isOpenShift(client)
} catch (e: Exception) {
false;
}
}

private fun setSslContext(
builder: HttpClient.Builder,
config: Config,
Expand Down Expand Up @@ -124,7 +108,7 @@ abstract class ClientAdapter<C : KubernetesClient>(private val fabric8Client: C)
private val clients = ConcurrentHashMap<Class<out Client>, Client>()

open val config by lazy {
ClientConfig(fabric8Client)
ClientConfig(fabric8Client.configuration)
}

abstract fun isOpenShift(): Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ package com.redhat.devtools.intellij.kubernetes.model.client

import com.redhat.devtools.intellij.common.utils.ConfigHelper
import com.redhat.devtools.intellij.kubernetes.CompletableFutureUtils.PLATFORM_EXECUTOR
import io.fabric8.kubernetes.api.model.Context
import com.redhat.devtools.intellij.kubernetes.model.util.ConfigUtils
import io.fabric8.kubernetes.api.model.NamedContext
import io.fabric8.kubernetes.client.Client
import io.fabric8.kubernetes.client.Config
import io.fabric8.kubernetes.client.internal.KubeConfigUtils
import java.util.concurrent.CompletableFuture
Expand All @@ -24,98 +23,53 @@ import java.util.concurrent.Executor
* An adapter to access [io.fabric8.kubernetes.client.Config].
* It also saves the kube config [KubeConfigUtils] when it changes the client config.
*/
open class ClientConfig(private val client: Client, private val executor: Executor = PLATFORM_EXECUTOR) {
open class ClientConfig(private val config: Config, private val executor: Executor = PLATFORM_EXECUTOR) {

open var currentContext: NamedContext?
get() {
return configuration.currentContext
return config.currentContext
}
set(context) {
configuration.currentContext = context
config.currentContext = context
}

open val allContexts: List<NamedContext>
get() {
return configuration.contexts ?: emptyList()
return config.contexts ?: emptyList()
}

open val configuration: Config by lazy {
client.configuration
}

protected open val kubeConfig: KubeConfigAdapter by lazy {
KubeConfigAdapter()
fun isEqualConfig(config: Config): Boolean {
return ConfigHelper.areEqualCurrentContext(config, this.config)
&& ConfigHelper.areEqualContexts(config, this.config)
&& ConfigHelper.areEqualCluster(config, this.config)
&& ConfigHelper.areEqualAuthInfo(config, this.config)
}

fun save(): CompletableFuture<Boolean> {
return CompletableFuture.supplyAsync(
{
if (!kubeConfig.exists()) {
return@supplyAsync false
val modified = HashSet<KubeConfigAdapter>()

val currentContextPair = ConfigUtils.getFileWithCurrentContext()
if (currentContextPair != null) {
val kubeConfig = KubeConfigAdapter(currentContextPair.first, currentContextPair.second)
if (kubeConfig.setCurrentContext(config.currentContext?.name)) {
modified.add(kubeConfig)
}
}
val fromFile = kubeConfig.load() ?: return@supplyAsync false
return@supplyAsync if (setCurrentContext(
currentContext,
KubeConfigUtils.getCurrentContext(fromFile),
fromFile
).or( // no short-circuit
setCurrentNamespace(
currentContext?.context,
KubeConfigUtils.getCurrentContext(fromFile)?.context
)
)
) {
kubeConfig.save(fromFile)
true
} else {
false
val kubeConfig = KubeConfigAdapter(config.file)
if (kubeConfig.setCurrentNamespace(config.currentContext?.name, config.namespace)) {
modified.add(kubeConfig)
}
modified.forEach { kubeConfig ->
kubeConfig.save()
}
modified.isNotEmpty()
},
executor
)
}

private fun setCurrentContext(
currentContext: NamedContext?,
kubeConfigCurrentContext: NamedContext?,
kubeConfig: io.fabric8.kubernetes.api.model.Config
): Boolean {
return if (currentContext != null
&& !ConfigHelper.areEqual(currentContext, kubeConfigCurrentContext)
) {
kubeConfig.currentContext = currentContext.name
true
} else {
false
}
}

/**
* Sets the namespace in the given source [Context] to the given target [Context].
* Does nothing if the target config has no current context
* or if the source config has no current context
* or if setting it would not change it.
*
* @param source Context whose namespace should be copied
* @param target Context whose namespace should be overriden
* @return
*/
private fun setCurrentNamespace(
source: Context?,
target: Context?
): Boolean {
val sourceNamespace = source?.namespace ?: return false
val targetNamespace = target?.namespace
return if (target != null
&& sourceNamespace != targetNamespace
) {
target.namespace = source.namespace
true
} else {
false
}
}

fun isCurrent(context: NamedContext): Boolean {
return context == currentContext
}
Expand Down
Loading
Loading