Skip to content

Commit e848c4c

Browse files
committed
fix #3162: decouple gp env from theia
1 parent 110ada6 commit e848c4c

File tree

20 files changed

+1216
-330
lines changed

20 files changed

+1216
-330
lines changed

components/gitpod-cli/BUILD.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,9 @@ packages:
88
env:
99
- CGO_ENABLED=0
1010
- GOOS=linux
11+
deps:
12+
- components/common-go:lib
13+
- components/supervisor-api/go:lib
14+
- components/gitpod-protocol/go:lib
1115
config:
1216
packaging: app

components/gitpod-cli/cmd/env.go

Lines changed: 146 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,19 @@
55
package cmd
66

77
import (
8+
"context"
9+
"errors"
810
"fmt"
911
"os"
1012
"strings"
13+
"time"
1114

1215
"github.com/spf13/cobra"
16+
"google.golang.org/grpc"
1317

1418
"github.com/gitpod-io/gitpod/gitpod-cli/pkg/theialib"
19+
serverapi "github.com/gitpod-io/gitpod/gitpod-protocol"
20+
supervisor "github.com/gitpod-io/gitpod/supervisor/api"
1521
)
1622

1723
var exportEnvs = false
@@ -42,79 +48,155 @@ delete environment variables with a repository pattern of */foo, foo/* or */*.
4248
`,
4349
Args: cobra.ArbitraryArgs,
4450
Run: func(cmd *cobra.Command, args []string) {
45-
fail := func(msg string) {
46-
fmt.Fprintln(os.Stderr, msg)
47-
os.Exit(-1)
51+
if len(args) > 0 {
52+
if unsetEnvs {
53+
deleteEnvs(args)
54+
return
55+
}
56+
57+
setEnvs(args)
58+
} else {
59+
getEnvs()
4860
}
61+
},
62+
}
4963

50-
service, err := theialib.NewServiceFromEnv()
64+
func getEnvs() {
65+
if !isTheiaIDE() {
66+
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
67+
defer cancel()
68+
supervisorAddr := os.Getenv("SUPERVISOR_ADDR")
69+
if supervisorAddr == "" {
70+
supervisorAddr = "localhost:22999"
71+
}
72+
supervisorConn, err := grpc.Dial(supervisorAddr, grpc.WithInsecure())
5173
if err != nil {
52-
fail(err.Error())
74+
fail("failed connecting to supervisor: " + err.Error())
75+
}
76+
wsinfo, err := supervisor.NewInfoServiceClient(supervisorConn).WorkspaceInfo(ctx, &supervisor.WorkspaceInfoRequest{})
77+
if err != nil {
78+
fail("failed getting workspace info from supervisor: " + err.Error())
79+
}
80+
if wsinfo.Repository == nil {
81+
fail("workspace info is missing repository")
82+
}
83+
if wsinfo.Repository.Owner == "" {
84+
fail("repository info is missing owner")
85+
}
86+
if wsinfo.Repository.Name == "" {
87+
fail("repository info is missing name")
5388
}
5489

55-
setEnvs := func() {
56-
vars := make([]theialib.EnvironmentVariable, len(args))
57-
for i, arg := range args {
58-
kv := strings.Split(arg, "=")
59-
if len(kv) != 2 {
60-
fail(fmt.Sprintf("%s has no value (correct format is %s=some_value)", arg, arg))
61-
}
62-
63-
key := strings.TrimSpace(kv[0])
64-
if key == "" {
65-
fail(fmt.Sprintf("variable must have a name"))
66-
}
67-
// Do not trim value - the user might want whitespace here
68-
// Also do not check if the value is empty, as an empty value means we want to delete the variable
69-
val := kv[1]
70-
if val == "" {
71-
fail(fmt.Sprintf("variable must have a value; use -u to unset a variable"))
72-
}
73-
74-
vars[i] = theialib.EnvironmentVariable{Name: key, Value: val}
75-
}
76-
77-
_, err = service.SetEnvVar(theialib.SetEnvvarRequest{Variables: vars})
78-
if err != nil {
79-
fail(fmt.Sprintf("cannot set environment variables: %v", err))
80-
}
90+
clientToken, err := supervisor.NewTokenServiceClient(supervisorConn).GetToken(ctx, &supervisor.GetTokenRequest{
91+
Host: wsinfo.GitpodApi.Host,
92+
Kind: "gitpod",
93+
Scope: []string{
94+
"function:getEnvVars",
95+
"resource:envVar::" + wsinfo.Repository.Owner + "/" + wsinfo.Repository.Name + "::get",
96+
},
97+
})
98+
if err != nil {
99+
fail("failed getting token from supervisor: " + err.Error())
100+
}
101+
client, err := serverapi.ConnectToServer(wsinfo.GitpodApi.Endpoint, serverapi.ConnectToServerOpts{Token: clientToken.Token, Context: ctx})
102+
if err != nil {
103+
fail("failed connecting to server: " + err.Error())
104+
}
105+
vars, err := client.GetEnvVars(ctx)
106+
if err != nil {
107+
fail("failed to fetch env vars from server: " + err.Error())
108+
}
81109

82-
for _, v := range vars {
83-
printVar(v, exportEnvs)
110+
for _, v := range vars {
111+
val := strings.Replace(v.Value, "\"", "\\\"", -1)
112+
if exportEnvs {
113+
fmt.Printf("export %s=\"%s\"\n", v.Name, val)
114+
} else {
115+
fmt.Printf("%s=%s\n", v.Name, val)
84116
}
85117
}
86-
getEnvs := func() {
87-
vars, err := service.GetEnvVars(theialib.GetEnvvarsRequest{})
88-
if err != nil {
89-
fail(fmt.Sprintf("cannot get environment variables: %v", err))
90-
}
118+
return
119+
}
91120

92-
for _, v := range vars.Variables {
93-
printVar(v, exportEnvs)
94-
}
121+
service, err := theialib.NewServiceFromEnv()
122+
if err != nil {
123+
fail(err.Error())
124+
}
125+
126+
vars, err := service.GetEnvVars(theialib.GetEnvvarsRequest{})
127+
if err != nil {
128+
fail(fmt.Sprintf("cannot get environment variables: %v", err))
129+
}
130+
131+
for _, v := range vars.Variables {
132+
printVar(v, exportEnvs)
133+
}
134+
}
135+
136+
func setEnvs(args []string) {
137+
if !isTheiaIDE() {
138+
fail("not supported")
139+
}
140+
141+
service, err := theialib.NewServiceFromEnv()
142+
if err != nil {
143+
fail(err.Error())
144+
}
145+
146+
vars := make([]theialib.EnvironmentVariable, len(args))
147+
for i, arg := range args {
148+
kv := strings.Split(arg, "=")
149+
if len(kv) != 2 {
150+
fail(fmt.Sprintf("%s has no value (correct format is %s=some_value)", arg, arg))
95151
}
96-
doUnsetEnvs := func() {
97-
resp, err := service.DeleteEnvVar(theialib.DeleteEnvvarRequest{Variables: args})
98-
if err != nil {
99-
fail(fmt.Sprintf("cannot unset environment variables: %v", err))
100-
}
101152

102-
if len(resp.NotDeleted) != 0 {
103-
fail(fmt.Sprintf("cannot unset environment variables: %s", strings.Join(resp.NotDeleted, ", ")))
104-
}
153+
key := strings.TrimSpace(kv[0])
154+
if key == "" {
155+
fail(fmt.Sprintf("variable must have a name"))
156+
}
157+
// Do not trim value - the user might want whitespace here
158+
// Also do not check if the value is empty, as an empty value means we want to delete the variable
159+
val := kv[1]
160+
if val == "" {
161+
fail(fmt.Sprintf("variable must have a value; use -u to unset a variable"))
105162
}
106163

107-
if len(args) > 0 {
108-
if unsetEnvs {
109-
doUnsetEnvs()
110-
return
111-
}
164+
vars[i] = theialib.EnvironmentVariable{Name: key, Value: val}
165+
}
112166

113-
setEnvs()
114-
} else {
115-
getEnvs()
116-
}
117-
},
167+
_, err = service.SetEnvVar(theialib.SetEnvvarRequest{Variables: vars})
168+
if err != nil {
169+
fail(fmt.Sprintf("cannot set environment variables: %v", err))
170+
}
171+
172+
for _, v := range vars {
173+
printVar(v, exportEnvs)
174+
}
175+
}
176+
177+
func deleteEnvs(args []string) {
178+
if !isTheiaIDE() {
179+
fail("not supported")
180+
}
181+
182+
service, err := theialib.NewServiceFromEnv()
183+
if err != nil {
184+
fail(err.Error())
185+
}
186+
187+
resp, err := service.DeleteEnvVar(theialib.DeleteEnvvarRequest{Variables: args})
188+
if err != nil {
189+
fail(fmt.Sprintf("cannot unset environment variables: %v", err))
190+
}
191+
192+
if len(resp.NotDeleted) != 0 {
193+
fail(fmt.Sprintf("cannot unset environment variables: %s", strings.Join(resp.NotDeleted, ", ")))
194+
}
195+
}
196+
197+
func fail(msg string) {
198+
fmt.Fprintln(os.Stderr, msg)
199+
os.Exit(-1)
118200
}
119201

120202
func printVar(v theialib.EnvironmentVariable, export bool) {
@@ -132,3 +214,8 @@ func init() {
132214
envCmd.Flags().BoolVarP(&exportEnvs, "export", "e", false, "produce a script that can be eval'ed in Bash")
133215
envCmd.Flags().BoolVarP(&unsetEnvs, "unset", "u", false, "deletes/unsets persisted environment variables")
134216
}
217+
218+
func isTheiaIDE() bool {
219+
stat, err := os.Stat("/theia")
220+
return !errors.Is(os.ErrNotExist, err) && stat != nil && stat.IsDir()
221+
}

components/gitpod-cli/go.mod

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,73 @@ go 1.16
44

55
require (
66
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
7+
github.com/gitpod-io/gitpod/gitpod-protocol v0.0.0-00010101000000-000000000000
8+
github.com/gitpod-io/gitpod/supervisor/api v0.0.0-00010101000000-000000000000
79
github.com/golang/mock v1.4.4
810
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
911
github.com/google/tcpproxy v0.0.0-20180808230851-dfa16c61dad2
1012
github.com/gorilla/handlers v1.4.2
1113
github.com/manifoldco/promptui v0.3.2
1214
github.com/nicksnyder/go-i18n v1.10.1 // indirect
13-
github.com/pkg/errors v0.8.1
15+
github.com/pkg/errors v0.9.1
1416
github.com/sirupsen/logrus v1.7.0
1517
github.com/spf13/cobra v0.0.5
16-
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037
18+
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd
19+
google.golang.org/grpc v1.36.0
1720
gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20191105091915-95d230a53780 // indirect
18-
gopkg.in/yaml.v2 v2.2.2
21+
gopkg.in/yaml.v2 v2.4.0
1922
)
23+
24+
replace github.com/gitpod-io/gitpod/common-go => ../common-go // leeway
25+
26+
replace github.com/gitpod-io/gitpod/gitpod-protocol => ../gitpod-protocol/go // leeway
27+
28+
replace github.com/gitpod-io/gitpod/supervisor/api => ../supervisor-api/go // leeway
29+
30+
replace k8s.io/api => k8s.io/api v0.20.4 // leeway indirect from components/common-go:lib
31+
32+
replace k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.20.4 // leeway indirect from components/common-go:lib
33+
34+
replace k8s.io/apimachinery => k8s.io/apimachinery v0.20.4 // leeway indirect from components/common-go:lib
35+
36+
replace k8s.io/apiserver => k8s.io/apiserver v0.20.4 // leeway indirect from components/common-go:lib
37+
38+
replace k8s.io/cli-runtime => k8s.io/cli-runtime v0.20.4 // leeway indirect from components/common-go:lib
39+
40+
replace k8s.io/client-go => k8s.io/client-go v0.20.4 // leeway indirect from components/common-go:lib
41+
42+
replace k8s.io/cloud-provider => k8s.io/cloud-provider v0.20.4 // leeway indirect from components/common-go:lib
43+
44+
replace k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.20.4 // leeway indirect from components/common-go:lib
45+
46+
replace k8s.io/code-generator => k8s.io/code-generator v0.20.4 // leeway indirect from components/common-go:lib
47+
48+
replace k8s.io/component-base => k8s.io/component-base v0.20.4 // leeway indirect from components/common-go:lib
49+
50+
replace k8s.io/cri-api => k8s.io/cri-api v0.20.4 // leeway indirect from components/common-go:lib
51+
52+
replace k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.20.4 // leeway indirect from components/common-go:lib
53+
54+
replace k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.20.4 // leeway indirect from components/common-go:lib
55+
56+
replace k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.20.4 // leeway indirect from components/common-go:lib
57+
58+
replace k8s.io/kube-proxy => k8s.io/kube-proxy v0.20.4 // leeway indirect from components/common-go:lib
59+
60+
replace k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.20.4 // leeway indirect from components/common-go:lib
61+
62+
replace k8s.io/kubelet => k8s.io/kubelet v0.20.4 // leeway indirect from components/common-go:lib
63+
64+
replace k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.20.4 // leeway indirect from components/common-go:lib
65+
66+
replace k8s.io/metrics => k8s.io/metrics v0.20.4 // leeway indirect from components/common-go:lib
67+
68+
replace k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.20.4 // leeway indirect from components/common-go:lib
69+
70+
replace k8s.io/component-helpers => k8s.io/component-helpers v0.20.4 // leeway indirect from components/common-go:lib
71+
72+
replace k8s.io/controller-manager => k8s.io/controller-manager v0.20.4 // leeway indirect from components/common-go:lib
73+
74+
replace k8s.io/kubectl => k8s.io/kubectl v0.20.4 // leeway indirect from components/common-go:lib
75+
76+
replace k8s.io/mount-utils => k8s.io/mount-utils v0.20.4 // leeway indirect from components/common-go:lib

0 commit comments

Comments
 (0)