github.com/mirantis/virtlet@v1.5.2-0.20191204181327-1659b8a48e9b/pkg/tools/ssh.go (about) 1 /* 2 Copyright 2018 Mirantis 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package tools 18 19 import ( 20 "errors" 21 "fmt" 22 "io" 23 "os" 24 "os/exec" 25 "strconv" 26 "strings" 27 28 "github.com/renstrom/dedent" 29 "github.com/spf13/cobra" 30 ) 31 32 // sshCommand can be used to ssh into a VM pod. 33 type sshCommand struct { 34 client KubeClient 35 user string 36 podName string 37 args []string 38 out io.Writer 39 sshExecutable string 40 } 41 42 // NewSSHCmd returns a cobra.Command that performs ssh into a VM pod. 43 func NewSSHCmd(client KubeClient, out io.Writer, sshExecutable string) *cobra.Command { 44 ssh := &sshCommand{client: client, out: out, sshExecutable: sshExecutable} 45 return &cobra.Command{ 46 Use: "ssh [flags] user@pod -- [ssh args...]", 47 Short: "Connect to a VM pod using ssh", 48 Long: dedent.Dedent(` 49 This command runs ssh and makes it connect to a VM pod. 50 `), 51 RunE: func(cmd *cobra.Command, args []string) error { 52 if len(args) < 1 { 53 return errors.New("user name and pod name not specified") 54 } 55 parts := strings.Split(args[0], "@") 56 if len(parts) != 2 || len(parts[0]) == 0 || len(parts[1]) == 0 { 57 return errors.New("malformed user@host") 58 } 59 ssh.user = parts[0] 60 ssh.podName = parts[1] 61 ssh.args = args[1:] 62 if sshExecutable == "" { 63 ssh.sshExecutable = "ssh" 64 } else { 65 ssh.sshExecutable = sshExecutable 66 } 67 return ssh.Run() 68 }, 69 } 70 } 71 72 // Run executes the command. 73 func (s *sshCommand) Run() error { 74 // make sure we're dealing with a VM pod 75 _, err := s.client.GetVMPodInfo(s.podName) 76 if err != nil { 77 return err 78 } 79 80 pf := &ForwardedPort{ 81 RemotePort: 22, 82 } 83 stopCh, err := s.client.ForwardPorts(s.podName, "", []*ForwardedPort{pf}) 84 if err != nil { 85 return fmt.Errorf("error forwarding the ssh port: %v", err) 86 } 87 defer close(stopCh) 88 sshArgs := append([]string{ 89 "-q", 90 "-o", 91 "StrictHostKeyChecking=no", 92 "-o", 93 "UserKnownHostsFile=/dev/null", 94 "-p", 95 strconv.Itoa(int(pf.LocalPort)), 96 fmt.Sprintf("%s@127.0.0.1", s.user), 97 }, s.args...) 98 cmd := exec.Command(s.sshExecutable, sshArgs...) 99 cmd.Stdin = os.Stdin 100 cmd.Stdout = s.out 101 cmd.Stderr = os.Stderr 102 if err := cmd.Run(); err != nil { 103 return fmt.Errorf("error executing ssh: %v", err) 104 } 105 return nil 106 }