github.com/bendemaree/terraform@v0.5.4-0.20150613200311-f50d97d6eee6/communicator/ssh/communicator_test.go (about) 1 // +build !race 2 3 package ssh 4 5 import ( 6 "bytes" 7 "fmt" 8 "net" 9 "regexp" 10 "strings" 11 "testing" 12 13 "github.com/hashicorp/terraform/communicator/remote" 14 "github.com/hashicorp/terraform/terraform" 15 "golang.org/x/crypto/ssh" 16 ) 17 18 // private key for mock server 19 const testServerPrivateKey = `-----BEGIN RSA PRIVATE KEY----- 20 MIIEpAIBAAKCAQEA19lGVsTqIT5iiNYRgnoY1CwkbETW5cq+Rzk5v/kTlf31XpSU 21 70HVWkbTERECjaYdXM2gGcbb+sxpq6GtXf1M3kVomycqhxwhPv4Cr6Xp4WT/jkFx 22 9z+FFzpeodGJWjOH6L2H5uX1Cvr9EDdQp9t9/J32/qBFntY8GwoUI/y/1MSTmMiF 23 tupdMODN064vd3gyMKTwrlQ8tZM6aYuyOPsutLlUY7M5x5FwMDYvnPDSeyT/Iw0z 24 s3B+NCyqeeMd2T7YzQFnRATj0M7rM5LoSs7DVqVriOEABssFyLj31PboaoLhOKgc 25 qoM9khkNzr7FHVvi+DhYM2jD0DwvqZLN6NmnLwIDAQABAoIBAQCGVj+kuSFOV1lT 26 +IclQYA6bM6uY5mroqcSBNegVxCNhWU03BxlW//BE9tA/+kq53vWylMeN9mpGZea 27 riEMIh25KFGWXqXlOOioH8bkMsqA8S7sBmc7jljyv+0toQ9vCCtJ+sueNPhxQQxH 28 D2YvUjfzBQ04I9+wn30BByDJ1QA/FoPsunxIOUCcRBE/7jxuLYcpR+JvEF68yYIh 29 atXRld4W4in7T65YDR8jK1Uj9XAcNeDYNpT/M6oFLx1aPIlkG86aCWRO19S1jLPT 30 b1ZAKHHxPMCVkSYW0RqvIgLXQOR62D0Zne6/2wtzJkk5UCjkSQ2z7ZzJpMkWgDgN 31 ifCULFPBAoGBAPoMZ5q1w+zB+knXUD33n1J+niN6TZHJulpf2w5zsW+m2K6Zn62M 32 MXndXlVAHtk6p02q9kxHdgov34Uo8VpuNjbS1+abGFTI8NZgFo+bsDxJdItemwC4 33 KJ7L1iz39hRN/ZylMRLz5uTYRGddCkeIHhiG2h7zohH/MaYzUacXEEy3AoGBANz8 34 e/msleB+iXC0cXKwds26N4hyMdAFE5qAqJXvV3S2W8JZnmU+sS7vPAWMYPlERPk1 35 D8Q2eXqdPIkAWBhrx4RxD7rNc5qFNcQWEhCIxC9fccluH1y5g2M+4jpMX2CT8Uv+ 36 3z+NoJ5uDTXZTnLCfoZzgZ4nCZVZ+6iU5U1+YXFJAoGBANLPpIV920n/nJmmquMj 37 orI1R/QXR9Cy56cMC65agezlGOfTYxk5Cfl5Ve+/2IJCfgzwJyjWUsFx7RviEeGw 38 64o7JoUom1HX+5xxdHPsyZ96OoTJ5RqtKKoApnhRMamau0fWydH1yeOEJd+TRHhc 39 XStGfhz8QNa1dVFvENczja1vAoGABGWhsd4VPVpHMc7lUvrf4kgKQtTC2PjA4xoc 40 QJ96hf/642sVE76jl+N6tkGMzGjnVm4P2j+bOy1VvwQavKGoXqJBRd5Apppv727g 41 /SM7hBXKFc/zH80xKBBgP/i1DR7kdjakCoeu4ngeGywvu2jTS6mQsqzkK+yWbUxJ 42 I7mYBsECgYB/KNXlTEpXtz/kwWCHFSYA8U74l7zZbVD8ul0e56JDK+lLcJ0tJffk 43 gqnBycHj6AhEycjda75cs+0zybZvN4x65KZHOGW/O/7OAWEcZP5TPb3zf9ned3Hl 44 NsZoFj52ponUM6+99A2CmezFCN16c4mbA//luWF+k3VVqR6BpkrhKw== 45 -----END RSA PRIVATE KEY-----` 46 47 var serverConfig = &ssh.ServerConfig{ 48 PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) { 49 if c.User() == "user" && string(pass) == "pass" { 50 return nil, nil 51 } 52 return nil, fmt.Errorf("password rejected for %q", c.User()) 53 }, 54 } 55 56 func init() { 57 // Parse and set the private key of the server, required to accept connections 58 signer, err := ssh.ParsePrivateKey([]byte(testServerPrivateKey)) 59 if err != nil { 60 panic("unable to parse private key: " + err.Error()) 61 } 62 serverConfig.AddHostKey(signer) 63 } 64 65 func newMockLineServer(t *testing.T) string { 66 l, err := net.Listen("tcp", "127.0.0.1:0") 67 if err != nil { 68 t.Fatalf("Unable to listen for connection: %s", err) 69 } 70 71 go func() { 72 defer l.Close() 73 c, err := l.Accept() 74 if err != nil { 75 t.Errorf("Unable to accept incoming connection: %s", err) 76 } 77 defer c.Close() 78 conn, chans, _, err := ssh.NewServerConn(c, serverConfig) 79 if err != nil { 80 t.Logf("Handshaking error: %v", err) 81 } 82 t.Log("Accepted SSH connection") 83 84 for newChannel := range chans { 85 channel, requests, err := newChannel.Accept() 86 if err != nil { 87 t.Errorf("Unable to accept channel.") 88 } 89 t.Log("Accepted channel") 90 91 go func(in <-chan *ssh.Request) { 92 for req := range in { 93 if req.WantReply { 94 req.Reply(true, nil) 95 } 96 } 97 }(requests) 98 99 go func(newChannel ssh.NewChannel) { 100 conn.OpenChannel(newChannel.ChannelType(), nil) 101 }(newChannel) 102 103 defer channel.Close() 104 } 105 conn.Close() 106 }() 107 108 return l.Addr().String() 109 } 110 111 func TestNew_Invalid(t *testing.T) { 112 address := newMockLineServer(t) 113 parts := strings.Split(address, ":") 114 115 r := &terraform.InstanceState{ 116 Ephemeral: terraform.EphemeralState{ 117 ConnInfo: map[string]string{ 118 "type": "ssh", 119 "user": "user", 120 "password": "i-am-invalid", 121 "host": parts[0], 122 "port": parts[1], 123 "timeout": "30s", 124 }, 125 }, 126 } 127 128 c, err := New(r) 129 if err != nil { 130 t.Fatalf("error creating communicator: %s", err) 131 } 132 133 err = c.Connect(nil) 134 if err == nil { 135 t.Fatal("should have had an error connecting") 136 } 137 } 138 139 func TestStart(t *testing.T) { 140 address := newMockLineServer(t) 141 parts := strings.Split(address, ":") 142 143 r := &terraform.InstanceState{ 144 Ephemeral: terraform.EphemeralState{ 145 ConnInfo: map[string]string{ 146 "type": "ssh", 147 "user": "user", 148 "password": "pass", 149 "host": parts[0], 150 "port": parts[1], 151 "timeout": "30s", 152 }, 153 }, 154 } 155 156 c, err := New(r) 157 if err != nil { 158 t.Fatalf("error creating communicator: %s", err) 159 } 160 161 var cmd remote.Cmd 162 stdout := new(bytes.Buffer) 163 cmd.Command = "echo foo" 164 cmd.Stdout = stdout 165 166 err = c.Start(&cmd) 167 if err != nil { 168 t.Fatalf("error executing remote command: %s", err) 169 } 170 } 171 172 func TestScriptPath(t *testing.T) { 173 cases := []struct { 174 Input string 175 Pattern string 176 }{ 177 { 178 "/tmp/script.sh", 179 `^/tmp/script\.sh$`, 180 }, 181 { 182 "/tmp/script_%RAND%.sh", 183 `^/tmp/script_(\d+)\.sh$`, 184 }, 185 } 186 187 for _, tc := range cases { 188 comm := &Communicator{connInfo: &connectionInfo{ScriptPath: tc.Input}} 189 output := comm.ScriptPath() 190 191 match, err := regexp.Match(tc.Pattern, []byte(output)) 192 if err != nil { 193 t.Fatalf("bad: %s\n\nerr: %s", tc.Input, err) 194 } 195 if !match { 196 t.Fatalf("bad: %s\n\n%s", tc.Input, output) 197 } 198 } 199 }