Skip to content

Commit

Permalink
retrieve resources in bkground, check if editor is authorized (#622, #…
Browse files Browse the repository at this point in the history
…621, #618)

Signed-off-by: Andre Dietisheim <[email protected]>
  • Loading branch information
adietish committed Jul 18, 2023
1 parent 855c035 commit 3c6ab10
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import com.redhat.devtools.intellij.kubernetes.model.util.ResourceException
import com.redhat.devtools.intellij.kubernetes.model.util.areEqual
import com.redhat.devtools.intellij.kubernetes.model.util.isNotFound
import com.redhat.devtools.intellij.kubernetes.model.util.isSameResource
import com.redhat.devtools.intellij.kubernetes.model.util.isUnauthorized
import com.redhat.devtools.intellij.kubernetes.model.util.isUnsupported
import io.fabric8.kubernetes.api.model.HasMetadata
import io.fabric8.kubernetes.client.KubernetesClient
Expand Down Expand Up @@ -192,6 +193,25 @@ open class ClusterResource protected constructor(
&& e.isUnsupported())
}

/**
* Returns `true` if this [ClusterResource] is authorized. Returns `false` otherwise.
*
* @return true if this ClusterResource is authorized
*
* @see HasMetadata.getKind
* @see HasMetadata.getApiVersion
*/
fun isAuthorized(): Boolean {
val e = try {
pull()
null
} catch(re: ResourceException) {
re.cause
}
return !(e is KubernetesClientException
&& e.isUnauthorized())
}

fun isDeleted(): Boolean {
synchronized(this) {
return isDeleted
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ open class EditorResource(
!isSupported() ->
Error("Unsupported kind ${resource.kind} in version ${resource.apiVersion}")

!isAuthorized() ->
Error("Authentication with cluster failed. Verify username and password, refresh token, etc.")

!hasName(resource)
&& !hasGenerateName(resource) ->
Error("Resource has neither name nor generateName.", null as String?)
Expand Down Expand Up @@ -271,6 +274,10 @@ open class EditorResource(
return clusterResource?.isSupported() ?: false
}

private fun isAuthorized(): Boolean {
return clusterResource?.isAuthorized() ?: false
}

/**
* Returns `true` if the given resource has changes that don't exist in the resource
* that was last pulled/pushed from/to the cluster.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,13 @@ import com.redhat.devtools.intellij.kubernetes.editor.util.getDocument
import com.redhat.devtools.intellij.kubernetes.editor.util.isKubernetesResource
import com.redhat.devtools.intellij.kubernetes.model.IResourceModel
import com.redhat.devtools.intellij.kubernetes.model.IResourceModelListener
import com.redhat.devtools.intellij.kubernetes.model.Notification
import com.redhat.devtools.intellij.kubernetes.model.context.IActiveContext
import com.redhat.devtools.intellij.kubernetes.model.util.KubernetesClientExceptionUtils.statusMessage
import com.redhat.devtools.intellij.kubernetes.model.util.ResourceException
import com.redhat.devtools.intellij.kubernetes.model.util.toMessage
import com.redhat.devtools.intellij.kubernetes.model.util.toTitle
import com.redhat.devtools.intellij.kubernetes.model.util.trimWithEllipsis
import io.fabric8.kubernetes.api.model.HasMetadata

/**
Expand Down Expand Up @@ -299,11 +303,39 @@ open class ResourceEditor(
fun diff() {
val manager = getPsiDocumentManager.invoke(project)
val file = editor.file ?: return
var fileType: FileType? = null
var beforeDiff: String? = null
runInUI {
val document = getDocument.invoke(editor) ?: return@runInUI
val resourcesOnCluster = editorResources.getAllResourcesOnCluster()
val serialized = serialize(resourcesOnCluster, getFileType(document, manager)) ?: return@runInUI
diff.open(file, serialized) { onDiffClosed(document.text) }
fileType = getFileType(document, manager) ?: return@runInUI
beforeDiff = document.text
}
if (fileType == null
|| beforeDiff == null
) {
return
}
runAsync {
try {
val resourcesOnCluster = editorResources.getAllResourcesOnCluster()
val serialized = serialize(resourcesOnCluster, fileType) ?: return@runAsync
runInUI {
diff.open(file, serialized) { onDiffClosed(beforeDiff) }
}
} catch(e: ResourceException) {
val message = trimWithEllipsis(e.message, 100)
val causeMessage = statusMessage(e.cause)
Notification()
.error("Could not open diff",
if (causeMessage == null) {
message ?: ""
} else if (message == null) {
causeMessage
} else {
"$message: $causeMessage"
}
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*******************************************************************************
* Copyright (c) 2023 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 com.redhat.devtools.intellij.kubernetes.model.util

import io.fabric8.kubernetes.api.model.Status
import io.fabric8.kubernetes.client.KubernetesClientException

object KubernetesClientExceptionUtils {

fun statusMessage(t: Throwable?): String? {
return status(t)?.message
}

fun status(t: Throwable?): Status? {
return if (t is KubernetesClientException) {
t.status
} else {
null
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ class EditorResourceTest {
assertThat(editorResource.getState()).isNotInstanceOf(Pushed::class.java)
doReturn(true)
.whenever(clusterResource).isSupported()
doReturn(true)
.whenever(clusterResource).isAuthorized()
doReturn(true) // after a push: resource exists on cluster
.whenever(clusterResource).exists()
doReturn(false) // after a push: resource is not deleted on cluster
Expand All @@ -187,6 +189,8 @@ class EditorResourceTest {
val editorResource = createEditorResource(POD2)
doReturn(true)
.whenever(clusterResource).isSupported()
doReturn(true)
.whenever(clusterResource).isAuthorized()
assertThat(editorResource.getState()).isNotInstanceOf(Error::class.java)
doThrow(ResourceException("interference with the force"))
.whenever(clusterResource).push(any())
Expand Down Expand Up @@ -250,6 +254,8 @@ class EditorResourceTest {
assertThat(editorResource.getState()).isNotInstanceOf(Pushed::class.java)
doReturn(true)
.whenever(clusterResource).isSupported()
doReturn(true)
.whenever(clusterResource).isAuthorized()
doReturn(true) // after a pull: resource exists on cluster
.whenever(clusterResource).exists()
doReturn(false) // after a pull: resource is not deleted on cluster
Expand All @@ -269,6 +275,8 @@ class EditorResourceTest {
editorResource.setLastPushedPulled(POD2) // not modified
doReturn(true)
.whenever(clusterResource).isSupported()
doReturn(true)
.whenever(clusterResource).isAuthorized()
assertThat(editorResource.getState()).isNotInstanceOf(Error::class.java)
doThrow(ResourceException("interference with the force"))
.whenever(clusterResource).pull(any())
Expand All @@ -287,6 +295,8 @@ class EditorResourceTest {
editorResource.setLastPushedPulled(POD2) // modified = (current resource != lastPushedPulled)
doReturn(true)
.whenever(clusterResource).isSupported()
doReturn(true)
.whenever(clusterResource).isAuthorized()
// when
val state = editorResource.getState()
// then
Expand All @@ -298,6 +308,8 @@ class EditorResourceTest {
// given
doReturn(true)
.whenever(clusterResource).isSupported()
doReturn(true)
.whenever(clusterResource).isAuthorized()
val editorResource = createEditorResource(POD2)
val error = Error("oh my!")
editorResource.setState(error)
Expand Down Expand Up @@ -348,6 +360,8 @@ class EditorResourceTest {
val editorResource = createEditorResource(resource)
doReturn(true)
.whenever(clusterResource).isSupported()
doReturn(true)
.whenever(clusterResource).isAuthorized()
// when
val state = editorResource.getState()
// then
Expand All @@ -366,6 +380,8 @@ class EditorResourceTest {
val editorResource = createEditorResource(resource)
doReturn(true)
.whenever(clusterResource).isSupported()
doReturn(true)
.whenever(clusterResource).isAuthorized()
// when
val state = editorResource.getState()
// then
Expand All @@ -378,6 +394,8 @@ class EditorResourceTest {
val editorResource = createEditorResource(POD2)
doReturn(true)
.whenever(clusterResource).isSupported()
doReturn(true)
.whenever(clusterResource).isAuthorized()
doReturn(true)
.whenever(clusterResource).isDeleted()
// when
Expand All @@ -392,6 +410,8 @@ class EditorResourceTest {
val editorResource = createEditorResource(POD2)
doReturn(true)
.whenever(clusterResource).isSupported()
doReturn(true)
.whenever(clusterResource).isAuthorized()
doReturn(false)
.whenever(clusterResource).exists()
// when
Expand All @@ -406,6 +426,8 @@ class EditorResourceTest {
// given
doReturn(true)
.whenever(clusterResource).isSupported()
doReturn(true)
.whenever(clusterResource).isAuthorized()
doReturn(true) // don't create modified state because it doesnt exist on cluster
.whenever(clusterResource).exists()
val editorResource = createEditorResource(POD2)
Expand All @@ -428,6 +450,8 @@ class EditorResourceTest {
val editorResource = createEditorResource(POD2)
doReturn(true)
.whenever(clusterResource).isSupported()
doReturn(true)
.whenever(clusterResource).isAuthorized()
doReturn(true)
.whenever(clusterResource).isOutdatedVersion(any())
doReturn(true) // don't return modified state because it doesnt exist
Expand All @@ -445,6 +469,8 @@ class EditorResourceTest {
val editorResource = createEditorResource(POD2)
doReturn(true)
.whenever(clusterResource).isSupported()
doReturn(true)
.whenever(clusterResource).isAuthorized()
doReturn(true)
.whenever(clusterResource).isOutdatedVersion(any())
doReturn(true) // don't return modified state because it doesnt exist
Expand All @@ -457,6 +483,32 @@ class EditorResourceTest {
assertThat(state).isInstanceOf(Error::class.java)
}

@Test
fun `#getState should return Error if resource is NOT supported on cluster`() {
// given
val editorResource = createEditorResource(POD2)
doReturn(false)
.whenever(clusterResource).isSupported()
// when
val state = editorResource.getState()
// then
assertThat(state).isInstanceOf(Error::class.java)
}

@Test
fun `#getState should return Error if cluster is not authorized`() {
// given
val editorResource = createEditorResource(POD2)
doReturn(true)
.whenever(clusterResource).isSupported()
doReturn(false)
.whenever(clusterResource).isAuthorized()
// when
val state = editorResource.getState()
// then
assertThat(state).isInstanceOf(Error::class.java)
}

@Test
fun `#dispose should close clusterResource that was created`() {
// given
Expand Down

0 comments on commit 3c6ab10

Please sign in to comment.