go: portability work

Compiles and mostly works on osx and freebsd.

Pull in gopsutil to fill in recon info.

Change-Id: I13c77f77cf99abbc275496edb254915ad9012181
This commit is contained in:
Michael Barton 2016-05-27 15:39:46 -05:00
parent f6834ae97f
commit 7ebda1bdfb
11 changed files with 343 additions and 105 deletions

View File

@ -29,6 +29,11 @@ import (
"strconv"
"strings"
"syscall"
"github.com/shirou/gopsutil/disk"
"github.com/shirou/gopsutil/load"
"github.com/shirou/gopsutil/mem"
"github.com/shirou/gopsutil/process"
)
func DumpReconCache(reconCachePath string, source string, cacheData map[string]interface{}) error {
@ -79,22 +84,44 @@ func DumpReconCache(reconCachePath string, source string, cacheData map[string]i
return WriteFileAtomic(reconFile, newdata, 0600)
}
// getMem dumps the contents of /proc/meminfo if it's available, otherwise it pulls what it can from gopsutil/mem
func getMem() interface{} {
results := make(map[string]string)
fp, _ := os.Open("/proc/meminfo")
defer fp.Close()
scanner := bufio.NewScanner(fp)
for scanner.Scan() {
vals := strings.Split(scanner.Text(), ":")
results[strings.TrimSpace(vals[0])] = strings.TrimSpace(vals[1])
if fp, err := os.Open("/proc/meminfo"); err == nil {
defer fp.Close()
results := make(map[string]string)
scanner := bufio.NewScanner(fp)
for scanner.Scan() {
vals := strings.Split(scanner.Text(), ":")
results[strings.TrimSpace(vals[0])] = strings.TrimSpace(vals[1])
}
return results
} else {
vmem, err := mem.VirtualMemory()
if err != nil {
return nil
}
swap, err := mem.SwapMemory()
if err != nil {
return nil
}
return map[string]string{
"MemTotal": strconv.FormatUint(vmem.Total, 10),
"MemFree": strconv.FormatUint(vmem.Available, 10),
"Buffers": strconv.FormatUint(vmem.Buffers, 10),
"Cached": strconv.FormatUint(vmem.Cached, 10),
"SwapTotal": strconv.FormatUint(swap.Total, 10),
"SwapFree": strconv.FormatUint(swap.Free, 10),
}
}
return results
}
func getSockstats() interface{} {
results := make(map[string]int64)
fp, _ := os.Open("/proc/net/sockstat")
fp, err := os.Open("/proc/net/sockstat")
if err != nil {
return nil
}
defer fp.Close()
scanner := bufio.NewScanner(fp)
for scanner.Scan() {
@ -109,7 +136,10 @@ func getSockstats() interface{} {
}
}
fp, _ = os.Open("/proc/net/sockstat6")
fp, err = os.Open("/proc/net/sockstat6")
if err != nil {
return nil
}
defer fp.Close()
scanner = bufio.NewScanner(fp)
for scanner.Scan() {
@ -125,26 +155,39 @@ func getSockstats() interface{} {
func getLoad() interface{} {
results := make(map[string]interface{})
fp, _ := os.Open("/proc/loadavg")
defer fp.Close()
data, _ := ioutil.ReadAll(fp)
parts := strings.Split(strings.TrimSpace(string(data)), " ")
results["1m"], _ = strconv.ParseFloat(parts[0], 64)
results["5m"], _ = strconv.ParseFloat(parts[1], 64)
results["15m"], _ = strconv.ParseFloat(parts[2], 64)
results["tasks"] = parts[3]
results["processes"], _ = strconv.ParseInt(parts[4], 10, 64)
avg, err := load.Avg()
if err != nil {
return nil
}
misc, err := load.Misc()
if err != nil {
return nil
}
pids, err := process.Pids()
if err != nil {
return nil
}
results["1m"] = avg.Load1
results["5m"] = avg.Load5
results["15m"] = avg.Load15
results["tasks"] = fmt.Sprintf("%d/%d", misc.ProcsRunning, len(pids))
// swift's recon puts the pid of the last created process in this field, which seems kind of useless.
// I'm making it the number of processes, which seems like what it was meant to be.
results["processes"] = len(pids)
// also adding these two fields, since they might be useful.
results["running"] = misc.ProcsRunning
results["blocked"] = misc.ProcsBlocked
return results
}
func getMounts() interface{} {
results := make([]map[string]string, 0)
fp, _ := os.Open("/proc/mounts")
defer fp.Close()
scanner := bufio.NewScanner(fp)
for scanner.Scan() {
vals := strings.Split(scanner.Text(), " ")
results = append(results, map[string]string{"device": vals[0], "path": vals[1]})
partitions, err := disk.Partitions(true)
if err != nil {
return nil
}
for _, part := range partitions {
results = append(results, map[string]string{"device": part.Device, "path": part.Mountpoint})
}
return results
}

View File

@ -161,7 +161,7 @@ func TestGetMem(t *testing.T) {
var v map[string]string
err := json.Unmarshal(output, &v)
require.Nil(t, err)
_, ok := v["Active"]
_, ok := v["MemTotal"]
require.True(t, ok)
}

View File

@ -359,7 +359,7 @@ func StandardizeTimestamp(timestamp string) (string, error) {
func IsNotDir(err error) bool {
if se, ok := err.(*os.SyscallError); ok {
return se.Err == syscall.ENOTDIR
return se.Err == syscall.ENOTDIR || se.Err == syscall.EINVAL
}
if se, ok := err.(*os.PathError); ok {
return os.IsNotExist(se)

View File

@ -216,7 +216,7 @@ func TestUrlencode(t *testing.T) {
}
func TestIsMount(t *testing.T) {
isMount, err := IsMount("/proc")
isMount, err := IsMount("/dev")
assert.Nil(t, err)
assert.True(t, isMount)
isMount, err = IsMount(".")

View File

@ -1,55 +0,0 @@
// Copyright (c) 2015 Rackspace
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package hummingbird
import (
"syscall"
"unsafe"
)
func FGetXattr(fd uintptr, attr string, value []byte) (int, error) {
attrp, err := syscall.BytePtrFromString(attr)
if err != nil {
return 0, err
}
if len(value) == 0 {
if r0, _, e1 := syscall.Syscall6(syscall.SYS_FGETXATTR, fd, uintptr(unsafe.Pointer(attrp)), 0, 0, 0, 0); e1 == 0 {
return int(r0), nil
} else {
return 0, e1
}
} else {
valuep := unsafe.Pointer(&value[0])
if r0, _, e1 := syscall.Syscall6(syscall.SYS_FGETXATTR, fd, uintptr(unsafe.Pointer(attrp)), uintptr(valuep), uintptr(len(value)), 0, 0); e1 == 0 {
return int(r0), nil
} else {
return int(r0), e1
}
}
}
func FSetXattr(fd uintptr, attr string, value []byte) (int, error) {
attrp, err := syscall.BytePtrFromString(attr)
if err != nil {
return 0, err
}
valuep := unsafe.Pointer(&value[0])
r0, _, e1 := syscall.Syscall6(syscall.SYS_FSETXATTR, fd, uintptr(unsafe.Pointer(attrp)), uintptr(valuep), uintptr(len(value)), 0, 0)
if e1 != 0 {
err = e1
}
return int(r0), nil
}

View File

@ -19,7 +19,6 @@ import (
"bufio"
"crypto/md5"
"encoding/hex"
"errors"
"fmt"
"io"
"io/ioutil"
@ -28,10 +27,10 @@ import (
"path/filepath"
"strconv"
"strings"
"syscall"
"time"
"github.com/openstack/swift/go/hummingbird"
"github.com/openstack/swift/go/xattr"
)
const METADATA_CHUNK_SIZE = 65536
@ -50,16 +49,6 @@ type AtomicFileWriter interface {
Preallocate(int64, int64) error
}
func GetXAttr(fileNameOrFd interface{}, attr string, value []byte) (int, error) {
switch v := fileNameOrFd.(type) {
case string:
return syscall.Getxattr(v, attr, value)
case uintptr:
return hummingbird.FGetXattr(v, attr, value)
}
return 0, &hummingbird.BackendError{Err: errors.New("Invalid fileNameOrFd"), Code: hummingbird.UnhandledError}
}
func RawReadMetadata(fileNameOrFd interface{}) ([]byte, error) {
var pickledMetadata []byte
offset := 0
@ -72,7 +61,7 @@ func RawReadMetadata(fileNameOrFd interface{}) ([]byte, error) {
metadataName = "user.swift.metadata" + strconv.Itoa(index)
}
// get size of xattr
length, err := GetXAttr(fileNameOrFd, metadataName, nil)
length, err := xattr.Getxattr(fileNameOrFd, metadataName, nil)
if err != nil || length <= 0 {
break
}
@ -81,7 +70,7 @@ func RawReadMetadata(fileNameOrFd interface{}) ([]byte, error) {
pickledMetadata = append(pickledMetadata, 0)
}
pickledMetadata = pickledMetadata[0 : offset+length]
if _, err := GetXAttr(fileNameOrFd, metadataName, pickledMetadata[offset:]); err != nil {
if _, err := xattr.Getxattr(fileNameOrFd, metadataName, pickledMetadata[offset:]); err != nil {
return nil, err
}
offset += length
@ -126,7 +115,7 @@ func RawWriteMetadata(fd uintptr, buf []byte) error {
if len(buf) < writelen {
writelen = len(buf)
}
if _, err := hummingbird.FSetXattr(fd, metadataName, buf[0:writelen]); err != nil {
if _, err := xattr.Setxattr(fd, metadataName, buf[0:writelen]); err != nil {
return err
}
buf = buf[writelen:len(buf)]

View File

@ -55,8 +55,9 @@ func (o *TempFile) Save(dst string) error {
}
// Preallocate pre-allocates space for the file.
func (o *TempFile) Preallocate(size int64, reserve int64) {
func (o *TempFile) Preallocate(size int64, reserve int64) error {
// TODO: this could be done for most non-linux operating systems, but it hasn't been important.
return nil
}
// NewAtomicFileWriter returns an AtomicFileWriter, which handles atomically writing files.

46
go/xattr/xattr.go Normal file
View File

@ -0,0 +1,46 @@
// Copyright (c) 2015 Rackspace
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package xattr
import "errors"
// Setxattr sets xattrs for a file, given a file descriptor, attribute name, and value buffer.
func Setxattr(fileNameOrFd interface{}, attr string, value []byte) (int, error) {
switch v := fileNameOrFd.(type) {
case string:
return setxattr(v, attr, value)
case uintptr:
return fsetxattr(v, attr, value)
case int:
return fsetxattr(uintptr(v), attr, value)
default:
return 0, errors.New("Invalid fileNameOrFd")
}
}
// Getxattr gets xattrs from a file, given a filename(string) or file descriptor(uintptr), an attribute name, and value buffer to store it to.
func Getxattr(fileNameOrFd interface{}, attr string, value []byte) (int, error) {
switch v := fileNameOrFd.(type) {
case string:
return getxattr(v, attr, value)
case uintptr:
return fgetxattr(v, attr, value)
case int:
return fgetxattr(uintptr(v), attr, value)
default:
return 0, errors.New("Invalid fileNameOrFd")
}
}

103
go/xattr/xattr_bsd.go Normal file
View File

@ -0,0 +1,103 @@
// Copyright (c) 2015 Rackspace
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build freebsd openbsd netbsd dragonfly
package xattr
import (
"syscall"
"unsafe"
)
/*
#include <sys/types.h>
#include <sys/extattr.h>
*/
import "C"
func fsetxattr(fd uintptr, attr string, value []byte) (int, error) {
attrp, err := syscall.BytePtrFromString(attr)
if err != nil {
return 0, err
}
valuep := unsafe.Pointer(&value[0])
if r0, _, e1 := syscall.Syscall6(syscall.SYS_EXTATTR_SET_FD, fd, uintptr(C.EXTATTR_NAMESPACE_USER), uintptr(unsafe.Pointer(attrp)), uintptr(valuep), uintptr(len(value)), 0); e1 == 0 {
return int(r0), nil
} else {
return 0, e1
}
}
func setxattr(path string, attr string, value []byte) (int, error) {
attrp, err := syscall.BytePtrFromString(attr)
if err != nil {
return 0, err
}
pathp, err := syscall.BytePtrFromString(path)
if err != nil {
return 0, err
}
valuep := unsafe.Pointer(&value[0])
if r0, _, e1 := syscall.Syscall6(syscall.SYS_EXTATTR_SET_FILE, uintptr(unsafe.Pointer(pathp)), uintptr(C.EXTATTR_NAMESPACE_USER), uintptr(unsafe.Pointer(attrp)), uintptr(valuep), uintptr(len(value)), 0); e1 == 0 {
return int(r0), nil
} else {
return 0, e1
}
}
func fgetxattr(fd uintptr, attr string, value []byte) (int, error) {
attrp, err := syscall.BytePtrFromString(attr)
if err != nil {
return 0, err
}
var r0 uintptr
var e1 syscall.Errno
if value == nil {
r0, _, e1 = syscall.Syscall6(syscall.SYS_EXTATTR_GET_FD, fd, uintptr(C.EXTATTR_NAMESPACE_USER), uintptr(unsafe.Pointer(attrp)), 0, 0, 0)
} else {
valuep := unsafe.Pointer(&value[0])
r0, _, e1 = syscall.Syscall6(syscall.SYS_EXTATTR_GET_FD, fd, uintptr(C.EXTATTR_NAMESPACE_USER), uintptr(unsafe.Pointer(attrp)), uintptr(valuep), uintptr(len(value)), 0)
}
if e1 == 0 {
return int(r0), nil
} else {
return 0, e1
}
}
func getxattr(path string, attr string, value []byte) (int, error) {
attrp, err := syscall.BytePtrFromString(attr)
if err != nil {
return 0, err
}
pathp, err := syscall.BytePtrFromString(path)
if err != nil {
return 0, err
}
var r0 uintptr
var e1 syscall.Errno
if value == nil {
r0, _, e1 = syscall.Syscall6(syscall.SYS_EXTATTR_GET_FILE, uintptr(unsafe.Pointer(pathp)), uintptr(C.EXTATTR_NAMESPACE_USER), uintptr(unsafe.Pointer(attrp)), 0, 0, 0)
} else {
valuep := unsafe.Pointer(&value[0])
r0, _, e1 = syscall.Syscall6(syscall.SYS_EXTATTR_GET_FILE, uintptr(unsafe.Pointer(pathp)), uintptr(C.EXTATTR_NAMESPACE_USER), uintptr(unsafe.Pointer(attrp)), uintptr(valuep), uintptr(len(value)), 0)
}
if e1 == 0 {
return int(r0), nil
} else {
return 0, e1
}
}

View File

@ -0,0 +1,97 @@
// Copyright (c) 2015 Rackspace
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build linux darwin
package xattr
import (
"syscall"
"unsafe"
)
func fsetxattr(fd uintptr, attr string, value []byte) (int, error) {
attrp, err := syscall.BytePtrFromString(attr)
if err != nil {
return 0, err
}
valuep := unsafe.Pointer(&value[0])
if r0, _, e1 := syscall.Syscall6(syscall.SYS_FSETXATTR, fd, uintptr(unsafe.Pointer(attrp)), uintptr(valuep), uintptr(len(value)), 0, 0); e1 == 0 {
return int(r0), nil
} else {
return 0, e1
}
}
func setxattr(path string, attr string, value []byte) (int, error) {
attrp, err := syscall.BytePtrFromString(attr)
if err != nil {
return 0, err
}
pathp, err := syscall.BytePtrFromString(path)
if err != nil {
return 0, err
}
valuep := unsafe.Pointer(&value[0])
if r0, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(pathp)), uintptr(unsafe.Pointer(attrp)), uintptr(valuep), uintptr(len(value)), 0, 0); e1 == 0 {
return int(r0), nil
} else {
return 0, e1
}
}
func fgetxattr(fd uintptr, attr string, value []byte) (int, error) {
attrp, err := syscall.BytePtrFromString(attr)
if err != nil {
return 0, err
}
var r0 uintptr
var e1 syscall.Errno
if len(value) == 0 {
r0, _, e1 = syscall.Syscall6(syscall.SYS_FGETXATTR, fd, uintptr(unsafe.Pointer(attrp)), 0, 0, 0, 0)
} else {
valuep := unsafe.Pointer(&value[0])
r0, _, e1 = syscall.Syscall6(syscall.SYS_FGETXATTR, fd, uintptr(unsafe.Pointer(attrp)), uintptr(valuep), uintptr(len(value)), 0, 0)
}
if e1 == 0 {
return int(r0), nil
} else {
return 0, e1
}
}
func getxattr(path string, attr string, value []byte) (int, error) {
attrp, err := syscall.BytePtrFromString(attr)
if err != nil {
return 0, err
}
pathp, err := syscall.BytePtrFromString(path)
if err != nil {
return 0, err
}
var r0 uintptr
var e1 syscall.Errno
if len(value) == 0 {
r0, _, e1 = syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(pathp)), uintptr(unsafe.Pointer(attrp)), 0, 0, 0, 0)
} else {
valuep := unsafe.Pointer(&value[0])
r0, _, e1 = syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(pathp)), uintptr(unsafe.Pointer(attrp)), uintptr(valuep), uintptr(len(value)), 0, 0)
}
if e1 == 0 {
return int(r0), nil
} else {
return 0, e1
}
}

View File

@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package hummingbird
package xattr
import (
"io/ioutil"
@ -23,8 +23,22 @@ import (
"github.com/stretchr/testify/require"
)
// func FGetXattr(fd uintptr, attr string, value []byte) (int, error)
// func FSetXattr(fd uintptr, attr string, value []byte) (int, error)
func TestFXattr(t *testing.T) {
fp, err := ioutil.TempFile("", "")
require.Nil(t, err)
defer fp.Close()
defer os.RemoveAll(fp.Name())
_, err = Setxattr(fp.Fd(), "user.swift.metadata", []byte("somevalue"))
require.Nil(t, err)
count, err := Getxattr(fp.Fd(), "user.swift.metadata", nil)
require.Nil(t, err)
value := make([]byte, count)
count, err = Getxattr(fp.Fd(), "user.swift.metadata", value)
require.Nil(t, err)
require.Equal(t, "somevalue", string(value))
}
func TestXattr(t *testing.T) {
fp, err := ioutil.TempFile("", "")
@ -32,13 +46,13 @@ func TestXattr(t *testing.T) {
defer fp.Close()
defer os.RemoveAll(fp.Name())
_, err = FSetXattr(fp.Fd(), "user.swift.metadata", []byte("somevalue"))
_, err = Setxattr(fp.Name(), "user.swift.metadata", []byte("somevalue"))
require.Nil(t, err)
count, err := FGetXattr(fp.Fd(), "user.swift.metadata", nil)
count, err := Getxattr(fp.Name(), "user.swift.metadata", nil)
require.Nil(t, err)
value := make([]byte, count)
count, err = FGetXattr(fp.Fd(), "user.swift.metadata", value)
count, err = Getxattr(fp.Name(), "user.swift.metadata", value)
require.Nil(t, err)
require.Equal(t, "somevalue", string(value))
}