Skip to content

Commit cb77bdf

Browse files
mustard-mhroboquat
authored andcommitted
[supervisor] local exposed
1 parent 31d8a79 commit cb77bdf

File tree

2 files changed

+73
-22
lines changed

2 files changed

+73
-22
lines changed

components/supervisor/pkg/ports/exposed-ports.go

Lines changed: 72 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ package ports
66

77
import (
88
"context"
9+
"fmt"
10+
"net/url"
911
"time"
1012

1113
backoff "github.com/cenkalti/backoff/v4"
@@ -57,9 +59,14 @@ func (*NoopExposedPorts) Expose(ctx context.Context, local uint32, public bool)
5759
// GitpodExposedPorts uses a connection to the Gitpod server to implement
5860
// the ExposedPortsInterface.
5961
type GitpodExposedPorts struct {
60-
WorkspaceID string
61-
InstanceID string
62-
C gitpod.APIInterface
62+
WorkspaceID string
63+
InstanceID string
64+
WorkspaceUrl string
65+
C gitpod.APIInterface
66+
67+
localExposedPort []uint32
68+
localExposedNotice chan struct{}
69+
lastServerExposed []*gitpod.WorkspaceInstancePort
6370

6471
requests chan *exposePortRequest
6572
}
@@ -71,15 +78,35 @@ type exposePortRequest struct {
7178
}
7279

7380
// NewGitpodExposedPorts creates a new instance of GitpodExposedPorts
74-
func NewGitpodExposedPorts(workspaceID string, instanceID string, gitpodService gitpod.APIInterface) *GitpodExposedPorts {
81+
func NewGitpodExposedPorts(workspaceID string, instanceID string, workspaceUrl string, gitpodService gitpod.APIInterface) *GitpodExposedPorts {
7582
return &GitpodExposedPorts{
76-
WorkspaceID: workspaceID,
77-
InstanceID: instanceID,
78-
C: gitpodService,
83+
WorkspaceID: workspaceID,
84+
InstanceID: instanceID,
85+
WorkspaceUrl: workspaceUrl,
86+
C: gitpodService,
7987

8088
// allow clients to submit 30 expose requests without blocking
81-
requests: make(chan *exposePortRequest, 30),
89+
requests: make(chan *exposePortRequest, 30),
90+
localExposedNotice: make(chan struct{}, 30),
91+
}
92+
}
93+
94+
func (g *GitpodExposedPorts) getPortUrl(port uint32) string {
95+
u, err := url.Parse(g.WorkspaceUrl)
96+
if err != nil {
97+
return ""
98+
}
99+
u.Host = fmt.Sprintf("%d-%s", port, u.Host)
100+
return u.String()
101+
}
102+
103+
func (g *GitpodExposedPorts) existInLocalExposed(port uint32) bool {
104+
for _, p := range g.localExposedPort {
105+
if p == port {
106+
return true
107+
}
82108
}
109+
return false
83110
}
84111

85112
// Observe starts observing the exposed ports until the context is canceled.
@@ -98,22 +125,41 @@ func (g *GitpodExposedPorts) Observe(ctx context.Context) (<-chan []ExposedPort,
98125
errchan <- err
99126
return
100127
}
128+
mixin := func(localExposedPort []uint32, serverExposePort []*gitpod.WorkspaceInstancePort) []ExposedPort {
129+
res := make(map[uint32]ExposedPort)
130+
for _, port := range g.localExposedPort {
131+
res[port] = ExposedPort{
132+
LocalPort: port,
133+
Public: false,
134+
URL: g.getPortUrl(port),
135+
}
136+
}
137+
138+
for _, p := range serverExposePort {
139+
res[uint32(p.Port)] = ExposedPort{
140+
LocalPort: uint32(p.Port),
141+
Public: p.Visibility == "public",
142+
URL: p.URL,
143+
}
144+
}
145+
exposedPort := make([]ExposedPort, 0, len(res))
146+
for _, p := range res {
147+
exposedPort = append(exposedPort, p)
148+
}
149+
return exposedPort
150+
}
101151
for {
102152
select {
103153
case u := <-updates:
104154
if u == nil {
105155
return
106156
}
157+
g.lastServerExposed = u.Status.ExposedPorts
107158

108-
res := make([]ExposedPort, len(u.Status.ExposedPorts))
109-
for i, p := range u.Status.ExposedPorts {
110-
res[i] = ExposedPort{
111-
LocalPort: uint32(p.Port),
112-
Public: p.Visibility == "public",
113-
URL: p.URL,
114-
}
115-
}
116-
159+
res := mixin(g.localExposedPort, g.lastServerExposed)
160+
reschan <- res
161+
case <-g.localExposedNotice:
162+
res := mixin(g.localExposedPort, g.lastServerExposed)
117163
reschan <- res
118164
case <-ctx.Done():
119165
return
@@ -180,14 +226,19 @@ func (g *GitpodExposedPorts) doExpose(req *exposePortRequest) {
180226

181227
// Expose exposes a port to the internet. Upon successful execution any Observer will be updated.
182228
func (g *GitpodExposedPorts) Expose(ctx context.Context, local uint32, public bool) <-chan error {
183-
v := "private"
184-
if public {
185-
v = "public"
229+
if !public {
230+
if !g.existInLocalExposed(local) {
231+
g.localExposedPort = append(g.localExposedPort, local)
232+
g.localExposedNotice <- struct{}{}
233+
}
234+
c := make(chan error)
235+
close(c)
236+
return c
186237
}
187238
req := &exposePortRequest{
188239
port: &gitpod.WorkspaceInstancePort{
189240
Port: float64(local),
190-
Visibility: v,
241+
Visibility: "public",
191242
},
192243
ctx: ctx,
193244
done: make(chan error),

components/supervisor/pkg/supervisor/supervisor.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ func createExposedPortsImpl(cfg *Config, gitpodService *gitpod.APIoverJSONRPC) p
634634
log.Error("auto-port exposure won't work")
635635
return &ports.NoopExposedPorts{}
636636
}
637-
return ports.NewGitpodExposedPorts(cfg.WorkspaceID, cfg.WorkspaceInstanceID, gitpodService)
637+
return ports.NewGitpodExposedPorts(cfg.WorkspaceID, cfg.WorkspaceInstanceID, cfg.WorkspaceUrl, gitpodService)
638638
}
639639

640640
// supervisor ships some binaries we want in the PATH. We could just add some directory to the path, but

0 commit comments

Comments
 (0)