Skip to content

Commit

Permalink
feat: Add DevSpaces gateway plugin
Browse files Browse the repository at this point in the history
Signed-off-by: Anatolii Bazko <[email protected]>
  • Loading branch information
tolusha committed Feb 12, 2024
1 parent 71098f6 commit 94b96d5
Show file tree
Hide file tree
Showing 21 changed files with 834 additions and 45 deletions.
3 changes: 3 additions & 0 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import org.jetbrains.changelog.Changelog
import org.jetbrains.changelog.markdownToHTML
import org.jetbrains.kotlin.ir.backend.js.compile

Check warning on line 3 in build.gradle.kts

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused import directive

Unused import directive

fun properties(key: String) = providers.gradleProperty(key)
fun environment(key: String) = providers.environmentVariable(key)
Expand All @@ -23,7 +24,9 @@ repositories {

// Dependencies are managed with Gradle version catalog - read more: https://docs.gradle.org/current/userguide/platforms.html#sub:version-catalog
dependencies {
// implementation(libs.annotations)
implementation("io.kubernetes:client-java:18.0.1")
implementation("io.fabric8:openshift-client:6.10.0")
implementation("io.fabric8:openshift-client-api:6.10.0")
}

// Set the JVM language level used to build the project. Use Java 11 for 2020.3+, and Java 17 for 2022.2+.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,22 @@
*/
package com.github.devspaces.gateway

import com.github.devspaces.gateway.help.DEVSPACES_DOC_LINK
import com.github.devspaces.gateway.view.DevSpacesMainView
import com.jetbrains.gateway.api.GatewayConnector
import com.jetbrains.gateway.api.GatewayConnectorDocumentationPage
import com.jetbrains.gateway.api.GatewayConnectorView
import com.jetbrains.rd.util.lifetime.Lifetime
import javax.swing.Icon

class DevSpacesConnector : GatewayConnector {
override fun getConnectorId() = "devspaces.connector"
override fun getConnectorId() = "devspaces.gateway.connector"

override val icon: Icon
get() = DevSpacesIcons.LOGO

override fun createView(lifetime: Lifetime): GatewayConnectorView {
return DevSpacesView()
return DevSpacesMainView()
}

override fun getActionText(): String {
Expand All @@ -35,10 +37,7 @@ class DevSpacesConnector : GatewayConnector {
return DevSpacesBundle.message("connector.description")

Check warning on line 37 in src/main/kotlin/com/github/devspaces/gateway/DevSpacesConnector.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Incorrect string capitalization

String 'Connects to a Dev Spaces Workspace' is not properly capitalized. It should have sentence capitalization
}

override fun getDocumentationAction() = GatewayConnectorDocumentationPage("https://access.redhat.com/documentation/en-us/red_hat_openshift_dev_spaces")

// override fun getRecentConnections(setContentCallback: (Component) -> Unit): GatewayRecentConnections {
// }
override fun getDocumentationAction() = GatewayConnectorDocumentationPage(DEVSPACES_DOC_LINK)

override fun getTitle(): String {
return DevSpacesBundle.message("connector.title")
Expand Down
38 changes: 0 additions & 38 deletions src/main/kotlin/com/github/devspaces/gateway/DevSpacesView.kt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright (c) 2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package com.github.devspaces.gateway.help

const val DEVSPACES_DOC_LINK = "https://access.redhat.com/documentation/en-us/red_hat_openshift_dev_spaces"

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright (c) 2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package com.github.devspaces.gateway.openshift

import io.kubernetes.client.openapi.ApiClient

class DevSpacesContext() {

Check notice on line 16 in src/main/kotlin/com/github/devspaces/gateway/openshift/DevSpacesContext.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Redundant empty primary constructor

Remove empty primary constructor
lateinit var client: ApiClient
lateinit var devWorkspace: Any
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package com.github.devspaces.gateway.openshift

import io.kubernetes.client.openapi.models.V1Pod
import java.io.IOException

class DevSpacesGatewayConnection(private val devSpacesContext: DevSpacesContext) {
@Throws(Exception::class)
fun connect() {
val name = Utils.getValue(devSpacesContext.devWorkspace, arrayOf("metadata", "name")) as String
val namespace = Utils.getValue(devSpacesContext.devWorkspace, arrayOf("metadata", "namespace")) as String

val podList = Pods(devSpacesContext.client).list(
namespace,
String.format("controller.devfile.io/devworkspace_name=%s", name)
)

if (podList.items.size != 1) throw IOException(String.format("Expected 1 pod, but found %d", podList.items.size))
val pod = podList.items[0]

val connectionURI = getConnectionURI(pod)
if (connectionURI == "") throw IOException("Connection URI not found")

val devSpacesPortForward = DevSpacesPortForward(devSpacesContext.client)
devSpacesPortForward.start(pod)

// TODO CONNECT
}

private fun getConnectionURI(pod: V1Pod): String {
for (container in pod.spec?.containers!!) {
try {
val result = Exec(devSpacesContext.client).run(
pod,
arrayOf("grep", "-Eo", "-m1", "tcp://.*", "/idea-server/std.out"),
container.name
)
if (result != "") return result
} catch (e: Exception) {
continue
}
}

return ""
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package com.github.devspaces.gateway.openshift

import io.kubernetes.client.PortForward
import io.kubernetes.client.openapi.ApiClient
import io.kubernetes.client.openapi.Configuration
import io.kubernetes.client.openapi.models.V1Pod
import io.kubernetes.client.util.Streams
import java.net.ServerSocket


// Sample:
// https://github.com/kubernetes-client/java/blob/master/examples/examples-release-19/src/main/java/io/kubernetes/client/examples/PortForwardExample.java
class DevSpacesPortForward(private val client: ApiClient) {
private val port = 5990
private lateinit var toLocalFromRemoteThread: Thread
private lateinit var fromLocalToRemoteThread: Thread
fun start(pod: V1Pod) {
Configuration.setDefaultApiClient(client)
val forwarding = PortForward().forward(
pod.metadata?.namespace,
pod.metadata?.name,
arrayListOf(port)
)

val serverSocket = ServerSocket(port)
val socket = serverSocket.accept()

toLocalFromRemoteThread = Thread {
Streams.copy(forwarding.getInputStream(port), socket.getOutputStream())
}

fromLocalToRemoteThread = Thread {
Streams.copy(socket.getInputStream(), forwarding.getOutboundStream(port))
}

toLocalFromRemoteThread.start()
fromLocalToRemoteThread.start()
}

fun stop() {

Check warning on line 51 in src/main/kotlin/com/github/devspaces/gateway/openshift/DevSpacesPortForward.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused symbol

Function "stop" is never used
toLocalFromRemoteThread.interrupt()
fromLocalToRemoteThread.interrupt()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package com.github.devspaces.gateway.openshift

import io.kubernetes.client.openapi.ApiClient
import io.kubernetes.client.openapi.ApiException
import io.kubernetes.client.openapi.apis.CustomObjectsApi

class DevWorkspaces(private val client: ApiClient) {
@Throws(ApiException::class)
fun list(namespace: String): Any {
val customApi = CustomObjectsApi(client)
return customApi.listNamespacedCustomObject(
"workspace.devfile.io",
"v1alpha2",
namespace,
"devworkspaces",
"false",
false,
"",
"",
"",
-1,
"",
"",
-1,
false
)
}
}
43 changes: 43 additions & 0 deletions src/main/kotlin/com/github/devspaces/gateway/openshift/Exec.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package com.github.devspaces.gateway.openshift

import io.kubernetes.client.Exec
import io.kubernetes.client.openapi.ApiClient
import io.kubernetes.client.openapi.Configuration
import io.kubernetes.client.openapi.models.V1Pod
import io.kubernetes.client.util.Streams
import java.io.ByteArrayOutputStream


// Sample:
// https://github.com/kubernetes-client/java/blob/master/examples/examples-release-19/src/main/java/io/kubernetes/client/examples/ExecExample.java
class Exec(private val client: ApiClient) {
fun run(pod: V1Pod, command: Array<String>, container: String): String {
val output = ByteArrayOutputStream()

Configuration.setDefaultApiClient(client)
val process = Exec().exec(pod, command, container, false, false)

val copyOutputThread =
Thread {
Streams.copy(process.inputStream, output)
}
copyOutputThread.start()

process.waitFor()
copyOutputThread.join()
process.destroy()

return output.toString()
}
}
Loading

0 comments on commit 94b96d5

Please sign in to comment.