ing
This commit is contained in:
parent
1076082050
commit
1552f4eaba
96
crawler/crawler.go
Normal file
96
crawler/crawler.go
Normal file
|
@ -0,0 +1,96 @@
|
|||
package crawler
|
||||
|
||||
import (
|
||||
"git.loafle.net/overflow/ssh_crawler/ssh"
|
||||
"git.loafle.net/overflow/ssh_crawler/stat"
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type Crawler struct {
|
||||
sshCli *ssh.SSHClient
|
||||
}
|
||||
|
||||
func New(ip, port, user, pw string) (*Crawler, error) {
|
||||
c := &Crawler{}
|
||||
err := c.connectSSH(ip, port, user, pw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *Crawler) connectSSH(ip, port, user, pw string) error {
|
||||
client, err := ssh.New(ip, port, user, pw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.sshCli = client
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
func (c *Crawler) CPUStat()([]stat.CPUStat, error) {
|
||||
cpu := &stat.CPUStat{}
|
||||
|
||||
b, err := c.sshCli.RunCommand(cpu.Command())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cpu.Parse(bytes.NewReader(b))
|
||||
}
|
||||
|
||||
func (c *Crawler) MEMStat()(map[string]string, error) {
|
||||
mem := &stat.MEMStat{}
|
||||
|
||||
b, err := c.sshCli.RunCommand(mem.Command())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mem.Parse(bytes.NewReader(b))
|
||||
}
|
||||
|
||||
func (c *Crawler) DiskIOStat()([]stat.DiskIOStat, error) {
|
||||
diskio := &stat.DiskIOStat{}
|
||||
|
||||
b, err := c.sshCli.RunCommand(diskio.Command())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return diskio.Parse(bytes.NewReader(b))
|
||||
}
|
||||
|
||||
func (c *Crawler) DiskFreeStat()([]stat.DiskFreeStat, error) {
|
||||
diskFree := &stat.DiskFreeStat{}
|
||||
|
||||
b, err := c.sshCli.RunCommand(diskFree.Command())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return diskFree.Parse(bytes.NewReader(b))
|
||||
}
|
||||
|
||||
func (c *Crawler) LoadAvgStat()(stat.LoadAvg, error) {
|
||||
load := &stat.LoadAvg{}
|
||||
|
||||
b, err := c.sshCli.RunCommand(load.Command())
|
||||
if err != nil {
|
||||
return stat.LoadAvg{}, err
|
||||
}
|
||||
|
||||
return load.Parse(bytes.NewReader(b))
|
||||
}
|
||||
|
||||
func (c *Crawler) NetworkStat() ([]stat.NetDevStat, error) {
|
||||
net := &stat.NetDevStat{}
|
||||
b, err := c.sshCli.RunCommand(net.Command())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return net.Parse(bytes.NewReader(b))
|
||||
}
|
53
main.go
53
main.go
|
@ -1,8 +1,8 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"git.loafle.net/overflow/ssh_crawler/ssh"
|
||||
"fmt"
|
||||
"git.loafle.net/overflow/ssh_crawler/crawler"
|
||||
)
|
||||
|
||||
|
||||
|
@ -13,29 +13,56 @@ func main() {
|
|||
const user = "administrator"
|
||||
const pw = "!@#$qwer1234"
|
||||
|
||||
client, err := connectSSH(ip, port, user, pw)
|
||||
cr, err := crawler.New(ip, port, user, pw)
|
||||
if err != nil {
|
||||
fmt.Errorf("%s", err)
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
res, err := client.CPUStat()
|
||||
//CPU
|
||||
cpu, err := cr.CPUStat()
|
||||
if err != nil {
|
||||
fmt.Errorf("%s", err)
|
||||
fmt.Printf("err : %s\n", err)
|
||||
}
|
||||
fmt.Printf("%s", res)
|
||||
fmt.Printf("CPU: %s\n", cpu)
|
||||
|
||||
client.Close()
|
||||
}
|
||||
|
||||
func connectSSH(ip, port, user, pw string) (*ssh.SSHClient, error){
|
||||
client, err := ssh.New(ip, port, user, pw)
|
||||
//MEM
|
||||
mem, err := cr.MEMStat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
fmt.Printf("err : %s\n", err)
|
||||
}
|
||||
return client, nil
|
||||
fmt.Printf("MEM: %s\n", mem)
|
||||
|
||||
//Disk IO
|
||||
diskio, err := cr.DiskIOStat()
|
||||
if err != nil {
|
||||
fmt.Printf("err : %s\n", err)
|
||||
}
|
||||
fmt.Printf("DiskIO: %s\n", diskio)
|
||||
|
||||
//Disk Free
|
||||
diskFree, err := cr.DiskFreeStat()
|
||||
if err != nil {
|
||||
fmt.Printf("err : %s\n", err)
|
||||
}
|
||||
fmt.Printf("DiskFree: %s\n", diskFree)
|
||||
|
||||
//Load Avg.
|
||||
load, err := cr.LoadAvgStat()
|
||||
if err != nil {
|
||||
fmt.Printf("err : %s\n", err)
|
||||
}
|
||||
fmt.Printf("Load: %s\n", load)
|
||||
|
||||
//Network
|
||||
net, err := cr.NetworkStat()
|
||||
if err != nil {
|
||||
fmt.Printf("err : %s\n", err)
|
||||
}
|
||||
fmt.Printf("Net: %s\n", net)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
58
ssh/ssh.go
58
ssh/ssh.go
|
@ -4,7 +4,6 @@ import (
|
|||
"fmt"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"bytes"
|
||||
"git.loafle.net/overflow/ssh_crawler/stat"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
|
@ -16,12 +15,13 @@ type SSHConfig struct {
|
|||
}
|
||||
|
||||
type SSHClient struct {
|
||||
Session *ssh.Session
|
||||
session *ssh.Session
|
||||
conf *SSHConfig
|
||||
}
|
||||
|
||||
func New(ip, port, user, pw string) (*SSHClient, error) {
|
||||
p, _ := strconv.Atoi(port)
|
||||
info := &SSHConfig {
|
||||
conf := &SSHConfig {
|
||||
User: user,
|
||||
Auth: []ssh.AuthMethod{
|
||||
ssh.Password(pw),
|
||||
|
@ -29,31 +29,24 @@ func New(ip, port, user, pw string) (*SSHClient, error) {
|
|||
Host: ip,
|
||||
Port: p,
|
||||
}
|
||||
session, err := info.Session()
|
||||
if err != nil {
|
||||
fmt.Errorf("%s", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &SSHClient{
|
||||
Session: session,
|
||||
}, nil
|
||||
return &SSHClient{conf:conf}, nil
|
||||
}
|
||||
|
||||
func (info *SSHConfig) Session() (*ssh.Session, error) {
|
||||
func (cli *SSHClient) Session() error {
|
||||
sshConfig := &ssh.ClientConfig{
|
||||
User: info.User,
|
||||
Auth: info.Auth,
|
||||
User: cli.conf.User,
|
||||
Auth: cli.conf.Auth,
|
||||
HostKeyCallback:ssh.InsecureIgnoreHostKey(),
|
||||
}
|
||||
|
||||
connection, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", info.Host, info.Port), sshConfig)
|
||||
connection, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", cli.conf.Host, cli.conf.Port), sshConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
session, err := connection.NewSession()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
modes := ssh.TerminalModes{
|
||||
|
@ -64,37 +57,30 @@ func (info *SSHConfig) Session() (*ssh.Session, error) {
|
|||
|
||||
if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
|
||||
session.Close()
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
cli.session = session
|
||||
|
||||
return session, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *SSHClient) Close() {
|
||||
cli.Session.Close()
|
||||
}
|
||||
|
||||
func (cli *SSHClient) RunCommand(command string) ([]byte, error) {
|
||||
|
||||
var b bytes.Buffer
|
||||
cli.Session.Stdout = &b
|
||||
if err := cli.Session(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err := cli.Session.Run(command)
|
||||
var b bytes.Buffer
|
||||
cli.session.Stdout = &b
|
||||
|
||||
err := cli.session.Run(command)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cli.session.Close()
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
func (cli *SSHClient) CPUStat()([]stat.CPUStat, error) {
|
||||
cpu := &stat.CPUStat{}
|
||||
|
||||
b, err := cli.RunCommand(cpu.Command())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cpu.Parse(bytes.NewReader(b))
|
||||
}
|
||||
|
|
49
stat/disk_free.go
Normal file
49
stat/disk_free.go
Normal file
|
@ -0,0 +1,49 @@
|
|||
package stat
|
||||
|
||||
import (
|
||||
"io"
|
||||
"bufio"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type DiskFreeStat struct {
|
||||
filesystem,
|
||||
size,
|
||||
used,
|
||||
available,
|
||||
usePerc,
|
||||
mountedOn string
|
||||
}
|
||||
|
||||
func (diskFree DiskFreeStat) Command() string {
|
||||
return "df -k"
|
||||
}
|
||||
|
||||
func (diskio DiskFreeStat) Parse(r io.Reader) ([]DiskFreeStat, error) {
|
||||
|
||||
var scanner = bufio.NewScanner(r)
|
||||
var stats = []DiskFreeStat{}
|
||||
|
||||
scanner.Scan()
|
||||
for scanner.Scan() {
|
||||
parts := strings.Fields(scanner.Text())
|
||||
stats = append(stats, DiskFreeStat{
|
||||
filesystem: parts[0],
|
||||
size: parts[1],
|
||||
used: parts[2],
|
||||
available: parts[3],
|
||||
usePerc: removePercUnit(parts[4]),
|
||||
mountedOn: parts[5],
|
||||
})
|
||||
}
|
||||
|
||||
return stats, scanner.Err()
|
||||
}
|
||||
|
||||
func removePercUnit(str string) string {
|
||||
if !strings.HasSuffix(str, "%"){
|
||||
return str
|
||||
}
|
||||
str = str[:len(str)-1]
|
||||
return str
|
||||
}
|
62
stat/disk_io.go
Normal file
62
stat/disk_io.go
Normal file
|
@ -0,0 +1,62 @@
|
|||
package stat
|
||||
|
||||
import (
|
||||
"io"
|
||||
"bufio"
|
||||
"strings"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type DiskIOStat struct {
|
||||
device,
|
||||
readCompleted,
|
||||
readMerged,
|
||||
sectorRead,
|
||||
timeSpentReading,
|
||||
writesCompleted,
|
||||
writesMerged,
|
||||
sectorsWritten,
|
||||
timeSpentWriting,
|
||||
ioInProg,
|
||||
timeSpentIO,
|
||||
weightedTimeSpentIO string
|
||||
}
|
||||
|
||||
func (diskio DiskIOStat) Command() string {
|
||||
return "cat /proc/diskstats"
|
||||
}
|
||||
|
||||
func (diskio DiskIOStat) Parse(r io.Reader) ([]DiskIOStat, error) {
|
||||
var (
|
||||
DiskIOStats = []DiskIOStat{}
|
||||
scanner = bufio.NewScanner(r)
|
||||
)
|
||||
|
||||
for scanner.Scan() {
|
||||
parts := strings.Fields(scanner.Text())
|
||||
if len(parts) < 4 {
|
||||
return nil, fmt.Errorf("invalid line in %s: %s", "/proc/diskstats", scanner.Text())
|
||||
}
|
||||
deviceName := parts[2]
|
||||
if !strings.HasPrefix(deviceName, "sd") {
|
||||
continue
|
||||
}
|
||||
DiskIOStats = append(DiskIOStats, DiskIOStat{
|
||||
device: deviceName,
|
||||
readCompleted: parts[3],
|
||||
readMerged: parts[4],
|
||||
sectorRead: parts[5],
|
||||
timeSpentReading: parts[6],
|
||||
writesCompleted: parts[7],
|
||||
writesMerged: parts[8],
|
||||
sectorsWritten: parts[9],
|
||||
timeSpentWriting: parts[10],
|
||||
ioInProg: parts[11],
|
||||
timeSpentIO: parts[12],
|
||||
weightedTimeSpentIO: parts[13],
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
return DiskIOStats, scanner.Err()
|
||||
}
|
33
stat/loadavg.go
Normal file
33
stat/loadavg.go
Normal file
|
@ -0,0 +1,33 @@
|
|||
package stat
|
||||
|
||||
import (
|
||||
"io"
|
||||
"bufio"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type LoadAvg struct {
|
||||
min1,
|
||||
min5,
|
||||
min15 string
|
||||
}
|
||||
|
||||
func (loadavg LoadAvg) Command() string {
|
||||
return "cat /proc/loadavg"
|
||||
}
|
||||
|
||||
func (loadavg LoadAvg) Parse(r io.Reader) (LoadAvg, error) {
|
||||
var (
|
||||
scanner = bufio.NewScanner(r)
|
||||
)
|
||||
|
||||
load := LoadAvg{}
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
parts := strings.Fields(line)
|
||||
load.min1 = parts[0]
|
||||
load.min5 = parts[1]
|
||||
load.min15 = parts[2]
|
||||
}
|
||||
return load, scanner.Err()
|
||||
}
|
31
stat/mem.go
Normal file
31
stat/mem.go
Normal file
|
@ -0,0 +1,31 @@
|
|||
package stat
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
"bufio"
|
||||
)
|
||||
|
||||
type MEMStat struct {
|
||||
|
||||
}
|
||||
|
||||
func (cpu MEMStat) Command() string {
|
||||
return "cat /proc/meminfo"
|
||||
}
|
||||
|
||||
func (cpu MEMStat) Parse(r io.Reader) (map[string]string, error) {
|
||||
var (
|
||||
memInfo = map[string]string{}
|
||||
scanner = bufio.NewScanner(r)
|
||||
)
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
parts := strings.Fields(line)
|
||||
key := parts[0][:len(parts[0])-1]
|
||||
memInfo[key] = parts[1]
|
||||
}
|
||||
|
||||
return memInfo, scanner.Err()
|
||||
}
|
79
stat/network.go
Normal file
79
stat/network.go
Normal file
|
@ -0,0 +1,79 @@
|
|||
package stat
|
||||
|
||||
import (
|
||||
"io"
|
||||
"bufio"
|
||||
"regexp"
|
||||
"strings"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type NetDevStat struct {
|
||||
iface,
|
||||
recvByte,
|
||||
recvPacket,
|
||||
recvErr,
|
||||
recvDrop,
|
||||
recvFifo,
|
||||
recvFrame,
|
||||
recvCompressed,
|
||||
recvMulticast,
|
||||
transByte,
|
||||
transPacket,
|
||||
transErr,
|
||||
transDrop,
|
||||
transFifo,
|
||||
transFrame,
|
||||
transCompressed,
|
||||
transMulticast string
|
||||
}
|
||||
|
||||
func (net *NetDevStat) Command() string {
|
||||
return "cat /proc/net/dev"
|
||||
}
|
||||
|
||||
func (net *NetDevStat) Parse(r io.Reader) ([]NetDevStat, error) {
|
||||
var (
|
||||
scanner = bufio.NewScanner(r)
|
||||
procNetDevFieldSep = regexp.MustCompile("[ :] *")
|
||||
netDevStats = []NetDevStat{}
|
||||
)
|
||||
scanner.Scan()
|
||||
scanner.Scan()
|
||||
parts := strings.Split(scanner.Text(), "|")
|
||||
if len(parts) != 3 { // interface + receive + transmit
|
||||
return nil, fmt.Errorf("invalid header line in net/dev: %s",
|
||||
scanner.Text())
|
||||
}
|
||||
|
||||
header := strings.Fields(parts[1])
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimLeft(scanner.Text(), " ")
|
||||
parts := procNetDevFieldSep.Split(line, -1)
|
||||
if len(parts) != 2*len(header)+1 {
|
||||
return nil, fmt.Errorf("invalid line in net/dev: %s", scanner.Text())
|
||||
}
|
||||
|
||||
dev := parts[0][:len(parts[0])]
|
||||
netDevStats = append(netDevStats, NetDevStat{
|
||||
iface: dev,
|
||||
recvByte: parts[1],
|
||||
recvPacket: parts[2],
|
||||
recvErr: parts[3],
|
||||
recvDrop: parts[4],
|
||||
recvFifo: parts[5],
|
||||
recvFrame: parts[6],
|
||||
recvCompressed: parts[7],
|
||||
recvMulticast: parts[8],
|
||||
transByte: parts[9],
|
||||
transPacket: parts[10],
|
||||
transErr: parts[11],
|
||||
transDrop: parts[12],
|
||||
transFifo: parts[13],
|
||||
transFrame: parts[14],
|
||||
transCompressed: parts[15],
|
||||
transMulticast: parts[16],
|
||||
})
|
||||
}
|
||||
return netDevStats, scanner.Err()
|
||||
}
|
|
@ -4,5 +4,5 @@ import "io"
|
|||
|
||||
type Stat interface {
|
||||
Command() string
|
||||
Parse(r io.Reader) ([]CPUStat, error)
|
||||
Parse(r io.Reader) (interface{}, error)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user