1
1
package platform
2
2
3
3
import (
4
+ "bufio"
5
+ "bytes"
4
6
"net"
5
7
"os"
8
+ "strconv"
9
+ "strings"
6
10
7
11
"github.com/pkg/errors"
8
12
"golang.org/x/crypto/ssh"
@@ -18,12 +22,12 @@ type SSH struct {
18
22
}
19
23
20
24
// TODO accept more method of connection than only via ssh-agent
21
- func NewSSHClient (username , addr string ) (SSH , error ) {
25
+ func NewSSHClient (username , addr string ) (* SSH , error ) {
22
26
sshClient , err := createAgentAuth (username , addr )
23
27
if err != nil {
24
- return SSH {} , err
28
+ return nil , err
25
29
}
26
- return SSH {
30
+ return & SSH {
27
31
client : sshClient ,
28
32
}, nil
29
33
}
@@ -48,3 +52,84 @@ func createAgentAuth(username, addr string) (*ssh.Client, error) {
48
52
49
53
return ssh .Dial ("tcp" , addr , config )
50
54
}
55
+
56
+ // Run a command on remote server via SSH
57
+ func (s * SSH ) Run (command string ) (string , error ) {
58
+ session , err := s .client .NewSession ()
59
+ if err != nil {
60
+ return "" , errors .Wrapf (err , "can't create session with SSH client for command %s" , command )
61
+ }
62
+ defer session .Close ()
63
+
64
+ var buf bytes.Buffer
65
+ session .Stdout = & buf
66
+ err = session .Run (command )
67
+ if err != nil {
68
+ return "" , errors .Wrapf (err , "can't run command %s on remote server" , command )
69
+ }
70
+
71
+ return string (buf .Bytes ()), nil
72
+ }
73
+
74
+ func (s * SSH ) getMemoryInfo (headers []string , metrics []string ) (cells [][]string , err error ) {
75
+ lines , err := s .Run ("/bin/cat /proc/meminfo" )
76
+ if err != nil {
77
+ return nil , err
78
+ }
79
+
80
+ scanner := bufio .NewScanner (strings .NewReader (lines ))
81
+ var data string
82
+ for scanner .Scan () {
83
+ line := scanner .Text ()
84
+ parts := strings .Fields (line )
85
+
86
+ if len (parts ) == 3 {
87
+ val , err := strconv .ParseUint (parts [1 ], 10 , 64 )
88
+ val = incSizeMetric (val )
89
+ if err != nil {
90
+ data += "unknown" + ","
91
+ continue
92
+ }
93
+
94
+ for _ , v := range metrics {
95
+ if parts [0 ] == v {
96
+ data += strconv .FormatInt (int64 (val ), 10 ) + ","
97
+ }
98
+ }
99
+ }
100
+ }
101
+
102
+ cells = append (cells , headers )
103
+ for _ , v := range formatToTable (headers , data ) {
104
+ cells = append (cells , v )
105
+ }
106
+
107
+ return cells , nil
108
+ }
109
+
110
+ // formatToTable display.
111
+ // The string needs to have this:
112
+ // Info needs to be splitted with comma
113
+ // Depending on number of columns (headers)
114
+ // TODO improve this comment :D
115
+ func formatToTable (headers []string , data string ) (cells [][]string ) {
116
+ col := len (headers )
117
+ c := strings .Split (data , "," )
118
+ lenCells := len (c )
119
+ for i := 0 ; i < lenCells ; i += col {
120
+ cells = append (cells , c [i :min (i + col , lenCells )])
121
+ }
122
+
123
+ return cells
124
+ }
125
+
126
+ func min (a , b int ) int {
127
+ if a <= b {
128
+ return a
129
+ }
130
+ return b
131
+ }
132
+
133
+ func incSizeMetric (val uint64 ) uint64 {
134
+ return val / 1024
135
+ }
0 commit comments