Skip to content
This repository was archived by the owner on Jan 17, 2021. It is now read-only.

Commit 0d19aed

Browse files
committed
Add support for specifying GCP instances
- Specifying 'gcp:<instance-name>' for the host argument is now supported for indicating a Google Cloud compute instance
1 parent 1b8bf23 commit 0d19aed

File tree

3 files changed

+63
-3
lines changed

3 files changed

+63
-3
lines changed

main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ Environment variables:
7474
More info: https://github.com/cdr/sshcode
7575
7676
Arguments:
77-
%vHOST is passed into the ssh command.
77+
%vHOST is passed into the ssh command. Valid formats are '<ip-address>' or 'gcp:<instance-name>'.
7878
%vDIR is optional.
7979
8080
%v`,

sshcode.go

+61-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ type options struct {
3232
func sshCode(host, dir string, o options) error {
3333
flog.Info("ensuring code-server is updated...")
3434

35+
host, extraSSHFlags, err := parseIP(host)
36+
if err != nil {
37+
return xerrors.Errorf("failed to parse host IP: %w", err)
38+
}
39+
if extraSSHFlags != "" {
40+
o.sshFlags = strings.Join([]string{extraSSHFlags, o.sshFlags}, " ")
41+
}
42+
3543
dlScript := downloadScript(codeServerPath)
3644

3745
// Downloads the latest code-server and allows it to be executed.
@@ -41,7 +49,7 @@ func sshCode(host, dir string, o options) error {
4149
sshCmd.Stdout = os.Stdout
4250
sshCmd.Stderr = os.Stderr
4351
sshCmd.Stdin = strings.NewReader(dlScript)
44-
err := sshCmd.Run()
52+
err = sshCmd.Run()
4553
if err != nil {
4654
return xerrors.Errorf("failed to update code-server: \n---ssh cmd---\n%s\n---download script---\n%s: %w",
4755
sshCmdStr,
@@ -341,3 +349,55 @@ func ensureDir(path string) error {
341349

342350
return nil
343351
}
352+
353+
// parseIP parses the host to a valid IP address. If 'gcp:' is prefixed to the
354+
// host then a lookup is done using gcloud to determine the external IP and any
355+
// additional SSH arguments that should be used for ssh commands.
356+
func parseIP(host string) (ip string, additionalFlags string, err error) {
357+
host = strings.TrimSpace(host)
358+
switch {
359+
case strings.HasPrefix(host, "gcp:"):
360+
instance := strings.TrimPrefix(host, "gcp:")
361+
return parseGCPSSHCmd(instance)
362+
default:
363+
if net.ParseIP(host) == nil {
364+
return "", "", xerrors.New("host argument is not a valid IP address")
365+
}
366+
return host, "", nil
367+
}
368+
}
369+
370+
// parseGCPSSHCmd parses the IP address and flags used by 'gcloud' when
371+
// ssh'ing to an instance.
372+
func parseGCPSSHCmd(instance string) (ip, sshFlags string, err error) {
373+
dryRunCmd := fmt.Sprintf("gcloud compute ssh --dry-run %v", instance)
374+
375+
out, err := exec.Command("sh", "-c", dryRunCmd).CombinedOutput()
376+
if err != nil {
377+
return "", "", xerrors.Errorf("%s: %w", out, err)
378+
}
379+
380+
toks := strings.Split(string(out), " ")
381+
if len(toks) < 2 {
382+
return "", "", xerrors.Errorf("unexpected output for '%v' command, %s", dryRunCmd, out)
383+
}
384+
385+
// Slice off the '/usr/bin/ssh' prefix and the '<user>@<ip>' suffix.
386+
sshFlags = strings.Join(toks[1:len(toks)-1], " ")
387+
388+
389+
userIP := toks[len(toks)-1]
390+
toks = strings.Split(userIP, "@")
391+
// Assume the '<user>@' is missing.
392+
if len(toks) < 2 {
393+
ip = strings.TrimSpace(toks[0])
394+
} else {
395+
ip = strings.TrimSpace(toks[1])
396+
}
397+
398+
if net.ParseIP(ip) == nil {
399+
return "", "", xerrors.Errorf("parsed invalid ip address %v", ip)
400+
}
401+
402+
return ip, sshFlags, nil
403+
}

sshcode_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ func waitForSSHCode(t *testing.T, port string, timeout time.Duration) {
261261
}
262262
}
263263

264-
// fakeRSAKey isn't used for anything other than the trashh ssh
264+
// fakeRSAKey isn't used for anything other than the trassh ssh
265265
// server.
266266
const fakeRSAKey = `-----BEGIN RSA PRIVATE KEY-----
267267
MIIEpQIBAAKCAQEAsbbGAxPQeqti2OgdzuMgJGBAwXe/bFhQTPuk0bIvavkZwX/a

0 commit comments

Comments
 (0)