mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-03 18:20:27 +00:00
Squash of: * Include plugins in the report * show plugin list in the UI * moving metric and metadata templates into the probe reports * update js for prime -> priority * added retry to plugin handshake * added iowait plugin * review feedback * plugin documentation
288 lines
5.3 KiB
Go
288 lines
5.3 KiB
Go
package fs
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"strings"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/weaveworks/scope/common/fs"
|
|
)
|
|
|
|
type mockInode struct{}
|
|
|
|
type dir struct {
|
|
mockInode
|
|
name string
|
|
entries map[string]Entry
|
|
stat syscall.Stat_t
|
|
}
|
|
|
|
// File is a mock file
|
|
type File struct {
|
|
mockInode
|
|
FName string
|
|
FContents string
|
|
FReader io.Reader
|
|
FWriter io.Writer
|
|
FCloser io.Closer
|
|
FStat syscall.Stat_t
|
|
}
|
|
|
|
// Entry is an entry in the mock filesystem
|
|
type Entry interface {
|
|
os.FileInfo
|
|
fs.Interface
|
|
Add(path string, e Entry) error
|
|
Remove(path string) error
|
|
}
|
|
|
|
// Dir creates a new directory with the given entries.
|
|
func Dir(name string, entries ...Entry) Entry {
|
|
result := dir{
|
|
name: name,
|
|
entries: map[string]Entry{},
|
|
}
|
|
|
|
for _, entry := range entries {
|
|
result.entries[entry.Name()] = entry
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func split(path string) (string, string) {
|
|
if !strings.HasPrefix(path, "/") {
|
|
panic(path)
|
|
}
|
|
|
|
comps := strings.SplitN(path, "/", 3)
|
|
if len(comps) == 2 {
|
|
return comps[1], "/"
|
|
}
|
|
|
|
return comps[1], "/" + comps[2]
|
|
}
|
|
|
|
func (mockInode) Size() int64 { return 0 }
|
|
func (mockInode) Mode() os.FileMode { return 0 }
|
|
func (mockInode) ModTime() time.Time { return time.Now() }
|
|
func (mockInode) Sys() interface{} { return nil }
|
|
|
|
func (p dir) Name() string { return p.name }
|
|
func (p dir) IsDir() bool { return true }
|
|
|
|
func (p dir) ReadDir(path string) ([]os.FileInfo, error) {
|
|
if path == "/" {
|
|
result := []os.FileInfo{}
|
|
for _, v := range p.entries {
|
|
result = append(result, v)
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
head, tail := split(path)
|
|
fs, ok := p.entries[head]
|
|
if !ok {
|
|
return nil, fmt.Errorf("Not found: %s", path)
|
|
}
|
|
|
|
return fs.ReadDir(tail)
|
|
}
|
|
|
|
func (p dir) ReadDirNames(path string) ([]string, error) {
|
|
if path == "/" {
|
|
result := []string{}
|
|
for _, v := range p.entries {
|
|
result = append(result, v.Name())
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
head, tail := split(path)
|
|
fs, ok := p.entries[head]
|
|
if !ok {
|
|
return nil, fmt.Errorf("Not found: %s", path)
|
|
}
|
|
|
|
return fs.ReadDirNames(tail)
|
|
}
|
|
|
|
func (p dir) ReadFile(path string) ([]byte, error) {
|
|
if path == "/" {
|
|
return nil, fmt.Errorf("I'm a directory!")
|
|
}
|
|
|
|
head, tail := split(path)
|
|
fs, ok := p.entries[head]
|
|
if !ok {
|
|
return nil, fmt.Errorf("Not found: %s", path)
|
|
}
|
|
|
|
return fs.ReadFile(tail)
|
|
}
|
|
|
|
func (p dir) Lstat(path string, stat *syscall.Stat_t) error {
|
|
if path == "/" {
|
|
*stat = syscall.Stat_t{Mode: syscall.S_IFDIR}
|
|
return nil
|
|
}
|
|
|
|
head, tail := split(path)
|
|
fs, ok := p.entries[head]
|
|
if !ok {
|
|
return fmt.Errorf("Not found: %s", path)
|
|
}
|
|
|
|
return fs.Lstat(tail, stat)
|
|
}
|
|
|
|
func (p dir) Stat(path string, stat *syscall.Stat_t) error {
|
|
if path == "/" {
|
|
*stat = syscall.Stat_t{Mode: syscall.S_IFDIR}
|
|
return nil
|
|
}
|
|
|
|
head, tail := split(path)
|
|
fs, ok := p.entries[head]
|
|
if !ok {
|
|
return fmt.Errorf("Not found: %s", path)
|
|
}
|
|
|
|
return fs.Stat(tail, stat)
|
|
}
|
|
|
|
func (p dir) Open(path string) (io.ReadWriteCloser, error) {
|
|
if path == "/" {
|
|
return nil, fmt.Errorf("I'm a directory!")
|
|
}
|
|
|
|
head, tail := split(path)
|
|
fs, ok := p.entries[head]
|
|
if !ok {
|
|
return nil, fmt.Errorf("Not found: %s", path)
|
|
}
|
|
|
|
return fs.Open(tail)
|
|
}
|
|
|
|
func (p dir) Add(path string, e Entry) error {
|
|
if path == "/" {
|
|
p.entries[e.Name()] = e
|
|
return nil
|
|
}
|
|
|
|
head, tail := split(path)
|
|
fs, ok := p.entries[head]
|
|
if !ok {
|
|
fs = Dir(head)
|
|
p.entries[head] = fs
|
|
}
|
|
|
|
return fs.Add(tail, e)
|
|
}
|
|
|
|
func (p dir) Remove(path string) error {
|
|
if _, ok := p.entries[strings.TrimPrefix(path, "/")]; ok {
|
|
delete(p.entries, strings.TrimPrefix(path, "/"))
|
|
return nil
|
|
}
|
|
|
|
head, tail := split(path)
|
|
fs, ok := p.entries[head]
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return fs.Remove(tail)
|
|
}
|
|
|
|
// Name implements os.FileInfo
|
|
func (p File) Name() string { return p.FName }
|
|
|
|
// IsDir implements os.FileInfo
|
|
func (p File) IsDir() bool { return false }
|
|
|
|
// ReadDir implements FS
|
|
func (p File) ReadDir(path string) ([]os.FileInfo, error) {
|
|
return nil, fmt.Errorf("I'm a file!")
|
|
}
|
|
|
|
// ReadDirNames implements FS
|
|
func (p File) ReadDirNames(path string) ([]string, error) {
|
|
return nil, fmt.Errorf("I'm a file!")
|
|
}
|
|
|
|
// ReadFile implements FS
|
|
func (p File) ReadFile(path string) ([]byte, error) {
|
|
if path != "/" {
|
|
return nil, fmt.Errorf("I'm a file!")
|
|
}
|
|
if p.FReader != nil {
|
|
return ioutil.ReadAll(p.FReader)
|
|
}
|
|
return []byte(p.FContents), nil
|
|
}
|
|
|
|
// Lstat implements FS
|
|
func (p File) Lstat(path string, stat *syscall.Stat_t) error {
|
|
if path != "/" {
|
|
return fmt.Errorf("I'm a file!")
|
|
}
|
|
*stat = p.FStat
|
|
return nil
|
|
}
|
|
|
|
// Stat implements FS
|
|
func (p File) Stat(path string, stat *syscall.Stat_t) error {
|
|
if path != "/" {
|
|
return fmt.Errorf("I'm a file!")
|
|
}
|
|
*stat = p.FStat
|
|
return nil
|
|
}
|
|
|
|
// Open implements FS
|
|
func (p File) Open(path string) (io.ReadWriteCloser, error) {
|
|
if path != "/" {
|
|
return nil, fmt.Errorf("I'm a file!")
|
|
}
|
|
buf := bytes.NewBuffer([]byte(p.FContents))
|
|
s := struct {
|
|
io.Reader
|
|
io.Writer
|
|
io.Closer
|
|
}{
|
|
buf, buf, ioutil.NopCloser(nil),
|
|
}
|
|
if p.FReader != nil {
|
|
s.Reader = p.FReader
|
|
}
|
|
if p.FWriter != nil {
|
|
s.Writer = p.FWriter
|
|
}
|
|
if p.FCloser != nil {
|
|
s.Closer = p.FCloser
|
|
}
|
|
return s, nil
|
|
}
|
|
|
|
// Add adds a new node to the fs
|
|
func (p File) Add(path string, e Entry) error {
|
|
if path != "/" {
|
|
return fmt.Errorf("I'm a file!")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Remove removes a node from the fs
|
|
func (p File) Remove(path string) error {
|
|
if path != "/" {
|
|
return fmt.Errorf("I'm a file!")
|
|
}
|
|
return nil
|
|
}
|