This commit is contained in:
insanity 2017-10-23 14:31:04 +09:00
parent 1076082050
commit 1552f4eaba
9 changed files with 413 additions and 50 deletions

96
crawler/crawler.go Normal file
View 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
View File

@ -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)
}

View File

@ -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
View 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
View 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
View 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
View 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
View 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()
}

View File

@ -4,5 +4,5 @@ import "io"
type Stat interface {
Command() string
Parse(r io.Reader) ([]CPUStat, error)
Parse(r io.Reader) (interface{}, error)
}