From 74d451c9a5db49030c7312a9180308b94f789c4e Mon Sep 17 00:00:00 2001 From: "Cornelius A. Ludmann" Date: Mon, 25 Oct 2021 09:51:06 +0000 Subject: [PATCH] [ide] Add JetBrains IDE images --- .werft/build.ts | 3 +- .werft/build.yaml | 3 + chart/templates/server-ide-configmap.yaml | 17 +++- chart/values.yaml | 5 ++ components/BUILD.yaml | 3 +- .../ide/jetbrains/backend-plugin/.project | 2 +- .../ide/jetbrains/backend-plugin/BUILD.yaml | 3 + components/ide/jetbrains/image/BUILD.yaml | 52 ++++++++++++ .../ide/jetbrains/image/leeway.Dockerfile | 23 ++++++ components/ide/jetbrains/image/startup.sh | 16 ++++ components/ide/jetbrains/image/status/go.mod | 3 + components/ide/jetbrains/image/status/main.go | 81 +++++++++++++++++++ .../image/supervisor-ide-config_goland.json | 11 +++ .../image/supervisor-ide-config_intellij.json | 11 +++ 14 files changed, 229 insertions(+), 4 deletions(-) create mode 100644 components/ide/jetbrains/image/BUILD.yaml create mode 100644 components/ide/jetbrains/image/leeway.Dockerfile create mode 100755 components/ide/jetbrains/image/startup.sh create mode 100644 components/ide/jetbrains/image/status/go.mod create mode 100644 components/ide/jetbrains/image/status/main.go create mode 100644 components/ide/jetbrains/image/supervisor-ide-config_goland.json create mode 100644 components/ide/jetbrains/image/supervisor-ide-config_intellij.json diff --git a/.werft/build.ts b/.werft/build.ts index 478c27c3ac3176..310577e78634dc 100644 --- a/.werft/build.ts +++ b/.werft/build.ts @@ -148,7 +148,8 @@ export async function build(context, version) { if (withContrib || publishRelease) { exec(`leeway build --docker-build-options network=host --werft=true -c remote ${dontTest ? '--dont-test' : ''} -Dversion=${version} -DimageRepoBase=${imageRepo} contrib:all`); } - exec(`leeway build --docker-build-options network=host --werft=true -c remote ${retag} --coverage-output-path=${coverageOutput} -Dversion=${version} -DremoveSources=false -DimageRepoBase=${imageRepo} -DlocalAppVersion=${localAppVersion} -DnpmPublishTrigger=${publishToNpm ? Date.now() : 'false'}`); + const jetbrainsArgs = `-DINTELLIJ_PLUGIN_PLATFORM_VERSION=${process.env.INTELLIJ_PLUGIN_PLATFORM_VERSION} -DINTELLIJ_BACKEND_URL=${process.env.INTELLIJ_BACKEND_URL} -DGOLAND_BACKEND_URL=${process.env.GOLAND_BACKEND_URL}`; + exec(`leeway build --docker-build-options network=host --werft=true -c remote ${retag} --coverage-output-path=${coverageOutput} -Dversion=${version} -DremoveSources=false -DimageRepoBase=${imageRepo} -DlocalAppVersion=${localAppVersion} ${jetbrainsArgs} -DnpmPublishTrigger=${publishToNpm ? Date.now() : 'false'}`); if (publishRelease) { try { werft.phase("publish", "checking version semver compliance..."); diff --git a/.werft/build.yaml b/.werft/build.yaml index 49c58b9468ea2e..7f24c32c1048f3 100644 --- a/.werft/build.yaml +++ b/.werft/build.yaml @@ -138,6 +138,9 @@ pod: secretKeyRef: name: codecov key: token + envFrom: + - secretRef: + name: jetbrains-secrets command: - bash - -c diff --git a/chart/templates/server-ide-configmap.yaml b/chart/templates/server-ide-configmap.yaml index c5ede8825d6b21..6d7c905552156f 100644 --- a/chart/templates/server-ide-configmap.yaml +++ b/chart/templates/server-ide-configmap.yaml @@ -18,6 +18,20 @@ {{ template "gitpod.comp.imageRepo" . }}:{{- $comp.insidersVersion | default (include "gitpod.comp.version" .) -}} {{- end -}} +{{- define "ide-images-aliases"}} +{{- $ := .root -}} +{{- $gp := .gp -}} +code: {{ (include "stable-image-full" (dict "root" $ "gp" $gp "comp" $gp.components.workspace.codeImage)) }} +code-latest: {{ (include "insider-image-full" (dict "root" $ "gp" $gp "comp" $gp.components.workspace.codeImage)) }} +{{ end }} + +{{- define "desktop-ide-images-aliases"}} +{{- $ := .root -}} +{{- $gp := .gp -}} +intellij: {{ (include "gitpod.comp.imageFull" (dict "root" $ "gp" $gp "comp" $gp.components.workspace.desktopIdeImages.intellij)) }} +goland: {{ (include "gitpod.comp.imageFull" (dict "root" $ "gp" $gp "comp" $gp.components.workspace.desktopIdeImages.goland)) }} +{{ end }} + {{- if $comp.serverIdeConfigDeploy.enabled }} apiVersion: v1 kind: ConfigMap @@ -33,6 +47,7 @@ data: { "ideVersion": "{{ .Values.components.workspace.codeImage.stableVersion }}", "ideImageRepo": "{{ template "gitpod.comp.imageRepo" (dict "root" . "gp" $.Values "comp" .Values.components.workspace.codeImage) }}", - "ideImageAliases": {{ (dict "code-latest" (include "insider-image-full" (dict "root" . "gp" $.Values "comp" .Values.components.workspace.codeImage)) "code" (include "stable-image-full" (dict "root" . "gp" $.Values "comp" .Values.components.workspace.codeImage))) | toJson }} + "ideImageAliases": {{ (include "ide-images-aliases" (dict "root" . "gp" $.Values)) | fromYaml | toJson }}, + "desktopIdeImageAliases": {{ (include "desktop-ide-images-aliases" (dict "root" . "gp" $.Values)) | fromYaml | toJson }} } {{- end }} \ No newline at end of file diff --git a/chart/values.yaml b/chart/values.yaml index 9aa89a58efffe9..4d4cc6d338ae92 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -401,6 +401,11 @@ components: imageName: "ide/code" stableVersion: "commit-7107fb8bde0b1f92265402ad5fa09a51022b14dd" insidersVersion: "nightly" + desktopIdeImages: + intellij: + imageName: "ide/intellij" + goland: + imageName: "ide/goland" supervisor: imageName: "supervisor" dockerUp: diff --git a/components/BUILD.yaml b/components/BUILD.yaml index 19520e546e3b11..2c9129acaa6498 100644 --- a/components/BUILD.yaml +++ b/components/BUILD.yaml @@ -14,7 +14,6 @@ packages: - dev:all-app - installer:app - components/gitpod-protocol:all - - components/ide/jetbrains/backend-plugin:plugin - operations/observability/mixins:lint - name: docker-versions type: docker @@ -41,6 +40,8 @@ packages: - components/ee/ws-scheduler:docker - components/gitpod-db:docker - components/ide/code:docker + - components/ide/jetbrains/image:intellij + - components/ide/jetbrains/image:goland - components/ide/theia:docker - components/image-builder:docker - components/image-builder-mk3:docker diff --git a/components/ide/jetbrains/backend-plugin/.project b/components/ide/jetbrains/backend-plugin/.project index 955f47e5756f9c..13196d8ceedd00 100644 --- a/components/ide/jetbrains/backend-plugin/.project +++ b/components/ide/jetbrains/backend-plugin/.project @@ -22,7 +22,7 @@ - 1634286379907 + 0 30 diff --git a/components/ide/jetbrains/backend-plugin/BUILD.yaml b/components/ide/jetbrains/backend-plugin/BUILD.yaml index cd80adfbe4f42b..1925b6085b2bc1 100644 --- a/components/ide/jetbrains/backend-plugin/BUILD.yaml +++ b/components/ide/jetbrains/backend-plugin/BUILD.yaml @@ -11,8 +11,11 @@ packages: - "gradle/wrapper/*" - "gradlew" - "settings.gradle.kts" + argdeps: + - INTELLIJ_PLUGIN_PLATFORM_VERSION env: - JAVA_HOME=/home/gitpod/.sdkman/candidates/java/current + - INTELLIJ_PLUGIN_PLATFORM_VERSION=${INTELLIJ_PLUGIN_PLATFORM_VERSION} config: commands: - ["./gradlew", "-PsupervisorApiProjectPath=components-supervisor-api-java--lib/", "-PgitpodProtocolProjectPath=components-gitpod-protocol-java--lib/", "buildPlugin"] diff --git a/components/ide/jetbrains/image/BUILD.yaml b/components/ide/jetbrains/image/BUILD.yaml new file mode 100644 index 00000000000000..d298e609ae61b6 --- /dev/null +++ b/components/ide/jetbrains/image/BUILD.yaml @@ -0,0 +1,52 @@ +packages: + - name: docker + type: generic + argdeps: + - version + deps: + - :intellij + - :goland + - name: intellij + type: docker + srcs: + - "startup.sh" + - "supervisor-ide-config_intellij.json" + - "status/go.mod" + - "status/main.go" + deps: + - components/ide/jetbrains/backend-plugin:plugin + argdeps: + - imageRepoBase + - INTELLIJ_BACKEND_URL + config: + dockerfile: leeway.Dockerfile + metadata: + helm-component: workspace.desktopIdeImages.intellij + buildArgs: + JETBRAINS_BACKEND_URL: ${INTELLIJ_BACKEND_URL} + SUPERVISOR_IDE_CONFIG: supervisor-ide-config_intellij.json + image: + - ${imageRepoBase}/ide/intellij:${version} + - ${imageRepoBase}/ide/intellij:commit-${__git_commit} + - name: goland + type: docker + srcs: + - "startup.sh" + - "supervisor-ide-config_goland.json" + - "status/go.mod" + - "status/main.go" + deps: + - components/ide/jetbrains/backend-plugin:plugin + argdeps: + - imageRepoBase + - GOLAND_BACKEND_URL + config: + dockerfile: leeway.Dockerfile + metadata: + helm-component: workspace.desktopIdeImages.goland + buildArgs: + JETBRAINS_BACKEND_URL: ${GOLAND_BACKEND_URL} + SUPERVISOR_IDE_CONFIG: supervisor-ide-config_goland.json + image: + - ${imageRepoBase}/ide/goland:${version} + - ${imageRepoBase}/ide/goland:commit-${__git_commit} diff --git a/components/ide/jetbrains/image/leeway.Dockerfile b/components/ide/jetbrains/image/leeway.Dockerfile new file mode 100644 index 00000000000000..f7cd98c44f1e94 --- /dev/null +++ b/components/ide/jetbrains/image/leeway.Dockerfile @@ -0,0 +1,23 @@ +# Copyright (c) 2021 Gitpod GmbH. All rights reserved. +# Licensed under the GNU Affero General Public License (AGPL). +# See License-AGPL.txt in the project root for license information. + +FROM golang:1.17 AS build +WORKDIR /app +COPY status/* /app/ +RUN go build -o status + +FROM alpine:3.14 as download +ARG JETBRAINS_BACKEND_URL +WORKDIR /workdir +RUN apk add --no-cache --upgrade curl gzip tar unzip +RUN curl -sSLo backend.tar.gz "$JETBRAINS_BACKEND_URL" && tar -xf backend.tar.gz --strip-components=1 && rm backend.tar.gz +COPY --chown=33333:33333 components-ide-jetbrains-backend-plugin--plugin/build/distributions/jetbrains-backend-plugin-1.0-SNAPSHOT.zip /workdir +RUN unzip jetbrains-backend-plugin-1.0-SNAPSHOT.zip -d plugins/ && rm jetbrains-backend-plugin-1.0-SNAPSHOT.zip + +FROM scratch +ARG SUPERVISOR_IDE_CONFIG +COPY --chown=33333:33333 ${SUPERVISOR_IDE_CONFIG} /ide-desktop/supervisor-ide-config.json +COPY --chown=33333:33333 startup.sh /ide-desktop/ +COPY --chown=33333:33333 --from=build /app/status /ide-desktop/ +COPY --chown=33333:33333 --from=download /workdir/ /ide-desktop/backend/ diff --git a/components/ide/jetbrains/image/startup.sh b/components/ide/jetbrains/image/startup.sh new file mode 100755 index 00000000000000..014cf1906bb4ca --- /dev/null +++ b/components/ide/jetbrains/image/startup.sh @@ -0,0 +1,16 @@ +#!/bin/bash -li +# Copyright (c) 2021 Gitpod GmbH. All rights reserved. +# Licensed under the GNU Affero General Public License (AGPL). +# See License-AGPL.txt in the project root for license information. + +set -euo pipefail + +# kill background jobs when the script exits +trap "jobs -p | xargs -r kill" SIGINT SIGTERM EXIT + +/ide-desktop/status 24000 "$1" & + +export CWM_NON_INTERACTIVE=1 +export CWM_HOST_PASSWORD=gitpod +export CWM_HOST_STATUS_OVER_HTTP_TOKEN=gitpod +/ide-desktop/backend/bin/remote-dev-server.sh cwmHost "$GITPOD_REPO_ROOT" diff --git a/components/ide/jetbrains/image/status/go.mod b/components/ide/jetbrains/image/status/go.mod new file mode 100644 index 00000000000000..9f8e692f627b16 --- /dev/null +++ b/components/ide/jetbrains/image/status/go.mod @@ -0,0 +1,3 @@ +module github.com/gitpod-io/gitpod/jetbrains/status + +go 1.17 diff --git a/components/ide/jetbrains/image/status/main.go b/components/ide/jetbrains/image/status/main.go new file mode 100644 index 00000000000000..d99ff3cb06d06e --- /dev/null +++ b/components/ide/jetbrains/image/status/main.go @@ -0,0 +1,81 @@ +// Copyright (c) 2021 Gitpod GmbH. All rights reserved. +// Licensed under the GNU Affero General Public License (AGPL). +// See License-AGPL.txt in the project root for license information. + +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + "time" +) + +// proxy for the Code With Me status endpoints that transforms it into the supervisor status format. +func main() { + if len(os.Args) < 2 { + fmt.Printf("Usage: %s []\n", os.Args[0]) + os.Exit(1) + } + port := os.Args[1] + label := "Open JetBrains IDE" + if len(os.Args) > 2 { + label = os.Args[2] + } + + http.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) { + var ( + url = "http://localhost:63342/codeWithMe/unattendedHostStatus?token=gitpod" + client = http.Client{Timeout: 1 * time.Second} + ) + resp, err := client.Get(url) + if err != nil { + http.Error(w, err.Error(), http.StatusServiceUnavailable) + return + } + defer resp.Body.Close() + + bodyBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + http.Error(w, err.Error(), http.StatusServiceUnavailable) + return + } + + if resp.StatusCode != http.StatusOK { + // log.Printf("Desktop IDE status proxy: getting non-200 status - %d\n%s\n", resp.StatusCode, bodyBytes) + http.Error(w, string(bodyBytes), resp.StatusCode) + return + } + + type Projects struct { + JoinLink string `json:"joinLink"` + } + type Response struct { + Projects []Projects `json:"projects"` + } + jsonResp := &Response{} + err = json.Unmarshal(bodyBytes, &jsonResp) + + if err != nil { + http.Error(w, "Error parsing JSON body from IDE status probe.", http.StatusServiceUnavailable) + return + } + if len(jsonResp.Projects) != 1 { + http.Error(w, "projects size != 1", http.StatusServiceUnavailable) + return + } + response := make(map[string]string) + response["link"] = jsonResp.Projects[0].JoinLink + response["label"] = label + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(response) + }) + + fmt.Printf("Starting status proxy for desktop IDE at port %s\n", port) + if err := http.ListenAndServe(fmt.Sprintf(":%s", port), nil); err != nil { + log.Fatal(err) + } +} diff --git a/components/ide/jetbrains/image/supervisor-ide-config_goland.json b/components/ide/jetbrains/image/supervisor-ide-config_goland.json new file mode 100644 index 00000000000000..7a6a95c21861d2 --- /dev/null +++ b/components/ide/jetbrains/image/supervisor-ide-config_goland.json @@ -0,0 +1,11 @@ +{ + "entrypoint": "/ide-desktop/startup.sh", + "entrypointArgs": [ "Open GoLand IDE" ], + "readinessProbe": { + "type": "http", + "http": { + "port": 24000, + "path": "/status" + } + } +} diff --git a/components/ide/jetbrains/image/supervisor-ide-config_intellij.json b/components/ide/jetbrains/image/supervisor-ide-config_intellij.json new file mode 100644 index 00000000000000..f33290e76702e2 --- /dev/null +++ b/components/ide/jetbrains/image/supervisor-ide-config_intellij.json @@ -0,0 +1,11 @@ +{ + "entrypoint": "/ide-desktop/startup.sh", + "entrypointArgs": [ "Open IntelliJ IDEA IDE" ], + "readinessProbe": { + "type": "http", + "http": { + "port": 24000, + "path": "/status" + } + } +}