Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Aug 30, 2024. It is now read-only.
/coder-v1-cliPublic archive

Commit2136d8d

Browse files
authored
chore: use access url from env resource pool (#216)
1 parentcf6e030 commit2136d8d

File tree

10 files changed

+136
-67
lines changed

10 files changed

+136
-67
lines changed

‎coder-sdk/env.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package coder
33
import (
44
"context"
55
"net/http"
6+
"net/url"
67
"time"
78

89
"cdr.dev/wsep"
@@ -32,7 +33,6 @@ type Environment struct {
3233
LastOpenedAt time.Time`json:"last_opened_at" table:"-"`
3334
LastConnectionAt time.Time`json:"last_connection_at" table:"-"`
3435
AutoOffThresholdDuration`json:"auto_off_threshold" table:"-"`
35-
SSHAvailablebool`json:"ssh_available" table:"-"`
3636
UseContainerVMbool`json:"use_container_vm" table:"CVM"`
3737
ResourcePoolIDstring`json:"resource_pool_id" table:"-"`
3838
}
@@ -147,22 +147,22 @@ func (c Client) EditEnvironment(ctx context.Context, envID string, req UpdateEnv
147147

148148
// DialWsep dials an environments command execution interface
149149
// See https://github.com/cdr/wsep for details.
150-
func (cClient)DialWsep(ctx context.Context,envIDstring) (*websocket.Conn,error) {
151-
returnc.dialWebsocket(ctx,"/proxy/environments/"+envID+"/wsep")
150+
func (cClient)DialWsep(ctx context.Context,baseURL*url.URL,envIDstring) (*websocket.Conn,error) {
151+
returnc.dialWebsocket(ctx,"/proxy/environments/"+envID+"/wsep",withBaseURL(baseURL))
152152
}
153153

154154
// DialExecutor gives a remote execution interface for performing commands inside an environment.
155-
func (cClient)DialExecutor(ctx context.Context,envIDstring) (wsep.Execer,error) {
156-
ws,err:=c.DialWsep(ctx,envID)
155+
func (cClient)DialExecutor(ctx context.Context,baseURL*url.URL,envIDstring) (wsep.Execer,error) {
156+
ws,err:=c.DialWsep(ctx,baseURL,envID)
157157
iferr!=nil {
158158
returnnil,err
159159
}
160160
returnwsep.RemoteExecer(ws),nil
161161
}
162162

163163
// DialIDEStatus opens a websocket connection for cpu load metrics on the environment.
164-
func (cClient)DialIDEStatus(ctx context.Context,envIDstring) (*websocket.Conn,error) {
165-
returnc.dialWebsocket(ctx,"/proxy/environments/"+envID+"/ide/api/status")
164+
func (cClient)DialIDEStatus(ctx context.Context,baseURL*url.URL,envIDstring) (*websocket.Conn,error) {
165+
returnc.dialWebsocket(ctx,"/proxy/environments/"+envID+"/ide/api/status",withBaseURL(baseURL))
166166
}
167167

168168
// DialEnvironmentBuildLog opens a websocket connection for the environment build log messages.

‎coder-sdk/request.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,21 @@ import (
1212
)
1313

1414
// request is a helper to set the cookie, marshal the payload and execute the request.
15-
func (cClient)request(ctx context.Context,method,pathstring,ininterface{}) (*http.Response,error) {
15+
func (cClient)request(ctx context.Context,method,pathstring,ininterface{},options...requestOption) (*http.Response,error) {
1616
// Create a default http client with the auth in the cookie.
1717
client,err:=c.newHTTPClient()
1818
iferr!=nil {
1919
returnnil,xerrors.Errorf("new http client: %w",err)
2020
}
21+
url:=*c.BaseURL
22+
23+
varconfigrequestOptions
24+
for_,o:=rangeoptions {
25+
o(&config)
26+
}
27+
ifconfig.BaseURLOverride!=nil {
28+
url=*config.BaseURLOverride
29+
}
2130

2231
// If we have incoming data, encode it as json.
2332
varpayload io.Reader
@@ -30,7 +39,7 @@ func (c Client) request(ctx context.Context, method, path string, in interface{}
3039
}
3140

3241
// Create the http request.
33-
req,err:=http.NewRequestWithContext(ctx,method,c.BaseURL.String()+path,payload)
42+
req,err:=http.NewRequestWithContext(ctx,method,url.String()+path,payload)
3443
iferr!=nil {
3544
returnnil,xerrors.Errorf("create request: %w",err)
3645
}

‎coder-sdk/resourcepools.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ type ResourcePool struct {
1717
DevurlHoststring`json:"devurl_host"`
1818
NamespaceWhitelist []string`json:"namespace_whitelist"`
1919
OrgWhitelist []string`json:"org_whitelist"`
20+
SSHEnabledbool`json:"ssh_enabled"`
21+
AccessURLstring`json:"envproxy_access_url"`
2022
}
2123

2224
// ResourcePoolByID fetches a resource pool entity by its unique ID.

‎coder-sdk/ws.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,35 @@ package coder
33
import (
44
"context"
55
"net/http"
6+
"net/url"
67

78
"nhooyr.io/websocket"
89
)
910

11+
typerequestOptionsstruct {
12+
BaseURLOverride*url.URL
13+
}
14+
15+
typerequestOptionfunc(*requestOptions)
16+
17+
funcwithBaseURL(base*url.URL)func(o*requestOptions) {
18+
returnfunc(o*requestOptions) {
19+
o.BaseURLOverride=base
20+
}
21+
}
22+
1023
// dialWebsocket establish the websocket connection while setting the authentication header.
11-
func (cClient)dialWebsocket(ctx context.Context,pathstring) (*websocket.Conn,error) {
24+
func (cClient)dialWebsocket(ctx context.Context,pathstring,options...requestOption) (*websocket.Conn,error) {
1225
// Make a copy of the url so we can update the scheme to ws(s) without mutating the state.
1326
url:=*c.BaseURL
27+
varconfigrequestOptions
28+
for_,o:=rangeoptions {
29+
o(&config)
30+
}
31+
ifconfig.BaseURLOverride!=nil {
32+
url=*config.BaseURLOverride
33+
}
34+
1435
ifurl.Scheme=="https" {
1536
url.Scheme="wss"
1637
}else {

‎internal/cmd/configssh.go

Lines changed: 23 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,16 @@ import (
44
"context"
55
"fmt"
66
"io/ioutil"
7-
"net"
87
"net/url"
98
"os"
109
"os/user"
1110
"path/filepath"
1211
"strings"
13-
"time"
1412

1513
"cdr.dev/coder-cli/pkg/clog"
1614

1715
"cdr.dev/coder-cli/coder-sdk"
16+
"cdr.dev/coder-cli/internal/coderutil"
1817
"cdr.dev/coder-cli/internal/config"
1918
"github.com/spf13/cobra"
2019
"golang.org/x/xerrors"
@@ -103,20 +102,17 @@ func configSSH(configpath *string, remove *bool) func(cmd *cobra.Command, _ []st
103102
returnxerrors.New("no environments found")
104103
}
105104

106-
if!sshAvailable(envs) {
107-
returnxerrors.New("SSH is disabled or not available for any environments in your Coder Enterprise deployment.")
108-
}
109-
110-
err=canConnectSSH(ctx)
105+
envsWithPools,err:=coderutil.EnvsWithPool(ctx,client,envs)
111106
iferr!=nil {
112-
returnxerrors.Errorf("check if SSH is available: unable to connect to SSH endpoint: %w",err)
107+
returnxerrors.Errorf("resolve env pools: %w",err)
113108
}
114109

115-
newConfig,err:=makeNewConfigs(user.Username,envs,privateKeyFilepath)
116-
iferr!=nil {
117-
returnxerrors.Errorf("make new ssh configurations: %w",err)
110+
if!sshAvailable(envsWithPools) {
111+
returnxerrors.New("SSH is disabled or not available for any environments in your Coder Enterprise deployment.")
118112
}
119113

114+
newConfig:=makeNewConfigs(user.Username,envsWithPools,privateKeyFilepath)
115+
120116
err=os.MkdirAll(filepath.Dir(*configpath),os.ModePerm)
121117
iferr!=nil {
122118
returnxerrors.Errorf("make configuration directory: %w",err)
@@ -159,42 +155,15 @@ func removeOldConfig(config string) (string, bool) {
159155
}
160156

161157
// sshAvailable returns true if SSH is available for at least one environment.
162-
funcsshAvailable(envs []coder.Environment)bool {
158+
funcsshAvailable(envs []coderutil.EnvWithPool)bool {
163159
for_,env:=rangeenvs {
164-
ifenv.SSHAvailable {
160+
ifenv.Pool.SSHEnabled {
165161
returntrue
166162
}
167163
}
168-
169164
returnfalse
170165
}
171166

172-
// canConnectSSH returns an error if we cannot dial the SSH port.
173-
funccanConnectSSH(ctx context.Context)error {
174-
ctx,cancel:=context.WithTimeout(ctx,3*time.Second)
175-
defercancel()
176-
177-
host,err:=configuredHostname()
178-
iferr!=nil {
179-
returnxerrors.Errorf("get configured manager hostname: %w",err)
180-
}
181-
182-
var (
183-
dialer net.Dialer
184-
hostPort=net.JoinHostPort(host,"22")
185-
)
186-
conn,err:=dialer.DialContext(ctx,"tcp",hostPort)
187-
iferr!=nil {
188-
iferr==context.DeadlineExceeded {
189-
err=xerrors.New("timed out after 3 seconds")
190-
}
191-
returnxerrors.Errorf("dial tcp://%v: %w",hostPort,err)
192-
}
193-
conn.Close()
194-
195-
returnnil
196-
}
197-
198167
funcwriteSSHKey(ctx context.Context,client*coder.Client,privateKeyPathstring)error {
199168
key,err:=client.SSHKey(ctx)
200169
iferr!=nil {
@@ -203,23 +172,26 @@ func writeSSHKey(ctx context.Context, client *coder.Client, privateKeyPath strin
203172
returnioutil.WriteFile(privateKeyPath, []byte(key.PrivateKey),0400)
204173
}
205174

206-
funcmakeNewConfigs(userNamestring,envs []coder.Environment,privateKeyFilepathstring) (string,error) {
207-
hostname,err:=configuredHostname()
208-
iferr!=nil {
209-
return"",err
210-
}
211-
175+
funcmakeNewConfigs(userNamestring,envs []coderutil.EnvWithPool,privateKeyFilepathstring)string {
212176
newConfig:=fmt.Sprintf("\n%s\n%s\n\n",sshStartToken,sshStartMessage)
213177
for_,env:=rangeenvs {
214-
if!env.SSHAvailable {
178+
if!env.Pool.SSHEnabled {
179+
clog.LogWarn(fmt.Sprintf("SSH is not enabled for pool %q",env.Pool.Name),
180+
clog.BlankLine,
181+
clog.Tipf("ask an infrastructure administrator to enable SSH for this resource pool"),
182+
)
215183
continue
216184
}
217-
218-
newConfig+=makeSSHConfig(hostname,userName,env.Name,privateKeyFilepath)
185+
u,err:=url.Parse(env.Pool.AccessURL)
186+
iferr!=nil {
187+
clog.LogWarn("invalid access url",clog.Causef("malformed url: %q",env.Pool.AccessURL))
188+
continue
189+
}
190+
newConfig+=makeSSHConfig(u.Host,userName,env.Env.Name,privateKeyFilepath)
219191
}
220192
newConfig+=fmt.Sprintf("\n%s\n",sshEndToken)
221193

222-
returnnewConfig,nil
194+
returnnewConfig
223195
}
224196

225197
funcmakeSSHConfig(host,userName,envName,privateKeyFilepathstring)string {
@@ -235,6 +207,7 @@ func makeSSHConfig(host, userName, envName, privateKeyFilepath string) string {
235207
`,envName,host,userName,envName,privateKeyFilepath)
236208
}
237209

210+
//nolint:deadcode,unused
238211
funcconfiguredHostname() (string,error) {
239212
u,err:=config.URL.Read()
240213
iferr!=nil {

‎internal/cmd/shell.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616

1717
"cdr.dev/coder-cli/coder-sdk"
1818
"cdr.dev/coder-cli/internal/activity"
19+
"cdr.dev/coder-cli/internal/coderutil"
1920
"cdr.dev/coder-cli/internal/x/xterminal"
2021
"cdr.dev/coder-cli/pkg/clog"
2122
"cdr.dev/wsep"
@@ -161,9 +162,9 @@ func runCommand(ctx context.Context, envName, command string, args []string) err
161162
ctx,cancel:=context.WithCancel(ctx)
162163
defercancel()
163164

164-
conn,err:=client.DialWsep(ctx,env.ID)
165+
conn,err:=coderutil.DialEnvWsep(ctx,client,env)
165166
iferr!=nil {
166-
returnxerrors.Errorf("dialwebsocket: %w",err)
167+
returnxerrors.Errorf("dialexecutor: %w",err)
167168
}
168169
goheartbeat(ctx,conn,15*time.Second)
169170

‎internal/coderutil/doc.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Package coderutil providers utilities for high-level operations on coder-sdk entities.
2+
package coderutil

‎internal/coderutil/env.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package coderutil
2+
3+
import (
4+
"context"
5+
"net/url"
6+
7+
"cdr.dev/coder-cli/coder-sdk"
8+
"golang.org/x/xerrors"
9+
"nhooyr.io/websocket"
10+
)
11+
12+
// DialEnvWsep dials the executor endpoint using the https://github.com/cdr/wsep message protocol.
13+
// The proper resource pool access URL is used.
14+
funcDialEnvWsep(ctx context.Context,client*coder.Client,env*coder.Environment) (*websocket.Conn,error) {
15+
resourcePool,err:=client.ResourcePoolByID(ctx,env.ResourcePoolID)
16+
iferr!=nil {
17+
returnnil,xerrors.Errorf("get env resource pool: %w",err)
18+
}
19+
accessURL,err:=url.Parse(resourcePool.AccessURL)
20+
iferr!=nil {
21+
returnnil,xerrors.Errorf("invalid resource pool access url: %w",err)
22+
}
23+
24+
conn,err:=client.DialWsep(ctx,accessURL,env.ID)
25+
iferr!=nil {
26+
returnnil,xerrors.Errorf("dial websocket: %w",err)
27+
}
28+
returnconn,nil
29+
}
30+
31+
// EnvWithPool composes an Environment entity with its associated ResourcePool.
32+
typeEnvWithPoolstruct {
33+
Env coder.Environment
34+
Pool coder.ResourcePool
35+
}
36+
37+
// EnvsWithPool performs the composition of each Environment with its associated ResourcePool.
38+
funcEnvsWithPool(ctx context.Context,client*coder.Client,envs []coder.Environment) ([]EnvWithPool,error) {
39+
pooledEnvs:=make([]EnvWithPool,len(envs))
40+
pools,err:=client.ResourcePools(ctx)
41+
iferr!=nil {
42+
returnnil,err
43+
}
44+
poolMap:=make(map[string]coder.ResourcePool,len(pools))
45+
for_,p:=rangepools {
46+
poolMap[p.ID]=p
47+
}
48+
for_,e:=rangeenvs {
49+
envPool,ok:=poolMap[e.ResourcePoolID]
50+
if!ok {
51+
returnnil,xerrors.Errorf("fetch env resource pool: %w",coder.ErrNotFound)
52+
}
53+
pooledEnvs=append(pooledEnvs,EnvWithPool{
54+
Env:e,
55+
Pool:envPool,
56+
})
57+
}
58+
returnpooledEnvs,nil
59+
}

‎internal/sync/singlefile.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@ import (
1010
"strings"
1111

1212
"cdr.dev/coder-cli/coder-sdk"
13+
"cdr.dev/coder-cli/internal/coderutil"
1314
"cdr.dev/wsep"
1415
"golang.org/x/xerrors"
1516
"nhooyr.io/websocket"
1617
)
1718

1819
// SingleFile copies the given file into the remote dir or remote path of the given coder.Environment.
1920
funcSingleFile(ctx context.Context,local,remoteDirstring,env*coder.Environment,client*coder.Client)error {
20-
conn,err:=client.DialWsep(ctx,env.ID)
21+
conn,err:=coderutil.DialEnvWsep(ctx,client,env)
2122
iferr!=nil {
2223
returnxerrors.Errorf("dial remote execer: %w",err)
2324
}

‎internal/sync/sync.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424

2525
"cdr.dev/coder-cli/coder-sdk"
2626
"cdr.dev/coder-cli/internal/activity"
27+
"cdr.dev/coder-cli/internal/coderutil"
2728
"cdr.dev/coder-cli/pkg/clog"
2829
"cdr.dev/wsep"
2930
)
@@ -89,9 +90,9 @@ func (s Sync) syncPaths(delete bool, local, remote string) error {
8990
}
9091

9192
func (sSync)remoteCmd(ctx context.Context,progstring,args...string)error {
92-
conn,err:=s.Client.DialWsep(ctx,s.Env.ID)
93+
conn,err:=coderutil.DialEnvWsep(ctx,s.Client,&s.Env)
9394
iferr!=nil {
94-
returnxerrors.Errorf("dialwebsocket: %w",err)
95+
returnxerrors.Errorf("dialexecutor: %w",err)
9596
}
9697
deferfunc() {_=conn.Close(websocket.CloseNormalClosure,"") }()// Best effort.
9798

@@ -270,9 +271,9 @@ func (s Sync) Version() (string, error) {
270271
ctx,cancel:=context.WithTimeout(context.Background(),10*time.Second)
271272
defercancel()
272273

273-
conn,err:=s.Client.DialWsep(ctx,s.Env.ID)
274+
conn,err:=coderutil.DialEnvWsep(ctx,s.Client,&s.Env)
274275
iferr!=nil {
275-
return"",err
276+
return"",xerrors.Errorf("dial env executor: %w",err)
276277
}
277278
deferfunc() {_=conn.Close(websocket.CloseNormalClosure,"") }()// Best effort.
278279

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp