Skip to content

Commit 756c5b0

Browse files
felladrinakosyakovAndrea Falzetti
authored andcommitted
Replace "Status" by "JetBrains Launcher" and run it in a separate image from IDEs
Co-authored-by: Anton Kosyakov <[email protected]> Co-authored-by: Andrea Falzetti <[email protected]>
1 parent 16e82f1 commit 756c5b0

File tree

71 files changed

+2391
-494
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+2391
-494
lines changed

components/BUILD.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ packages:
4141
- components/ide/code-desktop:docker
4242
- components/ide/code-desktop:docker-insiders
4343
- components/ide/code:docker
44+
- components/ide/jetbrains/launcher:docker
4445
- components/ide/jetbrains/backend-plugin:stable
4546
- components/ide/jetbrains/backend-plugin:latest
4647
- components/ide/jetbrains/image:goland
@@ -134,6 +135,7 @@ packages:
134135
- components/ws-manager:app
135136
- components/ide-metrics:app
136137
- components/ide-service:app
138+
- components/ide/jetbrains/launcher:app
137139
scripts:
138140
- name: update-license-header
139141
description: Updates the license header in all source files

components/ide-service-api/go/config/ideconfig.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,19 @@ type IDEOption struct {
5252
// This is useful if this image points to a tag like `nightly` that will be updated regularly. When `resolveImageDigest` is `true`, we make sure that we resolve the tag regularly to the most recent image version.
5353
ResolveImageDigest bool `json:"resolveImageDigest,omitempty"`
5454
// PluginImage ref for the IDE image, this image ref always resolve to digest.
55+
// DEPRECATED use ImageLayers instead
5556
PluginImage string `json:"pluginImage,omitempty"`
5657
// PluginLatestImage ref for the latest IDE image, this image ref always resolve to digest.
58+
// DEPRECATED use LatestImageLayers instead
5759
PluginLatestImage string `json:"pluginLatestImage,omitempty"`
5860
// ImageVersion the semantic version of the IDE image.
5961
ImageVersion string `json:"imageVersion,omitempty"`
6062
// LatestImageVersion the semantic version of the latest IDE image.
6163
LatestImageVersion string `json:"latestImageVersion,omitempty"`
64+
// ImageLayers for additional ide layers and dependencies
65+
ImageLayers []string `json:"imageLayers,omitempty"`
66+
// LatestImageLayers for latest additional ide layers and dependencies
67+
LatestImageLayers []string `json:"latestImageLayers,omitempty"`
6268
}
6369

6470
type IDEClient struct {

components/ide-service/example-ide-config.json

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,14 @@
2626
"logo": "https://ide.gitpod.io/image/ide-logo/golandLogo.svg",
2727
"image": "eu.gcr.io/gitpod-core-dev/build/ide/goland:commit-9a6c79a91b2b1f583d5bcb7f9f1ef54ee977e0df",
2828
"latestImage": "eu.gcr.io/gitpod-core-dev/build/ide/goland:latest@sha256:e07524e52089829dc8d3b38f7d18fb51b24f07aed7d8e4e6e447899687978d43",
29-
"pluginImage": "eu.gcr.io/gitpod-core-dev/build/ide/jb-backend-plugin:commit-b38092639d1783a1957894ddd4f492b3cdc9794a",
30-
"pluginLatestImage": "eu.gcr.io/gitpod-core-dev/build/ide/jb-backend-plugin:commit-b38092639d1783a1957894ddd4f492b3cdc9794a-latest"
29+
"imageLayers": [
30+
"eu.gcr.io/gitpod-core-dev/build/ide/jb-backend-plugin:commit-b38092639d1783a1957894ddd4f492b3cdc9794a",
31+
"eu.gcr.io/gitpod-core-dev/build/ide/jb-launcher:commit-b38092639d1783a1957894ddd4f492b3cdc9794a"
32+
],
33+
"latestImageLayers": [
34+
"eu.gcr.io/gitpod-core-dev/build/ide/jb-backend-plugin:commit-b38092639d1783a1957894ddd4f492b3cdc9794a-latest",
35+
"eu.gcr.io/gitpod-core-dev/build/ide/jb-launcher:commit-b38092639d1783a1957894ddd4f492b3cdc9794a"
36+
]
3137
},
3238
"intellij": {
3339
"orderKey": "04",
@@ -36,8 +42,14 @@
3642
"logo": "https://ide.gitpod.io/image/ide-logo/intellijIdeaLogo.svg",
3743
"image": "eu.gcr.io/gitpod-core-dev/build/ide/intellij:commit-9a6c79a91b2b1f583d5bcb7f9f1ef54ee977e0df",
3844
"latestImage": "eu.gcr.io/gitpod-core-dev/build/ide/intellij:latest@sha256:e07524e52089829dc8d3b38f7d18fb51b24f07aed7d8e4e6e447899687978d43",
39-
"pluginImage": "eu.gcr.io/gitpod-core-dev/build/ide/jb-backend-plugin:commit-b38092639d1783a1957894ddd4f492b3cdc9794a",
40-
"pluginLatestImage": "eu.gcr.io/gitpod-core-dev/build/ide/jb-backend-plugin:commit-b38092639d1783a1957894ddd4f492b3cdc9794a-latest"
45+
"imageLayers": [
46+
"eu.gcr.io/gitpod-core-dev/build/ide/jb-backend-plugin:commit-b38092639d1783a1957894ddd4f492b3cdc9794a",
47+
"eu.gcr.io/gitpod-core-dev/build/ide/jb-launcher:commit-b38092639d1783a1957894ddd4f492b3cdc9794a"
48+
],
49+
"latestImageLayers": [
50+
"eu.gcr.io/gitpod-core-dev/build/ide/jb-backend-plugin:commit-b38092639d1783a1957894ddd4f492b3cdc9794a-latest",
51+
"eu.gcr.io/gitpod-core-dev/build/ide/jb-launcher:commit-b38092639d1783a1957894ddd4f492b3cdc9794a"
52+
]
4153
},
4254
"phpstorm": {
4355
"orderKey": "07",
@@ -46,8 +58,14 @@
4658
"logo": "https://ide.gitpod.io/image/ide-logo/phpstormLogo.svg",
4759
"image": "eu.gcr.io/gitpod-core-dev/build/ide/phpstorm:commit-9a6c79a91b2b1f583d5bcb7f9f1ef54ee977e0df",
4860
"latestImage": "eu.gcr.io/gitpod-core-dev/build/ide/phpstorm:latest@sha256:e07524e52089829dc8d3b38f7d18fb51b24f07aed7d8e4e6e447899687978d43",
49-
"pluginImage": "eu.gcr.io/gitpod-core-dev/build/ide/jb-backend-plugin:commit-b38092639d1783a1957894ddd4f492b3cdc9794a",
50-
"pluginLatestImage": "eu.gcr.io/gitpod-core-dev/build/ide/jb-backend-plugin:commit-b38092639d1783a1957894ddd4f492b3cdc9794a-latest"
61+
"imageLayers": [
62+
"eu.gcr.io/gitpod-core-dev/build/ide/jb-backend-plugin:commit-b38092639d1783a1957894ddd4f492b3cdc9794a",
63+
"eu.gcr.io/gitpod-core-dev/build/ide/jb-launcher:commit-b38092639d1783a1957894ddd4f492b3cdc9794a"
64+
],
65+
"latestImageLayers": [
66+
"eu.gcr.io/gitpod-core-dev/build/ide/jb-backend-plugin:commit-b38092639d1783a1957894ddd4f492b3cdc9794a-latest",
67+
"eu.gcr.io/gitpod-core-dev/build/ide/jb-launcher:commit-b38092639d1783a1957894ddd4f492b3cdc9794a"
68+
]
5169
},
5270
"pycharm": {
5371
"orderKey": "06",
@@ -56,8 +74,14 @@
5674
"logo": "https://ide.gitpod.io/image/ide-logo/pycharmLogo.svg",
5775
"image": "eu.gcr.io/gitpod-core-dev/build/ide/pycharm:commit-9a6c79a91b2b1f583d5bcb7f9f1ef54ee977e0df",
5876
"latestImage": "eu.gcr.io/gitpod-core-dev/build/ide/pycharm:latest@sha256:e07524e52089829dc8d3b38f7d18fb51b24f07aed7d8e4e6e447899687978d43",
59-
"pluginImage": "eu.gcr.io/gitpod-core-dev/build/ide/jb-backend-plugin:commit-b38092639d1783a1957894ddd4f492b3cdc9794a",
60-
"pluginLatestImage": "eu.gcr.io/gitpod-core-dev/build/ide/jb-backend-plugin:commit-b38092639d1783a1957894ddd4f492b3cdc9794a-latest"
77+
"imageLayers": [
78+
"eu.gcr.io/gitpod-core-dev/build/ide/jb-backend-plugin:commit-b38092639d1783a1957894ddd4f492b3cdc9794a",
79+
"eu.gcr.io/gitpod-core-dev/build/ide/jb-launcher:commit-b38092639d1783a1957894ddd4f492b3cdc9794a"
80+
],
81+
"latestImageLayers": [
82+
"eu.gcr.io/gitpod-core-dev/build/ide/jb-backend-plugin:commit-b38092639d1783a1957894ddd4f492b3cdc9794a-latest",
83+
"eu.gcr.io/gitpod-core-dev/build/ide/jb-launcher:commit-b38092639d1783a1957894ddd4f492b3cdc9794a"
84+
]
6185
}
6286
},
6387
"defaultIde": "code",

components/ide-service/pkg/server/server.go

Lines changed: 87 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -188,20 +188,6 @@ type WorkspaceContext struct {
188188
ReferrerIde string `json:"referrerIde,omitempty"`
189189
}
190190

191-
var JetbrainsCode map[string]string
192-
193-
func init() {
194-
JetbrainsCode = make(map[string]string)
195-
JetbrainsCode["intellij"] = "IIU"
196-
JetbrainsCode["goland"] = "GO"
197-
JetbrainsCode["pycharm"] = "PCP"
198-
JetbrainsCode["phpstorm"] = "PS"
199-
JetbrainsCode["rubymine"] = "RM"
200-
JetbrainsCode["webstorm"] = "WS"
201-
JetbrainsCode["rider"] = "RD"
202-
JetbrainsCode["clion"] = "CL"
203-
}
204-
205191
func (s *IDEServiceServer) resolveReferrerIDE(ideConfig *config.IDEConfig, wsCtx *WorkspaceContext, chosenIDEName string) (ideName string, ideOption *config.IDEOption) {
206192
if wsCtx == nil || wsCtx.Referrer == "" {
207193
return
@@ -264,166 +250,149 @@ func (s *IDEServiceServer) ResolveWorkspaceConfig(ctx context.Context, req *api.
264250
WebImage: defaultIde.Image,
265251
}
266252

267-
// TODO: reconsider this
268-
// if req.Type != api.WorkspaceType_REGULAR {
269-
// return resp, nil
270-
// }
271-
272253
var wsConfig *gitpodapi.GitpodConfig
273-
var wsContext *WorkspaceContext
274-
var ideSettings *IDESettings
275254

276-
if req.IdeSettings != "" {
277-
if err := json.Unmarshal([]byte(req.IdeSettings), &ideSettings); err != nil {
278-
log.WithError(err).WithField("ideSetting", req.IdeSettings).Error("failed to parse ide settings")
279-
}
280-
}
281255
if req.WorkspaceConfig != "" {
282256
if err := json.Unmarshal([]byte(req.WorkspaceConfig), &wsConfig); err != nil {
283257
log.WithError(err).WithField("workspaceConfig", req.WorkspaceConfig).Error("failed to parse workspace config")
284258
}
285259
}
286-
if req.Context != "" {
287-
if err := json.Unmarshal([]byte(req.Context), &wsContext); err != nil {
288-
log.WithError(err).WithField("context", req.Context).Error("failed to parse context")
289-
}
290-
}
291260

292-
userIdeName := ""
293-
useLatest := false
261+
if req.Type == api.WorkspaceType_REGULAR {
262+
var ideSettings *IDESettings
263+
var wsContext *WorkspaceContext
294264

295-
if ideSettings != nil {
296-
userIdeName = ideSettings.DefaultIde
297-
useLatest = ideSettings.UseLatestVersion
298-
}
265+
if req.IdeSettings != "" {
266+
if err := json.Unmarshal([]byte(req.IdeSettings), &ideSettings); err != nil {
267+
log.WithError(err).WithField("ideSetting", req.IdeSettings).Error("failed to parse ide settings")
268+
}
269+
}
299270

300-
chosenIDE := defaultIde
271+
if req.Context != "" {
272+
if err := json.Unmarshal([]byte(req.Context), &wsContext); err != nil {
273+
log.WithError(err).WithField("context", req.Context).Error("failed to parse context")
274+
}
275+
}
301276

302-
getUserIDEImage := func(ideOption *config.IDEOption) string {
303-
if useLatest && ideOption.LatestImage != "" {
304-
return ideOption.LatestImage
277+
userIdeName := ""
278+
useLatest := false
279+
280+
if ideSettings != nil {
281+
userIdeName = ideSettings.DefaultIde
282+
useLatest = ideSettings.UseLatestVersion
305283
}
306284

307-
return ideOption.Image
308-
}
285+
chosenIDE := defaultIde
309286

310-
getUserPluginImage := func(ideOption *config.IDEOption) string {
311-
if useLatest && ideOption.PluginLatestImage != "" {
312-
return ideOption.PluginLatestImage
287+
getUserIDEImage := func(ideOption *config.IDEOption) string {
288+
if useLatest && ideOption.LatestImage != "" {
289+
return ideOption.LatestImage
290+
}
291+
292+
return ideOption.Image
313293
}
314294

315-
return ideOption.PluginImage
316-
}
295+
getUserImageLayers := func(ideOption *config.IDEOption) []string {
296+
if useLatest {
297+
return ideOption.LatestImageLayers
298+
}
317299

318-
if userIdeName != "" {
319-
if ide, ok := ideConfig.IdeOptions.Options[userIdeName]; ok {
320-
chosenIDE = &ide
300+
return ideOption.ImageLayers
301+
}
321302

322-
// TODO: Currently this variable reflects the IDE selected in
323-
// user's settings for backward compatibility but in the future
324-
// we want to make it represent the actual IDE.
325-
ideAlias := api.EnvironmentVariable{
326-
Name: "GITPOD_IDE_ALIAS",
327-
Value: userIdeName,
303+
if userIdeName != "" {
304+
if ide, ok := ideConfig.IdeOptions.Options[userIdeName]; ok {
305+
chosenIDE = &ide
306+
307+
// TODO: Currently this variable reflects the IDE selected in
308+
// user's settings for backward compatibility but in the future
309+
// we want to make it represent the actual IDE.
310+
ideAlias := api.EnvironmentVariable{
311+
Name: "GITPOD_IDE_ALIAS",
312+
Value: userIdeName,
313+
}
314+
resp.Envvars = append(resp.Envvars, &ideAlias)
328315
}
329-
resp.Envvars = append(resp.Envvars, &ideAlias)
330316
}
331-
}
332317

333-
// we always need WebImage for when the user chooses a desktop ide
334-
resp.WebImage = getUserIDEImage(defaultIde)
318+
// we always need WebImage for when the user chooses a desktop ide
319+
resp.WebImage = getUserIDEImage(defaultIde)
335320

336-
var desktopImageLayer string
337-
var desktopPluginImageLayer string
338-
if chosenIDE.Type == config.IDETypeDesktop {
339-
desktopImageLayer = getUserIDEImage(chosenIDE)
340-
desktopPluginImageLayer = getUserPluginImage(chosenIDE)
341-
} else {
342-
resp.WebImage = getUserIDEImage(chosenIDE)
343-
}
321+
var desktopImageLayer string
322+
var userImageLayers []string
323+
if chosenIDE.Type == config.IDETypeDesktop {
324+
desktopImageLayer = getUserIDEImage(chosenIDE)
325+
userImageLayers = getUserImageLayers(chosenIDE)
326+
} else {
327+
resp.WebImage = getUserIDEImage(chosenIDE)
328+
}
344329

345-
ideName, referrer := s.resolveReferrerIDE(ideConfig, wsContext, userIdeName)
346-
if ideName != "" {
347-
resp.RefererIde = ideName
348-
desktopImageLayer = getUserIDEImage(referrer)
349-
desktopPluginImageLayer = getUserPluginImage(referrer)
350-
}
330+
ideName, referrer := s.resolveReferrerIDE(ideConfig, wsContext, userIdeName)
331+
if ideName != "" {
332+
resp.RefererIde = ideName
333+
desktopImageLayer = getUserIDEImage(referrer)
334+
userImageLayers = getUserImageLayers(referrer)
335+
}
351336

352-
if desktopImageLayer != "" {
353-
resp.IdeImageLayers = append(resp.IdeImageLayers, desktopImageLayer)
354-
if desktopPluginImageLayer != "" {
355-
resp.IdeImageLayers = append(resp.IdeImageLayers, desktopPluginImageLayer)
337+
if desktopImageLayer != "" {
338+
resp.IdeImageLayers = append(resp.IdeImageLayers, desktopImageLayer)
339+
resp.IdeImageLayers = append(resp.IdeImageLayers, userImageLayers...)
356340
}
357341
}
358342

359343
jbGW, ok := ideConfig.IdeOptions.Clients["jetbrains-gateway"]
360344
if req.Type == api.WorkspaceType_PREBUILD && ok {
361345
warmUpTask := ""
346+
imageLayers := make(map[string]struct{})
362347
for _, alias := range jbGW.DesktopIDEs {
363348
prebuilds := getPrebuilds(wsConfig, alias)
364349
if prebuilds != nil {
365350
if prebuilds.Version != "latest" {
366-
template := `
351+
if ide, ok := ideConfig.IdeOptions.Options[alias]; ok {
352+
for _, ideImageLayer := range ide.ImageLayers {
353+
if _, ok := imageLayers[ideImageLayer]; !ok {
354+
imageLayers[ideImageLayer] = struct{}{}
355+
resp.IdeImageLayers = append(resp.IdeImageLayers, ideImageLayer)
356+
}
357+
}
358+
resp.IdeImageLayers = append(resp.IdeImageLayers, ide.Image)
359+
template := `
367360
echo 'warming up stable release of ${key}...'
368-
echo 'downloading stable ${key} backend...'
369-
mkdir /tmp/backend
370-
curl -sSLo /tmp/backend/backend.tar.gz "https://download.jetbrains.com/product?type=release&distribution=linux&code=${productCode}"
371-
tar -xf /tmp/backend/backend.tar.gz --strip-components=1 --directory /tmp/backend
372-
373-
echo 'configuring JB system config and caches aligned with runtime...'
374-
printf '\nshared.indexes.download.auto.consent=true' >> "/tmp/backend/bin/idea.properties"
375-
unset JAVA_TOOL_OPTIONS
376-
export IJ_HOST_CONFIG_BASE_DIR=/workspace/.config/JetBrains
377-
export IJ_HOST_SYSTEM_BASE_DIR=/workspace/.cache/JetBrains
378-
379-
echo 'running stable ${key} backend in warmup mode...'
380-
/tmp/backend/bin/remote-dev-server.sh warmup "$GITPOD_REPO_ROOT"
381-
382-
echo 'removing stable ${key} backend...'
383-
rm -rf /tmp/backend
361+
JETBRAINS_BACKEND_QUALIFIER=stable /ide-desktop/jb-launcher warmup ${key}
384362
`
385-
if code, ok := JetbrainsCode[alias]; ok {
386363
template = strings.ReplaceAll(template, "${key}", alias)
387-
template = strings.ReplaceAll(template, "${productCode}", code)
388364
warmUpTask += template
389365
}
390366
}
391367

392368
if prebuilds.Version != "stable" {
393-
template := `
369+
if ide, ok := ideConfig.IdeOptions.Options[alias]; ok {
370+
for _, latestIdeImageLayer := range ide.LatestImageLayers {
371+
if _, ok := imageLayers[latestIdeImageLayer]; !ok {
372+
imageLayers[latestIdeImageLayer] = struct{}{}
373+
resp.IdeImageLayers = append(resp.IdeImageLayers, latestIdeImageLayer)
374+
}
375+
}
376+
resp.IdeImageLayers = append(resp.IdeImageLayers, ide.LatestImage)
377+
template := `
394378
echo 'warming up latest release of ${key}...'
395-
echo 'downloading latest ${key} backend...'
396-
mkdir /tmp/backend-latest
397-
curl -sSLo /tmp/backend-latest/backend-latest.tar.gz "https://download.jetbrains.com/product?type=release,eap,rc&distribution=linux&code=${productCode}"
398-
tar -xf /tmp/backend-latest/backend-latest.tar.gz --strip-components=1 --directory /tmp/backend-latest
399-
400-
echo 'configuring JB system config and caches aligned with runtime...'
401-
printf '\nshared.indexes.download.auto.consent=true' >> "/tmp/backend-latest/bin/idea.properties"
402-
unset JAVA_TOOL_OPTIONS
403-
export IJ_HOST_CONFIG_BASE_DIR=/workspace/.config/JetBrains-latest
404-
export IJ_HOST_SYSTEM_BASE_DIR=/workspace/.cache/JetBrains-latest
405-
406-
echo 'running ${key} backend in warmup mode...'
407-
/tmp/backend-latest/bin/remote-dev-server.sh warmup "$GITPOD_REPO_ROOT"
408-
409-
echo 'removing latest ${key} backend...'
410-
rm -rf /tmp/backend-latest
379+
JETBRAINS_BACKEND_QUALIFIER=latest /ide-desktop/jb-launcher warmup ${key}
411380
`
412-
if code, ok := JetbrainsCode[alias]; ok {
413381
template = strings.ReplaceAll(template, "${key}", alias)
414-
template = strings.ReplaceAll(template, "${productCode}", code)
415382
warmUpTask += template
416383
}
417384
}
418385
}
419386
}
387+
420388
if warmUpTask != "" {
421389
warmUpEncoded := new(bytes.Buffer)
422390
enc := json.NewEncoder(warmUpEncoded)
423391
enc.SetEscapeHTML(false)
424392

425393
err := enc.Encode(&[]gitpodapi.TaskConfig{{
426394
Init: strings.TrimSpace(warmUpTask),
395+
Name: "GITPOD_JB_WARMUP_TASK",
427396
}})
428397
if err != nil {
429398
log.WithError(err).Error("cannot marshal warm up task")
@@ -432,6 +401,7 @@ rm -rf /tmp/backend-latest
432401
resp.Tasks = warmUpEncoded.String()
433402
}
434403
}
404+
435405
return
436406
}
437407

0 commit comments

Comments
 (0)