Skip to content

Commit cb23184

Browse files
committed
fix: display kubeconfig parse error on startup (#809)
Signed-off-by: Andre Dietisheim <[email protected]>
1 parent 52ad428 commit cb23184

File tree

15 files changed

+565
-509
lines changed

15 files changed

+565
-509
lines changed

Diff for: gradle/libs.versions.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[versions]
22
# libraries
33
kubernetes-client = "7.0.0"
4-
devtools-common = "1.9.7-SNAPSHOT"
4+
devtools-common = "1.9.7"
55
jackson-core = "2.17.0"
66
commons-lang3 = "3.12.0"
77
assertj-core = "3.22.0"

Diff for: src/main/kotlin/com/redhat/devtools/intellij/kubernetes/actions/SetAsCurrentClusterAction.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ class SetAsCurrentClusterAction: StructureTreeAction(IContext::class.java) {
2525
val context: IContext = selectedNode?.getElement() ?: return
2626
val telemetry = TelemetryService.instance
2727
.action(NAME_PREFIX_CONTEXT + "switch")
28-
run("Setting ${context.context.name} as current cluster...", true,
28+
run("Setting ${context.name} as current cluster...", true,
2929
Progressive {
3030
try {
3131
getResourceModel()?.setCurrentContext(context)
3232
telemetry.success().send()
3333
} catch (e: Exception) {
3434
logger<SetAsCurrentClusterAction>().warn(
35-
"Could not set current context to ${context.context.name}.", e
35+
"Could not set current context to ${context.name}.", e
3636
)
3737
telemetry.error(e).send()
3838
}

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

+21-14
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import com.redhat.devtools.intellij.kubernetes.model.context.IActiveContext
2121
import com.redhat.devtools.intellij.kubernetes.model.context.IContext
2222
import com.redhat.devtools.intellij.kubernetes.model.resource.ResourceKind
2323
import com.redhat.devtools.intellij.kubernetes.model.util.ResettableLazyProperty
24+
import com.redhat.devtools.intellij.kubernetes.model.util.ResourceException
25+
import com.redhat.devtools.intellij.kubernetes.model.util.toMessage
2426
import com.redhat.devtools.intellij.kubernetes.telemetry.TelemetryService
2527
import com.redhat.devtools.intellij.kubernetes.telemetry.TelemetryService.NAME_PREFIX_CONTEXT
2628
import com.redhat.devtools.intellij.kubernetes.telemetry.TelemetryService.PROP_IS_OPENSHIFT
@@ -110,10 +112,13 @@ open class AllContexts(
110112
lock.write {
111113
if (_all.isEmpty()) {
112114
try {
113-
val all = createContexts(client.get(), client.get()?.config)
114-
_all.addAll(all)
115+
val client = client.get()
116+
if (client != null) {
117+
val all = createContexts(client, client.config)
118+
_all.addAll(all)
119+
}
115120
} catch (e: Exception) {
116-
//
121+
throw ResourceException("Config error: ${toMessage(e)}", e)
117122
}
118123
}
119124
return _all
@@ -124,7 +129,7 @@ open class AllContexts(
124129
if (current == context) {
125130
return current
126131
}
127-
val newClient = clientFactory.invoke(context.context.context.namespace, context.context.name)
132+
val newClient = clientFactory.invoke(context.namespace, context.name)
128133
val new = setCurrentContext(newClient, emptyList())
129134
if (new != null) {
130135
modelChange.fireAllContextsChanged()
@@ -134,7 +139,7 @@ open class AllContexts(
134139

135140
override fun setCurrentNamespace(namespace: String): IActiveContext<out HasMetadata, out KubernetesClient>? {
136141
val old = this.current ?: return null
137-
val newClient = clientFactory.invoke(namespace, old.context.name)
142+
val newClient = clientFactory.invoke(namespace, old.name)
138143
val new = setCurrentContext(newClient, old.getWatched())
139144
if (new != null) {
140145
modelChange.fireCurrentNamespaceChanged(new, old)
@@ -173,6 +178,7 @@ open class AllContexts(
173178
lock.write {
174179
this.current?.close()
175180
clearAllContexts() // latter access will cause reload
181+
client.reset()
176182
}
177183
modelChange.fireAllContextsChanged()
178184
}
@@ -244,20 +250,21 @@ open class AllContexts(
244250
* The latter gets closed/recreated whenever the context changes in
245251
* [com.redhat.devtools.intellij.kubernetes.model.client.KubeConfigAdapter].
246252
*/
247-
val watcher = ConfigWatcher { config: Config? -> onKubeConfigChanged(config) }
253+
val watcher = ConfigWatcher { config: Config?, error: Exception? -> onKubeConfigChanged(config, error) }
248254
runAsync(watcher::run)
249255
}
250256

251-
protected open fun onKubeConfigChanged(updated: Config?) {
257+
protected open fun onKubeConfigChanged(updated: Config?, error: Exception?) {
252258
lock.read {
253-
updated ?: return
254-
val client = client.get() ?: return
255-
val existing = client.config
256-
if (existing.isEqualConfig(updated)) {
257-
return
259+
if (error == null) {
260+
val client = client.get() ?: return
261+
val existing = client.config
262+
if (existing.isEqualConfig(updated)) {
263+
return
264+
}
265+
this.client.reset() // create new client when accessed
266+
client.close()
258267
}
259-
this.client.reset() // create new client when accessed
260-
client.close()
261268
}
262269
refresh()
263270
}

Diff for: src/main/kotlin/com/redhat/devtools/intellij/kubernetes/model/client/ClientConfig.kt

+4-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ open class ClientConfig(
6666
* @param config the [Config] to compare the adapted config in this class to.
6767
* @return true if the given config is equal to the one that this class adapts
6868
*/
69-
fun isEqualConfig(config: Config): Boolean {
69+
fun isEqualConfig(config: Config?): Boolean {
70+
if (config == null) {
71+
return false
72+
}
7073
return ConfigHelper.areEqualCurrentContext(config, this.config)
7174
&& ConfigHelper.areEqualContexts(config, this.config)
7275
&& ConfigHelper.areEqualCluster(config, this.config)

Diff for: src/main/kotlin/com/redhat/devtools/intellij/kubernetes/model/context/ActiveContext.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ abstract class ActiveContext<N : HasMetadata, C : KubernetesClient>(
487487
}
488488

489489
override fun close() {
490-
logger<ActiveContext<*, *>>().debug("Closing context ${context.name}.")
490+
logger<ActiveContext<*, *>>().debug("Closing context $name.")
491491
watch.close()
492492
dashboard.close()
493493
}

Diff for: src/main/kotlin/com/redhat/devtools/intellij/kubernetes/model/context/Context.kt

+15-3
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,25 @@
1010
******************************************************************************/
1111
package com.redhat.devtools.intellij.kubernetes.model.context
1212

13+
import com.redhat.devtools.intellij.kubernetes.model.util.toMessage
1314
import io.fabric8.kubernetes.api.model.NamedContext
1415

1516
interface IContext {
16-
val context: NamedContext
1717
val active: Boolean
18+
val name: String?
19+
val namespace: String?
1820
}
1921

20-
open class Context(override val context: NamedContext): IContext {
22+
open class Context(private val context: NamedContext): IContext {
2123
override val active: Boolean = false
22-
}
24+
override val name: String?
25+
get() = context.name
26+
override val namespace: String?
27+
get() = context.context?.namespace
28+
}
29+
30+
class KubeConfigError(error: Exception? = null): IContext {
31+
override val active: Boolean = false
32+
override val name: String = "Configuration error: ${toMessage(error)}"
33+
override val namespace: String? = null
34+
}

Diff for: src/main/kotlin/com/redhat/devtools/intellij/kubernetes/model/context/IActiveContext.kt

-4
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,6 @@ interface IActiveContext<N: HasMetadata, C: KubernetesClient>: IContext {
6565
}
6666
}
6767

68-
val name: String?
69-
get() {
70-
return context.name
71-
}
7268
/**
7369
* The master url for this context. This is the url of the cluster for this context.
7470
*/

Diff for: src/main/kotlin/com/redhat/devtools/intellij/kubernetes/model/util/ResettableLazyProperty.kt

+4
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,8 @@ open class ResettableLazyProperty<T>(private val initializer: () -> T?) {
3636
fun reset() {
3737
this.initialized = false
3838
}
39+
40+
fun isReset(): Boolean {
41+
return !initialized
42+
}
3943
}

Diff for: src/main/kotlin/com/redhat/devtools/intellij/kubernetes/tree/AbstractTreeStructureContribution.kt

+5-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,11 @@ abstract class AbstractTreeStructureContribution(override val model: IResourceMo
5151
abstract fun descriptorFactory(): (Any, ResourceKind<out HasMetadata>?, NodeDescriptor<*>?, IResourceModel, Project) -> NodeDescriptor<*>?
5252

5353
protected fun getRootElement(): Any? {
54-
return model.getCurrentContext()
54+
return try {
55+
model.getCurrentContext()
56+
} catch (e: Exception) {
57+
null
58+
}
5559
}
5660

5761
fun <T> element(initializer: ElementNode<T>.() -> Unit): ElementNode<T> {

Diff for: src/main/kotlin/com/redhat/devtools/intellij/kubernetes/tree/KubernetesDescriptors.kt

+7-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,13 @@ import javax.swing.Icon
5050

5151
object KubernetesDescriptors {
5252

53-
fun createDescriptor(element: Any, childrenKind: ResourceKind<out HasMetadata>?, parent: NodeDescriptor<*>?, model: IResourceModel, project: Project): NodeDescriptor<*>? {
53+
fun createDescriptor(
54+
element: Any,
55+
childrenKind: ResourceKind<out HasMetadata>?,
56+
parent: NodeDescriptor<*>?,
57+
model: IResourceModel,
58+
project: Project
59+
): NodeDescriptor<*>? {
5460
return when {
5561
element is DescriptorFactory<*> ->
5662
element.create(parent, model, project)

Diff for: src/main/kotlin/com/redhat/devtools/intellij/kubernetes/tree/TreeStructure.kt

+37-31
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,25 @@ open class TreeStructure(
6060

6161
override fun getChildElements(element: Any): Array<Any> {
6262
return when (element) {
63-
rootElement -> model.getAllContexts().toTypedArray()
63+
rootElement -> getAllContexts()
6464
else -> getValidContributions()
65-
.flatMap { getChildElements(element, it) }
66-
.toTypedArray()
65+
.flatMap { getChildElements(element, it) }
66+
.toTypedArray()
67+
}
68+
}
69+
70+
private fun getAllContexts(): Array<Any> {
71+
return try {
72+
model.getAllContexts().toTypedArray()
73+
} catch (e: Exception) {
74+
arrayOf(e)
6775
}
6876
}
6977

7078
private fun getChildElements(element: Any, contribution: ITreeStructureContribution): Collection<Any> {
7179
return try {
7280
contribution.getChildElements(element)
73-
} catch (e: java.lang.Exception) {
81+
} catch (e: Exception) {
7482
logger<TreeStructure>().warn(e)
7583
listOf(e)
7684
}
@@ -101,24 +109,30 @@ open class TreeStructure(
101109
}
102110

103111
override fun createDescriptor(element: Any, parent: NodeDescriptor<*>?): NodeDescriptor<*> {
104-
val descriptor: NodeDescriptor<*>? =
105-
getValidContributions()
106-
.map { it.createDescriptor(element, parent, project) }
107-
.find { it != null }
108-
if (descriptor != null) {
109-
return descriptor
110-
}
111-
return when (element) {
112-
is IContext -> ContextDescriptor(element, parent, model, project)
113-
is Exception -> ErrorDescriptor(element, parent, model, project)
114-
is Folder -> FolderDescriptor(element, parent, model, project)
115-
else -> Descriptor(element, null, parent, model, project)
112+
return try {
113+
val descriptor: NodeDescriptor<*>? = getValidContributions()
114+
.map { it.createDescriptor(element, parent, project) }
115+
.find { it != null }
116+
descriptor ?: when (element) {
117+
is IContext -> ContextDescriptor(element, parent, model, project)
118+
is Exception -> ErrorDescriptor(element, parent, model, project)
119+
is Folder -> FolderDescriptor(element, parent, model, project)
120+
else -> Descriptor(element, null, parent, model, project)
121+
}
122+
} catch (e: Exception) {
123+
ErrorDescriptor(e, parent, model, project)
116124
}
117125
}
118126

119127
private fun getValidContributions(): Collection<ITreeStructureContribution> {
120128
return contributions
121-
.filter { it.canContribute() }
129+
.filter {
130+
try {
131+
it.canContribute()
132+
} catch (e: Exception) {
133+
false
134+
}
135+
}
122136
}
123137

124138
private fun getTreeStructureExtensions(model: IResourceModel): List<ITreeStructureContribution> {
@@ -167,11 +181,7 @@ open class TreeStructure(
167181
project
168182
) {
169183
override fun getLabel(element: C?): String {
170-
return if (element?.context?.name == null) {
171-
"<unknown context>"
172-
} else {
173-
element.context.name
174-
}
184+
return element?.name ?: "<unknown context>"
175185
}
176186

177187
override fun getIcon(element: C): Icon? {
@@ -237,26 +247,22 @@ open class TreeStructure(
237247
}
238248

239249
private class ErrorDescriptor(
240-
exception: java.lang.Exception,
250+
exception: Exception,
241251
parent: NodeDescriptor<*>?,
242252
model: IResourceModel,
243253
project: Project
244-
) : Descriptor<java.lang.Exception>(
254+
) : Descriptor<Exception>(
245255
exception,
246256
null,
247257
parent,
248258
model,
249259
project
250260
) {
251-
override fun getLabel(element: java.lang.Exception?): String {
252-
return getMessage(element)
253-
}
254-
255-
private fun getMessage(e: Exception?): String {
256-
return toMessage(e)
261+
override fun getLabel(element: Exception?): String {
262+
return toMessage(element)
257263
}
258264

259-
override fun getIcon(element: java.lang.Exception): Icon {
265+
override fun getIcon(element: Exception): Icon {
260266
return AllIcons.General.BalloonError
261267
}
262268
}

Diff for: src/main/kotlin/com/redhat/devtools/intellij/kubernetes/tree/TreeUpdater.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ class TreeUpdater(
123123
}
124124
}
125125

126-
private fun isRootNode(element: Any?): Boolean {
126+
private fun isRootElement(element: Any?): Boolean {
127127
val descriptor = (treeModel.root as? DefaultMutableTreeNode)?.userObject as? NodeDescriptor<*>
128128
return element == descriptor?.element
129129
}
@@ -150,7 +150,7 @@ class TreeUpdater(
150150
private fun findNodes(element: Any?): Collection<TreeNode> {
151151
return if (element == null) {
152152
emptyList()
153-
} else if (isRootNode(element)) {
153+
} else if (isRootElement(element)) {
154154
listOf(treeModel.root)
155155
} else {
156156
findNodes({ node: TreeNode -> hasElement(element, node) }, treeModel.root)

0 commit comments

Comments
 (0)