forked from contiv-experimental/volplugin
/
vagrantnode.go
135 lines (110 loc) · 3.22 KB
/
vagrantnode.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/***
Copyright 2014 Cisco Systems Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package utils
import (
"fmt"
"io/ioutil"
"net"
"golang.org/x/crypto/ssh"
)
// VagrantNode implements a node in vagrant testbed
type VagrantNode struct {
Name string
primaryIP net.IP
client *ssh.Client
}
//NewVagrantNode intializes a node in vagrant testbed
func NewVagrantNode(name, port, privKeyFile string) (*VagrantNode, error) {
var (
vnode *VagrantNode
err error
signer ssh.Signer
privateKey []byte
)
if privateKey, err = ioutil.ReadFile(privKeyFile); err != nil {
return nil, err
}
if signer, err = ssh.ParsePrivateKey(privateKey); err != nil {
return nil, err
}
config := &ssh.ClientConfig{
User: "vagrant",
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
}
vnode = &VagrantNode{Name: name}
if vnode.client, err = ssh.Dial("tcp", fmt.Sprintf("127.0.0.1:%s", port), config); err != nil {
return nil, err
}
return vnode, nil
}
//Cleanup clears the ssh client resources
func (n *VagrantNode) Cleanup() {
n.client.Close()
}
func newCmdStrWithSource(cmd string) string {
// we need to source the environment manually as the ssh package client
// doesn't do it automatically (I guess something to do with non interative
// mode)
return fmt.Sprintf("bash -lc '%s'", cmd)
}
// RunCommand runs a shell command in a vagrant node and returns it's exit status
func (n *VagrantNode) RunCommand(cmd string) error {
var (
s *ssh.Session
err error
)
if s, err = n.client.NewSession(); err != nil {
return err
}
defer s.Close()
if err := s.RequestPty("vt100", 80, 25, ssh.TerminalModes{}); err != nil {
fmt.Println(err)
return err
}
return s.Run(newCmdStrWithSource(cmd))
}
// RunCommandWithOutput runs a shell command in a vagrant node and returns it's
// exit status and output
func (n *VagrantNode) RunCommandWithOutput(cmd string) (string, error) {
var (
s *ssh.Session
err error
)
if s, err = n.client.NewSession(); err != nil {
return "", err
}
defer s.Close()
output, err := s.CombinedOutput(newCmdStrWithSource(cmd))
return string(output), err
}
// RunCommandBackground runs a background command in a vagrant node
func (n *VagrantNode) RunCommandBackground(cmd string) (string, error) {
var (
s *ssh.Session
err error
)
if s, err = n.client.NewSession(); err != nil {
return "", err
}
defer s.Close()
// start and forget about the command as user asked to run in background.
// The limitation is we/ won't know if it fails though. Not a worry right
// now as the test will fail anyways, but might be good to find a better way.
return "", s.Start(newCmdStrWithSource(cmd))
}
// GetName returns vagrant node's name
func (n *VagrantNode) GetName() string {
return n.Name
}