1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: Apache-2.0
18 "git.arvados.org/arvados.git/lib/controller/rpc"
19 "git.arvados.org/arvados.git/sdk/go/arvados"
22 // shellCommand connects the terminal to an interactive shell on a
24 type shellCommand struct{}
26 func (shellCommand) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
27 f := flag.NewFlagSet(prog, flag.ContinueOnError)
30 fmt.Print(stderr, prog+`: open an interactive shell on a running container.
32 Usage: `+prog+` [options] container-uuid [ssh-options] [remote-command [args...]]
38 detachKeys := f.String("detach-keys", "ctrl-],ctrl-]", "set detach key sequence, as in docker-attach(1)")
41 fmt.Println(stderr, err)
50 targetUUID := f.Args()[0]
51 sshargs := f.Args()[1:]
53 selfbin, err := os.Readlink("/proc/self/exe")
55 fmt.Fprintln(stderr, err)
58 sshargs = append([]string{
59 "-o", "ProxyCommand " + selfbin + " connect-ssh -detach-keys='" + strings.Replace(*detachKeys, "'", "'\\''", -1) + "' " + targetUUID,
60 "-o", "StrictHostKeyChecking no",
61 "root@" + targetUUID},
63 cmd := exec.Command("ssh", sshargs...)
70 } else if exiterr, ok := err.(*exec.ExitError); !ok {
71 fmt.Fprintln(stderr, err)
73 } else if status, ok := exiterr.Sys().(syscall.WaitStatus); !ok {
74 fmt.Fprintln(stderr, err)
77 return status.ExitStatus()
81 // connectSSHCommand connects stdin/stdout to a container's gateway
82 // server (see lib/crunchrun/ssh.go).
84 // It is intended to be invoked with OpenSSH client's ProxyCommand
86 type connectSSHCommand struct{}
88 func (connectSSHCommand) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
89 f := flag.NewFlagSet(prog, flag.ContinueOnError)
92 fmt.Fprint(stderr, prog+`: connect to the gateway service for a running container.
94 Usage: `+prog+` [options] container-uuid
100 detachKeys := f.String("detach-keys", "", "set detach key sequence, as in docker-attach(1)")
101 if err := f.Parse(args); err != nil {
102 fmt.Fprintln(stderr, err)
105 } else if f.NArg() != 1 {
109 targetUUID := f.Args()[0]
110 insecure := os.Getenv("ARVADOS_API_HOST_INSECURE")
111 rpcconn := rpc.NewConn("",
114 Host: os.Getenv("ARVADOS_API_HOST"),
116 insecure == "1" || insecure == "yes" || insecure == "true",
117 func(context.Context) ([]string, error) {
118 return []string{os.Getenv("ARVADOS_API_TOKEN")}, nil
120 // if strings.Contains(targetUUID, "-xvhdp-") {
121 // cr, err := rpcconn.ContainerRequestGet(context.TODO(), arvados.GetOptions{UUID: targetUUID})
123 // fmt.Fprintln(stderr, err)
126 // if cr.ContainerUUID == "" {
127 // fmt.Fprintf(stderr, "no container assigned, container request state is %s\n", strings.ToLower(cr.State))
130 // targetUUID = cr.ContainerUUID
132 sshconn, err := rpcconn.ContainerSSH(context.TODO(), arvados.ContainerSSHOptions{
134 DetachKeys: *detachKeys,
137 fmt.Fprintln(stderr, err)
140 defer sshconn.Conn.Close()
142 ctx, cancel := context.WithCancel(context.Background())
145 _, err := io.Copy(stdout, sshconn.Conn)
146 if err != nil && ctx.Err() == nil {
147 fmt.Fprintf(stderr, "receive: %v\n", err)
152 _, err := io.Copy(sshconn.Conn, stdin)
153 if err != nil && ctx.Err() == nil {
154 fmt.Fprintf(stderr, "send: %v\n", err)