Skip to content

Commit c996c6c

Browse files
authored
fix: refactor: bump kubernetes-client to 6.12.0 (#713) (#730)
* bump kubernetes-client to 6.10 (#713) * remove watches even if closing failed * dont dead lock when switching ns/refreshing cluster * bumped kubernetes-client to 6.12.0 (#713) Signed-off-by: Andre Dietisheim <[email protected]>
1 parent 9f97baa commit c996c6c

File tree

11 files changed

+63
-60
lines changed

11 files changed

+63
-60
lines changed

build.gradle

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
buildscript {
2-
32
ext.ideaVersion = ideaVersion
43
ext.kotlinVersion = kotlinVersion
54
ext.java_version = "17"
@@ -42,17 +41,17 @@ dependencies {
4241
"io.fabric8:kubernetes-model-common:${kubernetesClientVersion}",
4342
"io.fabric8:openshift-client:${kubernetesClientVersion}",
4443
"io.fabric8:kubernetes-httpclient-okhttp:${kubernetesClientVersion}",
44+
"com.fasterxml.jackson.core:jackson-core:2.17.0", /* IC-2022.3 ships 2.16.0 */
4545
"org.apache.commons:commons-lang3:3.12.0"
4646
)
4747
testImplementation(
4848
"org.assertj:assertj-core:3.22.0",
4949
"org.mockito:mockito-inline:4.5.1",
5050
"com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0",
51-
"org.jetbrains.kotlin:kotlin-test-junit:${kotlinVersion}",
52-
"org.yaml:snakeyaml:1.33" /* IC-2023.2 provides incompatible 2.0 */
51+
"org.jetbrains.kotlin:kotlin-test-junit:${kotlinVersion}"
5352
)
5453
integrationTestImplementation(
55-
"com.redhat.devtools.intellij:intellij-common:1.1.0",
54+
"com.redhat.devtools.intellij:intellij-common:${intellijCommonVersion}",
5655
"com.redhat.devtools.intellij:intellij-common-ui-test-library:0.2.0",
5756
"org.junit.jupiter:junit-jupiter-engine:5.8.2",
5857
"org.junit.jupiter:junit-jupiter-api:5.8.2",

gradle.properties

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ ideaVersion=IC-2024.1
22
# build number ranges
33
# https://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/build_number_ranges.html
44
sinceIdeaBuild=223
5-
projectVersion=1.2.3
5+
projectVersion=1.2.4-SNAPSHOT
66
jetBrainsToken=invalid
77
jetBrainsChannel=stable
88
intellijPluginVersion=1.16.1
99
kotlinJvmPluginVersion=1.8.0
10-
intellijCommonVersion=1.9.4-SNAPSHOT
10+
intellijCommonVersion=1.9.4
1111
telemetryPluginVersion=1.1.0.52
1212
kotlin.stdlib.default.dependency = false
1313
kotlinVersion=1.6.21
14-
kubernetesClientVersion=6.4.0
14+
kubernetesClientVersion=6.12.0
1515
fixturesVersion=1.1.18

src/main/kotlin/com/redhat/devtools/intellij/kubernetes/model/AllContexts.kt

+37-34
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import com.redhat.devtools.intellij.kubernetes.model.context.IActiveContext
2222
import com.redhat.devtools.intellij.kubernetes.model.context.IContext
2323
import com.redhat.devtools.intellij.kubernetes.model.resource.ResourceKind
2424
import com.redhat.devtools.intellij.kubernetes.model.util.ResettableLazyProperty
25-
import com.redhat.devtools.intellij.kubernetes.model.util.ResourceException
2625
import com.redhat.devtools.intellij.kubernetes.telemetry.TelemetryService
2726
import com.redhat.devtools.intellij.kubernetes.telemetry.TelemetryService.NAME_PREFIX_CONTEXT
2827
import com.redhat.devtools.intellij.kubernetes.telemetry.TelemetryService.PROP_IS_OPENSHIFT
@@ -31,9 +30,11 @@ import com.redhat.devtools.intellij.kubernetes.telemetry.TelemetryService.PROP_O
3130
import io.fabric8.kubernetes.api.model.HasMetadata
3231
import io.fabric8.kubernetes.client.Config
3332
import io.fabric8.kubernetes.client.KubernetesClient
34-
import io.fabric8.kubernetes.client.KubernetesClientException
3533
import java.nio.file.Paths
3634
import java.util.concurrent.CompletionException
35+
import java.util.concurrent.locks.ReentrantReadWriteLock
36+
import kotlin.concurrent.read
37+
import kotlin.concurrent.write
3738

3839
interface IAllContexts {
3940
/**
@@ -89,25 +90,29 @@ open class AllContexts(
8990
watchKubeConfig()
9091
}
9192

93+
private val lock = ReentrantReadWriteLock()
94+
9295
private val client = ResettableLazyProperty {
93-
clientFactory.invoke(null,null)
96+
lock.write {
97+
clientFactory.invoke(null, null)
98+
}
9499
}
95100

96101
override val current: IActiveContext<out HasMetadata, out KubernetesClient>?
97102
get() {
98-
synchronized(this) {
99-
return findActive(all)
100-
}
103+
return findActive(all)
101104
}
102105

103-
override val all: MutableList<IContext> = mutableListOf()
106+
private val _all: MutableList<IContext> = mutableListOf()
107+
108+
override val all: List<IContext>
104109
get() {
105-
synchronized(this) {
106-
if (field.isEmpty()) {
110+
lock.write {
111+
if (_all.isEmpty()) {
107112
val all = createContexts(client.get(), client.get()?.config)
108-
field.addAll(all)
113+
_all.addAll(all)
109114
}
110-
return field
115+
return _all
111116
}
112117
}
113118

@@ -137,36 +142,32 @@ open class AllContexts(
137142
newClient: ClientAdapter<out KubernetesClient>,
138143
toWatch: Collection<ResourceKind<out HasMetadata>>?,
139144
) : IActiveContext<out HasMetadata, out KubernetesClient>? {
140-
try {
141-
synchronized(this) {
145+
lock.write {
146+
try {
142147
replaceClient(newClient, this.client.get())
143148
newClient.config.save().join()
144149
current?.close()
145-
all.clear() // causes reload of all contexts when accessed afterwards
150+
clearAllContexts() // causes reload of all contexts when accessed afterwards
146151
val newCurrent = current // gets new current from all
147152
if (toWatch != null) {
148153
newCurrent?.watchAll(toWatch)
149154
}
150155
return newCurrent
156+
} catch (e: CompletionException) {
157+
val cause = e.cause ?: throw e
158+
throw cause
151159
}
152-
} catch (e: CompletionException) {
153-
val cause = e.cause ?: throw e
154-
throw cause
155160
}
156161
}
157162

158-
private fun throwIfNotAccessible(namespace: String, client: KubernetesClient) {
159-
try {
160-
client.namespaces()?.withName(namespace)?.isReady
161-
} catch(e: KubernetesClientException) {
162-
throw ResourceException("Namespace $namespace is not accessible", e)
163-
}
163+
private fun clearAllContexts() {
164+
_all.clear()
164165
}
165166

166167
override fun refresh() {
167-
synchronized(this) {
168+
lock.write {
168169
this.current?.close()
169-
all.clear() // latter access will cause reload
170+
clearAllContexts() // latter access will cause reload
170171
}
171172
modelChange.fireAllContextsChanged()
172173
}
@@ -187,14 +188,16 @@ open class AllContexts(
187188
) {
188189
return emptyList()
189190
}
190-
return config.allContexts
191-
.map {
192-
if (config.isCurrent(it)) {
193-
createActiveContext(client) ?: Context(it)
194-
} else {
195-
Context(it)
191+
lock.read {
192+
return config.allContexts
193+
.map {
194+
if (config.isCurrent(it)) {
195+
createActiveContext(client) ?: Context(it)
196+
} else {
197+
Context(it)
198+
}
196199
}
197-
}
200+
}
198201
}
199202

200203
private fun replaceClient(new: ClientAdapter<out KubernetesClient>, old: ClientAdapter<out KubernetesClient>?)
@@ -249,7 +252,7 @@ open class AllContexts(
249252
}
250253

251254
protected open fun onKubeConfigChanged(fileConfig: io.fabric8.kubernetes.api.model.Config?) {
252-
synchronized(this) {
255+
lock.read {
253256
fileConfig ?: return
254257
val client = client.get() ?: return
255258
val clientConfig = client.config.configuration
@@ -258,8 +261,8 @@ open class AllContexts(
258261
}
259262
this.client.reset() // create new client when accessed
260263
client.close()
261-
refresh()
262264
}
265+
refresh()
263266
}
264267

265268
/** for testing purposes */

src/main/kotlin/com/redhat/devtools/intellij/kubernetes/model/ResourceWatch.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ open class ResourceWatch<T>(
113113
true
114114
} catch (e: Exception) {
115115
logger<ResourceWatch<*>>().warn("Error when closing watch for $type resources.", e)
116-
false
116+
// do as if close() worked so that watch gets removed
117+
true
117118
}
118119
}
119120

src/main/kotlin/com/redhat/devtools/intellij/kubernetes/model/resource/NamespacedResourceOperator.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ abstract class NamespacedResourceOperator<R : HasMetadata, C: Client>(
117117
client.adapt(KubernetesClient::class.java)
118118
.resource(toReplace)
119119
.inNamespace(inNamespace)
120-
.replace()
120+
.patch()
121121
}
122122
}
123123

src/main/kotlin/com/redhat/devtools/intellij/kubernetes/model/resource/NonNamespacedResourceOperator.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ abstract class NonNamespacedResourceOperator<R : HasMetadata, C : Client>(
8787
return runWithoutServerSetProperties(toReplace) {
8888
client.adapt(KubernetesClient::class.java)
8989
.resource(toReplace)
90-
.replace()
90+
.patch()
9191
}
9292
}
9393

src/main/kotlin/com/redhat/devtools/intellij/kubernetes/model/resource/kubernetes/custom/NamespacedCustomResourceOperator.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ open class NamespacedCustomResourceOperator(
8686
getOperation()
8787
?.inNamespace(inNamespace)
8888
?.resource(toReplace)
89-
?.createOrReplace()
89+
?.patch()
9090
}
9191
}
9292

src/main/kotlin/com/redhat/devtools/intellij/kubernetes/model/resource/kubernetes/custom/NonNamespacedCustomResourceOperator.kt

+4-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,10 @@ class NonNamespacedCustomResourceOperator(
7272
return runWithoutServerSetProperties(toReplace) {
7373
getOperation()
7474
?.resource(resource)
75-
?.createOrReplace()
75+
/**
76+
* See: https://github.com/fabric8io/kubernetes-client/blob/main/doc/FAQ.md#alternatives-to-createOrReplace-and-replace
77+
*/
78+
?.patch()
7679
}
7780
}
7881

src/main/kotlin/com/redhat/devtools/intellij/kubernetes/model/util/ResourceUtils.kt

+6-9
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition
1616
import io.fabric8.kubernetes.client.utils.ApiVersionUtil
1717
import io.fabric8.kubernetes.client.utils.KubernetesVersionPriority
1818
import io.fabric8.kubernetes.client.utils.Serialization
19-
import io.fabric8.kubernetes.model.annotation.Group
20-
import io.fabric8.kubernetes.model.annotation.Version
21-
import io.fabric8.kubernetes.model.util.Helper
2219
import java.util.stream.Collectors
2320

2421
const val MARKER_WILL_BE_DELETED = "willBeDeleted"
@@ -128,13 +125,13 @@ fun String.isGreaterIntThan(other: String?): Boolean {
128125
* @see io.fabric8.kubernetes.model.annotation.Group (annotation)
129126
*/
130127
fun getApiVersion(clazz: Class<out HasMetadata>): String {
131-
val apiVersion = Helper.getAnnotationValue(clazz, Version::class.java)
132-
return if (!apiVersion.isNullOrBlank()) {
133-
val apiGroup = Helper.getAnnotationValue(clazz, Group::class.java)
134-
if (!apiGroup.isNullOrBlank()) {
135-
getApiVersion(apiGroup, apiVersion)
128+
val version = HasMetadata.getVersion(clazz)
129+
return if (!version.isNullOrBlank()) {
130+
val group = HasMetadata.getGroup(clazz)
131+
if (!group.isNullOrBlank()) {
132+
getApiVersion(group, version)
136133
} else {
137-
apiVersion
134+
version
138135
}
139136
} else {
140137
clazz.simpleName

src/test/kotlin/com/redhat/devtools/intellij/kubernetes/model/mocks/ClientMocks.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -130,15 +130,15 @@ object ClientMocks {
130130
) {
131131
val inNamespaceOp: Resource<HasMetadata> = mock {
132132
on { delete() } doReturn statusDetails
133-
on { replace() } doReturn resource
133+
on { patch() } doReturn resource
134134
on { create() } doReturn resource
135135
on { get() } doReturn resource
136136
}
137137
/** [KubernetesClient.resource] */
138138
val resourceOperation: NamespaceableResource<HasMetadata> = mock {
139139
on { inNamespace(any()) } doReturn inNamespaceOp
140140
on { delete() } doReturn statusDetails
141-
on { replace() } doReturn resource
141+
on { patch() } doReturn resource
142142
}
143143

144144
doReturn(resourceOperation)

src/test/kotlin/com/redhat/devtools/intellij/kubernetes/model/resource/kubernetes/NamespacedPodsOperatorTest.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ class NamespacedPodsOperatorTest {
381381
verify(client.get().adapt(KubernetesClient::class.java)
382382
.resource(toReplace)
383383
.inNamespace(toReplace.metadata.namespace))
384-
.replace()
384+
.patch()
385385
}
386386

387387
@Test
@@ -424,7 +424,7 @@ class NamespacedPodsOperatorTest {
424424
verify(client.get().adapt(KubernetesClient::class.java)
425425
.resource(toReplace)
426426
.inNamespace(toReplace.metadata.namespace))
427-
.replace()
427+
.patch()
428428
}
429429

430430
@Test
@@ -436,7 +436,7 @@ class NamespacedPodsOperatorTest {
436436
whenever(client.get().adapt(KubernetesClient::class.java)
437437
.resource(toReplace)
438438
.inNamespace(toReplace.metadata.namespace)
439-
.replace())
439+
.patch())
440440
.thenReturn(POD3)
441441
// when
442442
val newPod = operator.replace(toReplace)

0 commit comments

Comments
 (0)