Files
linuxkit/alpine/packages/diagnostics/capture.go
Nathan LeClaire a9ced0a205 Fix error in diagnostic server init code
Signed-off-by: Nathan LeClaire <nathan.leclaire@gmail.com>
2016-07-20 13:48:21 -07:00

171 lines
4.5 KiB
Go

package main
import (
"archive/tar"
"bytes"
"io"
"log"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"time"
)
var (
commonCmdCaptures = []CommandCapturer{
{"/bin/date", nil},
{"/bin/uname", []string{"-a"}},
{"/bin/ps", []string{"uax"}},
{"/bin/netstat", []string{"-tulpn"}},
{"/sbin/iptables-save", nil},
{"/sbin/ifconfig", nil},
{"/sbin/route", nil},
{"/usr/sbin/brctl", nil},
{"/bin/dmesg", nil},
{"/usr/bin/docker", []string{"ps"}},
{"/usr/bin/tail", []string{"-100", "/var/log/docker.log"}},
{"/usr/bin/tail", []string{"-100", "/var/log/messages"}},
{"/bin/mount", nil},
{"/bin/df", nil},
{"/bin/ls", []string{"-l", "/var"}},
{"/bin/ls", []string{"-l", "/var/lib"}},
{"/bin/ls", []string{"-l", "/var/lib/docker"}},
{"/usr/bin/diagnostics", nil},
{"/bin/ping", []string{"-w", "5", "8.8.8.8"}},
{"/bin/cat", []string{"/etc/docker/daemon.json"}},
{"/bin/cat", []string{"/etc/network/interfaces"}},
{"/bin/cat", []string{"/etc/resolv.conf"}},
{"/bin/cat", []string{"/etc/sysctl.conf"}},
{"/usr/bin/dig", []string{"docker.com"}},
{"/usr/bin/dig", []string{"@8.8.8.8", "docker.com"}},
{"/usr/bin/wget", []string{"-O", "-", "http://www.docker.com/"}},
{"/usr/bin/wget", []string{"-O", "-", "http://104.239.220.248/"}}, // a www.docker.com address
{"/usr/bin/wget", []string{"-O", "-", "http://216.58.213.68/"}}, // a www.google.com address
{"/usr/bin/wget", []string{"-O", "-", "http://91.198.174.192/"}}, // a www.wikipedia.com address
}
localCmdCaptures = []CommandCapturer{
{"/usr/bin/tail", []string{"-100", "/var/log/proxy-vsockd.log"}},
{"/usr/bin/tail", []string{"-100", "/var/log/service-port-opener.log"}},
{"/usr/bin/tail", []string{"-100", "/var/log/vsudd.log"}},
}
localCaptures = []Capturer{NewDatabaseCapturer()}
)
func init() {
for _, c := range localCmdCaptures {
localCaptures = append(localCaptures, c)
}
}
// Capturer defines behavior for structs which will capture arbitrary
// diagnostic information and write it to a tar archive with a timeout.
type Capturer interface {
Capture(time.Duration, *tar.Writer)
}
type CommandCapturer struct {
command string
args []string
}
func (cc CommandCapturer) Capture(timeout time.Duration, w *tar.Writer) {
log.Printf("Running %s", cc.command)
c := exec.Command(cc.command, cc.args...)
stdoutPipe, err := c.StdoutPipe()
if err != nil {
log.Fatalf("Failed to create stdout pipe: %s", err)
}
stderrPipe, err := c.StderrPipe()
if err != nil {
log.Fatalf("Failed to create stderr pipe: %s", err)
}
var stdoutBuffer bytes.Buffer
var stderrBuffer bytes.Buffer
done := make(chan int)
go func() {
io.Copy(&stdoutBuffer, stdoutPipe)
done <- 0
}()
go func() {
io.Copy(&stderrBuffer, stderrPipe)
done <- 0
}()
var timer *time.Timer
timer = time.AfterFunc(timeout, func() {
timer.Stop()
if c.Process != nil {
c.Process.Kill()
}
})
_ = c.Run()
<-done
<-done
timer.Stop()
name := strings.Join(append([]string{path.Base(cc.command)}, cc.args...), " ")
hdr := &tar.Header{
Name: name + ".stdout",
Mode: 0644,
Size: int64(stdoutBuffer.Len()),
}
if err = w.WriteHeader(hdr); err != nil {
log.Fatalln(err)
}
if _, err = w.Write(stdoutBuffer.Bytes()); err != nil {
log.Fatalln(err)
}
hdr = &tar.Header{
Name: name + ".stderr",
Mode: 0644,
Size: int64(stderrBuffer.Len()),
}
if err = w.WriteHeader(hdr); err != nil {
log.Fatalln(err)
}
if _, err = w.Write(stderrBuffer.Bytes()); err != nil {
log.Fatalln(err)
}
}
type DatabaseCapturer struct {
*CommandCapturer
}
func NewDatabaseCapturer() DatabaseCapturer {
return DatabaseCapturer{
&CommandCapturer{
command: "/bin/cat",
},
}
}
func (dc DatabaseCapturer) Capture(timeout time.Duration, w *tar.Writer) {
// Dump the database
dbBase := "/Database/branch/master/ro"
filepath.Walk(dbBase, func(path string, f os.FileInfo, err error) error {
if f.Mode().IsRegular() {
dc.CommandCapturer.args = []string{path}
dc.CommandCapturer.Capture(timeout, w)
}
return nil
})
}
// Capture is the outer level wrapper function to trigger the capturing of
// information. Clients are expected to call it with a slice of Capturers
// which define the information to be captured. By using an interface we can
// flexibly define various capture actions for the various listeners.
//
// It is a passed a tar.Writer which the results of the capture will be written
// to.
func Capture(w *tar.Writer, captures []Capturer) {
t := 2 * time.Second
for _, c := range captures {
c.Capture(t, w)
}
}