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

feat: Add DevSpaces gateway plugin #16

Merged
merged 1 commit into from
Feb 12, 2024
Merged
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: 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 @@

// 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 @@ -32,13 +34,10 @@
}

override fun getDescription(): String {
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
Loading