<commit_before>package http

import (
	"bytes"
	"errors"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	dag "github.com/jbenet/go-ipfs/merkledag"
	u "github.com/jbenet/go-ipfs/util"
)

type test struct {
	url      string
	code     int
	reqbody  string
	respbody string
}

func TestServeHTTP(t *testing.T) {
	testhandler := &handler{&testIpfsHandler{}}
	tests := []test{
		{"/", http.StatusInternalServerError, "", ""},
		{"/hash", http.StatusOK, "", "some fine data"},
		{"/hash2", http.StatusInternalServerError, "", ""},
	}

	for _, test := range tests {
		req, _ := http.NewRequest("GET", test.url, nil)
		resp := httptest.NewRecorder()
		testhandler.ServeHTTP(resp, req)

		if resp.Code != test.code {
			t.Error("expected status code", test.code, "received", resp.Code)
		}

		if resp.Body.String() != test.respbody {
			t.Error("expected body:", test.respbody)
			t.Error("received body:", resp.Body)
		}
	}
}

func TestPostHandler(t *testing.T) {
	testhandler := &handler{&testIpfsHandler{}}
	tests := []test{
		{"/", http.StatusInternalServerError, "", ""},
		{"/", http.StatusInternalServerError, "something that causes an error in adding to DAG", ""},
		{"/", http.StatusCreated, "some fine data", "jSQBpNSebeYbPBjs1vp"},
	}

	for _, test := range tests {
		req, _ := http.NewRequest("POST", test.url, strings.NewReader(test.reqbody))
		resp := httptest.NewRecorder()
		testhandler.postHandler(resp, req)

		if resp.Code != test.code {
			t.Error("expected status code", test.code, "received", resp.Code)
		}

		if resp.Body.String() != test.respbody {
			t.Error("expected body:", test.respbody)
			t.Error("received body:", resp.Body)
		}
	}
}

type testIpfsHandler struct{}

func (i *testIpfsHandler) ResolvePath(path string) (*dag.Node, error) {
	if path == "/hash" {
		return &dag.Node{Data: []byte("some fine data")}, nil
	}

	if path == "/hash2" {
		return &dag.Node{Data: []byte("data that breaks dagreader")}, nil
	}

	return nil, errors.New("")
}

func (i *testIpfsHandler) NewDagFromReader(r io.Reader) (*dag.Node, error) {
	if data, err := ioutil.ReadAll(r); err == nil {
		return &dag.Node{Data: data}, nil
	}

	return nil, errors.New("")
}

func (i *testIpfsHandler) AddNodeToDAG(nd *dag.Node) (u.Key, error) {
	if len(nd.Data) != 0 && string(nd.Data) != "something that causes an error in adding to DAG" {
		return u.Key(nd.Data), nil
	}

	return "", errors.New("")
}

func (i *testIpfsHandler) NewDagReader(nd *dag.Node) (io.Reader, error) {
	if string(nd.Data) != "data that breaks dagreader" {
		return bytes.NewReader(nd.Data), nil
	}

	return nil, errors.New("")
}
<commit_msg>fix http test<commit_after>package http

import (
	"bytes"
	"errors"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	dag "github.com/jbenet/go-ipfs/merkledag"
	u "github.com/jbenet/go-ipfs/util"
)

type test struct {
	url      string
	code     int
	reqbody  string
	respbody string
}

func TestServeHTTP(t *testing.T) {
	testhandler := &handler{&testIpfsHandler{}}
	tests := []test{
		{"/ipfs/", http.StatusInternalServerError, "", ""},
		{"/ipfs/hash", http.StatusOK, "", "some fine data"},
		{"/ipfs/hash2", http.StatusInternalServerError, "", ""},
	}

	for _, test := range tests {
		req, _ := http.NewRequest("GET", test.url, nil)
		resp := httptest.NewRecorder()
		testhandler.ServeHTTP(resp, req)

		if resp.Code != test.code {
			t.Error("expected status code", test.code, "received", resp.Code)
		}

		if resp.Body.String() != test.respbody {
			t.Error("expected body:", test.respbody)
			t.Error("received body:", resp.Body)
		}
	}
}

func TestPostHandler(t *testing.T) {
	testhandler := &handler{&testIpfsHandler{}}
	tests := []test{
		{"/ifps/", http.StatusInternalServerError, "", ""},
		{"/ipfs/", http.StatusInternalServerError, "something that causes an error in adding to DAG", ""},
		{"/ipfs/", http.StatusCreated, "some fine data", "jSQBpNSebeYbPBjs1vp"},
	}

	for _, test := range tests {
		req, _ := http.NewRequest("POST", test.url, strings.NewReader(test.reqbody))
		resp := httptest.NewRecorder()
		testhandler.postHandler(resp, req)

		if resp.Code != test.code {
			t.Error("expected status code", test.code, "received", resp.Code)
		}

		if resp.Body.String() != test.respbody {
			t.Error("expected body:", test.respbody)
			t.Error("received body:", resp.Body)
		}
	}
}

type testIpfsHandler struct{}

func (i *testIpfsHandler) ResolvePath(path string) (*dag.Node, error) {
	if path == "/hash" {
		return &dag.Node{Data: []byte("some fine data")}, nil
	}

	if path == "/hash2" {
		return &dag.Node{Data: []byte("data that breaks dagreader")}, nil
	}

	return nil, errors.New("")
}

func (i *testIpfsHandler) NewDagFromReader(r io.Reader) (*dag.Node, error) {
	if data, err := ioutil.ReadAll(r); err == nil {
		return &dag.Node{Data: data}, nil
	}

	return nil, errors.New("")
}

func (i *testIpfsHandler) AddNodeToDAG(nd *dag.Node) (u.Key, error) {
	if len(nd.Data) != 0 && string(nd.Data) != "something that causes an error in adding to DAG" {
		return u.Key(nd.Data), nil
	}

	return "", errors.New("")
}

func (i *testIpfsHandler) NewDagReader(nd *dag.Node) (io.Reader, error) {
	if string(nd.Data) != "data that breaks dagreader" {
		return bytes.NewReader(nd.Data), nil
	}

	return nil, errors.New("")
}
<|endoftext|>


<commit_before>// +build linux

package systemd

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"math"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	systemdDbus "github.com/coreos/go-systemd/v22/dbus"
	"github.com/opencontainers/runc/libcontainer/cgroups"
	"github.com/opencontainers/runc/libcontainer/cgroups/fs2"
	"github.com/opencontainers/runc/libcontainer/configs"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

type UnifiedManager struct {
	mu      sync.Mutex
	Cgroups *configs.Cgroup
	Paths   map[string]string
}

func (m *UnifiedManager) Apply(pid int) error {
	var (
		c          = m.Cgroups
		unitName   = getUnitName(c)
		slice      = "system.slice"
		properties []systemdDbus.Property
	)

	if c.Paths != nil {
		paths := make(map[string]string)
		for name, path := range c.Paths {
			paths[name] = path
		}
		m.Paths = paths
		return cgroups.EnterPid(m.Paths, pid)
	}

	if c.Parent != "" {
		slice = c.Parent
	}

	properties = append(properties, systemdDbus.PropDescription("libcontainer container "+c.Name))

	// if we create a slice, the parent is defined via a Wants=
	if strings.HasSuffix(unitName, ".slice") {
		properties = append(properties, systemdDbus.PropWants(slice))
	} else {
		// otherwise, we use Slice=
		properties = append(properties, systemdDbus.PropSlice(slice))
	}

	// only add pid if its valid, -1 is used w/ general slice creation.
	if pid != -1 {
		properties = append(properties, newProp("PIDs", []uint32{uint32(pid)}))
	}

	// Check if we can delegate. This is only supported on systemd versions 218 and above.
	if !strings.HasSuffix(unitName, ".slice") {
		// Assume scopes always support delegation.
		properties = append(properties, newProp("Delegate", true))
	}

	// Always enable accounting, this gets us the same behaviour as the fs implementation,
	// plus the kernel has some problems with joining the memory cgroup at a later time.
	properties = append(properties,
		newProp("MemoryAccounting", true),
		newProp("CPUAccounting", true),
		newProp("IOAccounting", true))

	// Assume DefaultDependencies= will always work (the check for it was previously broken.)
	properties = append(properties,
		newProp("DefaultDependencies", false))

	if c.Resources.Memory != 0 {
		properties = append(properties,
			newProp("MemoryMax", uint64(c.Resources.Memory)))
	}

	if c.Resources.CpuWeight != 0 {
		properties = append(properties,
			newProp("CPUWeight", c.Resources.CpuWeight))
	}

	// cpu.cfs_quota_us and cpu.cfs_period_us are controlled by systemd.
	if c.Resources.CpuQuota != 0 && c.Resources.CpuPeriod != 0 {
		// corresponds to USEC_INFINITY in systemd
		// if USEC_INFINITY is provided, CPUQuota is left unbound by systemd
		// always setting a property value ensures we can apply a quota and remove it later
		cpuQuotaPerSecUSec := uint64(math.MaxUint64)
		if c.Resources.CpuQuota > 0 {
			// systemd converts CPUQuotaPerSecUSec (microseconds per CPU second) to CPUQuota
			// (integer percentage of CPU) internally.  This means that if a fractional percent of
			// CPU is indicated by Resources.CpuQuota, we need to round up to the nearest
			// 10ms (1% of a second) such that child cgroups can set the cpu.cfs_quota_us they expect.
			cpuQuotaPerSecUSec = uint64(c.Resources.CpuQuota*1000000) / c.Resources.CpuPeriod
			if cpuQuotaPerSecUSec%10000 != 0 {
				cpuQuotaPerSecUSec = ((cpuQuotaPerSecUSec / 10000) + 1) * 10000
			}
		}
		properties = append(properties,
			newProp("CPUQuotaPerSecUSec", cpuQuotaPerSecUSec))
	}

	if c.Resources.PidsLimit > 0 {
		properties = append(properties,
			newProp("TasksAccounting", true),
			newProp("TasksMax", uint64(c.Resources.PidsLimit)))
	}

	properties = append(properties, c.SystemdProps...)

	// ignore c.Resources.KernelMemory

	statusChan := make(chan string, 1)
	if _, err := theConn.StartTransientUnit(unitName, "replace", properties, statusChan); err == nil {
		select {
		case <-statusChan:
		case <-time.After(time.Second):
			logrus.Warnf("Timed out while waiting for StartTransientUnit(%s) completion signal from dbus. Continuing...", unitName)
		}
	} else if !isUnitExists(err) {
		return err
	}

	if err := joinCgroupsV2(c, pid); err != nil {
		return err
	}

	path, err := getSubsystemPath(m.Cgroups, "")
	if err != nil {
		return err
	}
	m.Paths = map[string]string{
		"pids":    path,
		"memory":  path,
		"io":      path,
		"cpu":     path,
		"devices": path,
		"cpuset":  path,
		"freezer": path,
	}
	return nil
}

func (m *UnifiedManager) Destroy() error {
	if m.Cgroups.Paths != nil {
		return nil
	}
	m.mu.Lock()
	defer m.mu.Unlock()
	theConn.StopUnit(getUnitName(m.Cgroups), "replace", nil)
	if err := cgroups.RemovePaths(m.Paths); err != nil {
		return err
	}
	m.Paths = make(map[string]string)
	return nil
}

func (m *UnifiedManager) GetPaths() map[string]string {
	m.mu.Lock()
	paths := m.Paths
	m.mu.Unlock()
	return paths
}
func (m *UnifiedManager) GetUnifiedPath() (string, error) {
	unifiedPath := ""
	m.mu.Lock()
	defer m.mu.Unlock()
	for k, v := range m.Paths {
		if unifiedPath == "" {
			unifiedPath = v
		} else if v != unifiedPath {
			return unifiedPath,
				errors.Errorf("expected %q path to be unified path %q, got %q", k, unifiedPath, v)
		}
	}
	if unifiedPath == "" {
		// FIXME: unified path could be detected even when no controller is available
		return unifiedPath, errors.New("cannot detect unified path")
	}
	return unifiedPath, nil
}
func createCgroupsv2Path(path string) (Err error) {
	content, err := ioutil.ReadFile("/sys/fs/cgroup/cgroup.controllers")
	if err != nil {
		return err
	}
	if !filepath.HasPrefix(path, "/sys/fs/cgroup") {
		return fmt.Errorf("invalid cgroup path %s", path)
	}

	ctrs := bytes.Fields(content)
	res := append([]byte("+"), bytes.Join(ctrs, []byte(" +"))...)

	current := "/sys/fs"
	elements := strings.Split(path, "/")
	for i, e := range elements[3:] {
		current = filepath.Join(current, e)
		if i > 0 {
			if err := os.Mkdir(current, 0755); err != nil {
				if !os.IsExist(err) {
					return err
				}
			} else {
				// If the directory was created, be sure it is not left around on errors.
				defer func() {
					if Err != nil {
						os.Remove(current)
					}
				}()
			}
		}
		if i < len(elements[3:])-1 {
			if err := ioutil.WriteFile(filepath.Join(current, "cgroup.subtree_control"), res, 0755); err != nil {
				return err
			}
		}
	}
	return nil
}

func joinCgroupsV2(c *configs.Cgroup, pid int) error {
	path, err := getSubsystemPath(c, "memory")
	if err != nil {
		return err
	}
	return createCgroupsv2Path(path)
}

func (m *UnifiedManager) fsManager() (cgroups.Manager, error) {
	path, err := m.GetUnifiedPath()
	if err != nil {
		return nil, err
	}
	return fs2.NewManager(m.Cgroups, path, false)
}

func (m *UnifiedManager) Freeze(state configs.FreezerState) error {
	fsMgr, err := m.fsManager()
	if err != nil {
		return err
	}
	return fsMgr.Freeze(state)
}

func (m *UnifiedManager) GetPids() ([]int, error) {
	path, err := m.GetUnifiedPath()
	if err != nil {
		return nil, err
	}
	return cgroups.GetPids(path)
}

func (m *UnifiedManager) GetAllPids() ([]int, error) {
	path, err := m.GetUnifiedPath()
	if err != nil {
		return nil, err
	}
	return cgroups.GetAllPids(path)
}

func (m *UnifiedManager) GetStats() (*cgroups.Stats, error) {
	fsMgr, err := m.fsManager()
	if err != nil {
		return nil, err
	}
	return fsMgr.GetStats()
}

func (m *UnifiedManager) Set(container *configs.Config) error {
	fsMgr, err := m.fsManager()
	if err != nil {
		return err
	}
	return fsMgr.Set(container)
}

func (m *UnifiedManager) GetCgroups() (*configs.Cgroup, error) {
	return m.Cgroups, nil
}
<commit_msg>cgroupv2/systemd: add getv2Path<commit_after>// +build linux

package systemd

import (
	"bytes"
	"io/ioutil"
	"math"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	systemdDbus "github.com/coreos/go-systemd/v22/dbus"
	"github.com/opencontainers/runc/libcontainer/cgroups"
	"github.com/opencontainers/runc/libcontainer/cgroups/fs2"
	"github.com/opencontainers/runc/libcontainer/configs"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

type UnifiedManager struct {
	mu      sync.Mutex
	Cgroups *configs.Cgroup
	Paths   map[string]string
}

func (m *UnifiedManager) Apply(pid int) error {
	var (
		c          = m.Cgroups
		unitName   = getUnitName(c)
		slice      = "system.slice"
		properties []systemdDbus.Property
	)

	if c.Paths != nil {
		paths := make(map[string]string)
		for name, path := range c.Paths {
			paths[name] = path
		}
		m.Paths = paths
		return cgroups.EnterPid(m.Paths, pid)
	}

	if c.Parent != "" {
		slice = c.Parent
	}

	properties = append(properties, systemdDbus.PropDescription("libcontainer container "+c.Name))

	// if we create a slice, the parent is defined via a Wants=
	if strings.HasSuffix(unitName, ".slice") {
		properties = append(properties, systemdDbus.PropWants(slice))
	} else {
		// otherwise, we use Slice=
		properties = append(properties, systemdDbus.PropSlice(slice))
	}

	// only add pid if its valid, -1 is used w/ general slice creation.
	if pid != -1 {
		properties = append(properties, newProp("PIDs", []uint32{uint32(pid)}))
	}

	// Check if we can delegate. This is only supported on systemd versions 218 and above.
	if !strings.HasSuffix(unitName, ".slice") {
		// Assume scopes always support delegation.
		properties = append(properties, newProp("Delegate", true))
	}

	// Always enable accounting, this gets us the same behaviour as the fs implementation,
	// plus the kernel has some problems with joining the memory cgroup at a later time.
	properties = append(properties,
		newProp("MemoryAccounting", true),
		newProp("CPUAccounting", true),
		newProp("IOAccounting", true))

	// Assume DefaultDependencies= will always work (the check for it was previously broken.)
	properties = append(properties,
		newProp("DefaultDependencies", false))

	if c.Resources.Memory != 0 {
		properties = append(properties,
			newProp("MemoryMax", uint64(c.Resources.Memory)))
	}

	if c.Resources.CpuWeight != 0 {
		properties = append(properties,
			newProp("CPUWeight", c.Resources.CpuWeight))
	}

	// cpu.cfs_quota_us and cpu.cfs_period_us are controlled by systemd.
	if c.Resources.CpuQuota != 0 && c.Resources.CpuPeriod != 0 {
		// corresponds to USEC_INFINITY in systemd
		// if USEC_INFINITY is provided, CPUQuota is left unbound by systemd
		// always setting a property value ensures we can apply a quota and remove it later
		cpuQuotaPerSecUSec := uint64(math.MaxUint64)
		if c.Resources.CpuQuota > 0 {
			// systemd converts CPUQuotaPerSecUSec (microseconds per CPU second) to CPUQuota
			// (integer percentage of CPU) internally.  This means that if a fractional percent of
			// CPU is indicated by Resources.CpuQuota, we need to round up to the nearest
			// 10ms (1% of a second) such that child cgroups can set the cpu.cfs_quota_us they expect.
			cpuQuotaPerSecUSec = uint64(c.Resources.CpuQuota*1000000) / c.Resources.CpuPeriod
			if cpuQuotaPerSecUSec%10000 != 0 {
				cpuQuotaPerSecUSec = ((cpuQuotaPerSecUSec / 10000) + 1) * 10000
			}
		}
		properties = append(properties,
			newProp("CPUQuotaPerSecUSec", cpuQuotaPerSecUSec))
	}

	if c.Resources.PidsLimit > 0 {
		properties = append(properties,
			newProp("TasksAccounting", true),
			newProp("TasksMax", uint64(c.Resources.PidsLimit)))
	}

	properties = append(properties, c.SystemdProps...)

	// ignore c.Resources.KernelMemory

	statusChan := make(chan string, 1)
	if _, err := theConn.StartTransientUnit(unitName, "replace", properties, statusChan); err == nil {
		select {
		case <-statusChan:
		case <-time.After(time.Second):
			logrus.Warnf("Timed out while waiting for StartTransientUnit(%s) completion signal from dbus. Continuing...", unitName)
		}
	} else if !isUnitExists(err) {
		return err
	}

	if err := joinCgroupsV2(c, pid); err != nil {
		return err
	}

	path, err := getv2Path(m.Cgroups)
	if err != nil {
		return err
	}
	m.Paths = map[string]string{
		"pids":    path,
		"memory":  path,
		"io":      path,
		"cpu":     path,
		"devices": path,
		"cpuset":  path,
		"freezer": path,
	}
	return nil
}

func (m *UnifiedManager) Destroy() error {
	if m.Cgroups.Paths != nil {
		return nil
	}
	m.mu.Lock()
	defer m.mu.Unlock()
	theConn.StopUnit(getUnitName(m.Cgroups), "replace", nil)
	if err := cgroups.RemovePaths(m.Paths); err != nil {
		return err
	}
	m.Paths = make(map[string]string)
	return nil
}

func (m *UnifiedManager) GetPaths() map[string]string {
	m.mu.Lock()
	paths := m.Paths
	m.mu.Unlock()
	return paths
}
func (m *UnifiedManager) GetUnifiedPath() (string, error) {
	unifiedPath := ""
	m.mu.Lock()
	defer m.mu.Unlock()
	for k, v := range m.Paths {
		if unifiedPath == "" {
			unifiedPath = v
		} else if v != unifiedPath {
			return unifiedPath,
				errors.Errorf("expected %q path to be unified path %q, got %q", k, unifiedPath, v)
		}
	}
	if unifiedPath == "" {
		// FIXME: unified path could be detected even when no controller is available
		return unifiedPath, errors.New("cannot detect unified path")
	}
	return unifiedPath, nil
}

func getv2Path(c *configs.Cgroup) (string, error) {
	slice := "system.slice"
	if c.Parent != "" {
		slice = c.Parent
	}

	slice, err := ExpandSlice(slice)
	if err != nil {
		return "", err
	}

	return filepath.Join(fs2.UnifiedMountpoint, slice, getUnitName(c)), nil
}

func createCgroupsv2Path(path string) (Err error) {
	content, err := ioutil.ReadFile("/sys/fs/cgroup/cgroup.controllers")
	if err != nil {
		return err
	}

	ctrs := bytes.Fields(content)
	res := append([]byte("+"), bytes.Join(ctrs, []byte(" +"))...)

	current := "/sys/fs"
	elements := strings.Split(path, "/")
	for i, e := range elements[3:] {
		current = filepath.Join(current, e)
		if i > 0 {
			if err := os.Mkdir(current, 0755); err != nil {
				if !os.IsExist(err) {
					return err
				}
			} else {
				// If the directory was created, be sure it is not left around on errors.
				defer func() {
					if Err != nil {
						os.Remove(current)
					}
				}()
			}
		}
		if i < len(elements[3:])-1 {
			if err := ioutil.WriteFile(filepath.Join(current, "cgroup.subtree_control"), res, 0755); err != nil {
				return err
			}
		}
	}
	return nil
}

func joinCgroupsV2(c *configs.Cgroup, pid int) error {
	path, err := getv2Path(c)
	if err != nil {
		return err
	}
	return createCgroupsv2Path(path)
}

func (m *UnifiedManager) fsManager() (cgroups.Manager, error) {
	path, err := m.GetUnifiedPath()
	if err != nil {
		return nil, err
	}
	return fs2.NewManager(m.Cgroups, path, false)
}

func (m *UnifiedManager) Freeze(state configs.FreezerState) error {
	fsMgr, err := m.fsManager()
	if err != nil {
		return err
	}
	return fsMgr.Freeze(state)
}

func (m *UnifiedManager) GetPids() ([]int, error) {
	path, err := m.GetUnifiedPath()
	if err != nil {
		return nil, err
	}
	return cgroups.GetPids(path)
}

func (m *UnifiedManager) GetAllPids() ([]int, error) {
	path, err := m.GetUnifiedPath()
	if err != nil {
		return nil, err
	}
	return cgroups.GetAllPids(path)
}

func (m *UnifiedManager) GetStats() (*cgroups.Stats, error) {
	fsMgr, err := m.fsManager()
	if err != nil {
		return nil, err
	}
	return fsMgr.GetStats()
}

func (m *UnifiedManager) Set(container *configs.Config) error {
	fsMgr, err := m.fsManager()
	if err != nil {
		return err
	}
	return fsMgr.Set(container)
}

func (m *UnifiedManager) GetCgroups() (*configs.Cgroup, error) {
	return m.Cgroups, nil
}
<|endoftext|>


<commit_before>package lib

import (
	"bytes"
	"encoding/json"
	"os"
	"testing"
	"time"

	"github.com/manyminds/api2go/jsonapi"

	"gopkg.in/mgo.v2/bson"
)

func TestGetID(t *testing.T) {
	id := bson.NewObjectId()
	b := Bookmark{ID: id}
	if b.GetID() != id.Hex() {
		t.Errorf("GetID() = %q; want: %q", b.GetID(), id.Hex())
	}
}

func TestSetID(t *testing.T) {
	b := Bookmark{}
	err := b.SetID("bogus id string")
	if err == nil {
		t.Error("err = nil")
	}

	err = b.SetID("")
	if err == nil {
		t.Error("err = nil")
	}

	err = b.SetID(bson.NewObjectId().Hex())
	if err != nil {
		t.Error(err)
	}
}

func ExampleBookmark() {
	timestamp := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
	b := Bookmark{
		Title:       "The Title",
		URL:         "http://example.com",
		Description: "A Description.",
		Timestamp:   timestamp,
		Tags:        []string{"foo", "bar"},
	}
	b.SetID("572135023cd994201b0bb61c")
	result, err := jsonapi.Marshal(b)
	if err != nil {
		return
	}
	var out bytes.Buffer
	json.Indent(&out, result, "", "  ")
	out.WriteTo(os.Stdout)
	// Output:
	// {
	//   "data": {
	//     "type": "bookmarks",
	//     "id": "572135023cd994201b0bb61c",
	//     "attributes": {
	//       "title": "The Title",
	//       "url": "http://example.com",
	//       "description": "A Description.",
	//       "timestamp": "2009-11-10T23:00:00Z",
	//       "tags": [
	//         "foo",
	//         "bar"
	//       ]
	//     }
	//   }
	// }
}
<commit_msg>Add error checks to Example func.<commit_after>package lib

import (
	"bytes"
	"encoding/json"
	"log"
	"os"
	"testing"
	"time"

	"github.com/manyminds/api2go/jsonapi"

	"gopkg.in/mgo.v2/bson"
)

func TestGetID(t *testing.T) {
	id := bson.NewObjectId()
	b := Bookmark{ID: id}
	if b.GetID() != id.Hex() {
		t.Errorf("GetID() = %q; want: %q", b.GetID(), id.Hex())
	}
}

func TestSetID(t *testing.T) {
	b := Bookmark{}
	err := b.SetID("bogus id string")
	if err == nil {
		t.Error("err = nil")
	}

	err = b.SetID("")
	if err == nil {
		t.Error("err = nil")
	}

	err = b.SetID(bson.NewObjectId().Hex())
	if err != nil {
		t.Error(err)
	}
}

func ExampleBookmark() {
	timestamp := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
	b := Bookmark{
		Title:       "The Title",
		URL:         "http://example.com",
		Description: "A Description.",
		Timestamp:   timestamp,
		Tags:        []string{"foo", "bar"},
	}
	if err := b.SetID("572135023cd994201b0bb61c"); err != nil {
		log.Fatal(err)
	}
	result, err := jsonapi.Marshal(b)
	if err != nil {
		return
	}
	var out bytes.Buffer
	if err := json.Indent(&out, result, "", "  "); err != nil {
		log.Fatal(err)
	}
	if _, err := out.WriteTo(os.Stdout); err != nil {
		log.Fatal(err)
	}
	// Output:
	// {
	//   "data": {
	//     "type": "bookmarks",
	//     "id": "572135023cd994201b0bb61c",
	//     "attributes": {
	//       "title": "The Title",
	//       "url": "http://example.com",
	//       "description": "A Description.",
	//       "timestamp": "2009-11-10T23:00:00Z",
	//       "tags": [
	//         "foo",
	//         "bar"
	//       ]
	//     }
	//   }
	// }
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"
)

// ReadFile takes a relative path and returns the bytes in that file
func ReadFile(filename string) (data []byte, err error) {
	path, err := filepath.Abs(filename)
	if err != nil {
		fmt.Println("ERROR: Unable to file:", filename)
		return nil, err
	}

	filehandle, err := os.Open(path)
	if err != nil {
		fmt.Println("ERROR: Error opening file:", path)
		return nil, err
	}
	defer filehandle.Close()

	data, err = ioutil.ReadAll(filehandle)
	if err != nil {
		return nil, err
	}

	return data, nil
}

// ConfigRules holds our json file containing our config
var ConfigRules ConfigRuleList

// ConfigRule is a container for each individual rule
type ConfigRule struct {
    Title     string                   `json:"title"`
	CheckCommand     string            `json:"check_command"`
	FixCommand       string            `json:"fix_command"`
	Enabled          bool              `json:"enabled"`
	AllowRemediation *bool             `json:"allow_remediation"`
}

// ConfigRuleList is an array
type ConfigRuleList []ConfigRule

// ReadConfigRules reads our json file
func ReadConfigRules(configFile string) error {
	jsonFile, err := ReadFile(configFile)
	if err != nil {
		return err
	}

	err = json.Unmarshal(jsonFile, &ConfigRules)
	if err != nil {
		return err
	}
	return nil
}

// RunCommand returns true if the audit passed, or command was successful
func RunCommand(cmd string) bool {
	_, err := exec.Command("bash", "-c", cmd).Output()
	if err != nil {
		return false
	}

	return true
}

// SystemInfo holds system information
type SystemInfo struct {
	SerialNumber string
	HardwareUUID string
}

// GetCommandOutput runs a command and returns it's output
func GetCommandOutput(cmd string) string {
	out, _ := exec.Command("bash", "-c", cmd).Output()
	return strings.TrimSpace(string(out))
}

// GetSystemInfo collects information about the system
func GetSystemInfo() (sysinfo SystemInfo) {
	sysinfo.SerialNumber = GetCommandOutput("system_profiler SPHardwareDataType | grep \"Serial Number\" | cut -d: -f2")
	sysinfo.HardwareUUID = GetCommandOutput("system_profiler SPHardwareDataType | grep \"Hardware UUID\" | cut -d: -f2")

	return sysinfo
}

// CalculateScore returns the compliance score for this system
func CalculateScore(ruleCount int, failCount int) int {
    if ruleCount == 0 { return 0}
	return int(float64(ruleCount-failCount) / float64(ruleCount) * 100.0)
}

// AllowRemediation returns true if the rule is allowed to be remediated
func AllowRemediation(configRule ConfigRule) bool {
	return configRule.FixCommand != "" && (configRule.AllowRemediation == nil || *configRule.AllowRemediation)
}

func main() {

	hideSummary := flag.Bool("hide_summary", false, "Disables printing the summary")
	hidePasses := flag.Bool("hide_passes", false, "Disables printing the rules that passed")
	remediate := flag.Bool("remediate", false, "Implements fixes for failed checks. WARNING: Beware this may break things.")

	var commandFile string
	flag.StringVar(&commandFile, "commands_file", "commands.json", "JSON file containing the commands and configuration")

	flag.Parse()

	// Check OS version to make sure we will work
	osVersion := GetCommandOutput("system_profiler SPSoftwareDataType | grep \"System Version\" | cut -d: -f2")
	if !strings.Contains(osVersion, "OS X 10.11") {
		fmt.Println("ERROR: Unsupported OS. This tool was meant to be used only on OSX 10.11 (El Capitan)")
		return
	}

	// Read our command/config file
	err := ReadConfigRules(commandFile)
	if err != nil {
		fmt.Println(err)
		return
	}

	// Run commands and print results
	ruleCount := 0
	failCount := 0

    for _, rule := range ConfigRules {
        if rule.Enabled {
            checkCommand := rule.CheckCommand
            ruleCount++

            result := RunCommand(checkCommand)

            resultText := "PASSED"
            if !result {
                // Audit failed, check if we can remediate
                if *remediate && AllowRemediation(rule) {
                    // Remediate
                    fixCommand := rule.FixCommand
                    RunCommand(fixCommand)
                    // Check our fix worked
                    result = RunCommand(checkCommand)
                    if result {
                        resultText = "FIXED "
                    }
                }

                if !result {
                    failCount++
                    resultText = "FAILED"
                }
            }

            if !result || !*hidePasses {
                fmt.Printf("[%s] %s\n", resultText, rule.Title)
            }
        }
    }

	// Print summary
	if !*hideSummary {
		fmt.Printf("-------------------------------------------------------------------------------\n")
		t := time.Now()
		fmt.Printf("Date: %s\n", t.Format("2006-01-02T15:04:05-07:00"))
		sysinfo := GetSystemInfo()
		fmt.Printf("SerialNumber: %s\nHardwareUUID: %s\n", sysinfo.SerialNumber, sysinfo.HardwareUUID)
		fmt.Printf("Final Score %d%%; Pass rate: %d/%d\n",
			CalculateScore(ruleCount, failCount),
			(ruleCount-failCount), ruleCount)
	}
}
<commit_msg>Colorful statutes<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"
)

// ReadFile takes a relative path and returns the bytes in that file
func ReadFile(filename string) (data []byte, err error) {
	path, err := filepath.Abs(filename)
	if err != nil {
		fmt.Println("ERROR: Unable to file:", filename)
		return nil, err
	}

	filehandle, err := os.Open(path)
	if err != nil {
		fmt.Println("ERROR: Error opening file:", path)
		return nil, err
	}
	defer filehandle.Close()

	data, err = ioutil.ReadAll(filehandle)
	if err != nil {
		return nil, err
	}

	return data, nil
}

// ConfigRules holds our json file containing our config
var ConfigRules ConfigRuleList

// ConfigRule is a container for each individual rule
type ConfigRule struct {
    Title     string                   `json:"title"`
	CheckCommand     string            `json:"check_command"`
	FixCommand       string            `json:"fix_command"`
	Enabled          bool              `json:"enabled"`
	AllowRemediation *bool             `json:"allow_remediation"`
}

// ConfigRuleList is an array
type ConfigRuleList []ConfigRule

// ReadConfigRules reads our json file
func ReadConfigRules(configFile string) error {
	jsonFile, err := ReadFile(configFile)
	if err != nil {
		return err
	}

	err = json.Unmarshal(jsonFile, &ConfigRules)
	if err != nil {
		return err
	}
	return nil
}

// RunCommand returns true if the audit passed, or command was successful
func RunCommand(cmd string) bool {
	_, err := exec.Command("bash", "-c", cmd).Output()
	if err != nil {
		return false
	}

	return true
}

// SystemInfo holds system information
type SystemInfo struct {
	SerialNumber string
	HardwareUUID string
}

// GetCommandOutput runs a command and returns it's output
func GetCommandOutput(cmd string) string {
	out, _ := exec.Command("bash", "-c", cmd).Output()
	return strings.TrimSpace(string(out))
}

// GetSystemInfo collects information about the system
func GetSystemInfo() (sysinfo SystemInfo) {
	sysinfo.SerialNumber = GetCommandOutput("system_profiler SPHardwareDataType | grep \"Serial Number\" | cut -d: -f2")
	sysinfo.HardwareUUID = GetCommandOutput("system_profiler SPHardwareDataType | grep \"Hardware UUID\" | cut -d: -f2")

	return sysinfo
}

// CalculateScore returns the compliance score for this system
func CalculateScore(ruleCount int, failCount int) int {
    if ruleCount == 0 { return 0}
	return int(float64(ruleCount-failCount) / float64(ruleCount) * 100.0)
}

// AllowRemediation returns true if the rule is allowed to be remediated
func AllowRemediation(configRule ConfigRule) bool {
	return configRule.FixCommand != "" && (configRule.AllowRemediation == nil || *configRule.AllowRemediation)
}

func main() {

	hideSummary := flag.Bool("hide_summary", false, "Disables printing the summary")
	hidePasses := flag.Bool("hide_passes", false, "Disables printing the rules that passed")
	remediate := flag.Bool("remediate", false, "Implements fixes for failed checks. WARNING: Beware this may break things.")

	var commandFile string
	flag.StringVar(&commandFile, "commands_file", "commands.json", "JSON file containing the commands and configuration")

	flag.Parse()

	// Check OS version to make sure we will work
	osVersion := GetCommandOutput("system_profiler SPSoftwareDataType | grep \"System Version\" | cut -d: -f2")
	if !strings.Contains(osVersion, "OS X 10.11") {
		fmt.Println("ERROR: Unsupported OS. This tool was meant to be used only on OSX 10.11 (El Capitan)")
		return
	}

	// Read our command/config file
	err := ReadConfigRules(commandFile)
	if err != nil {
		fmt.Println(err)
		return
	}

	// Run commands and print results
	ruleCount := 0
	failCount := 0

    for _, rule := range ConfigRules {
        if rule.Enabled {
            checkCommand := rule.CheckCommand
            ruleCount++

            result := RunCommand(checkCommand)

            resultText := "\033[32mPASSED\033[39m"
            if !result {
                // Audit failed, check if we can remediate
                if *remediate && AllowRemediation(rule) {
                    // Remediate
                    fixCommand := rule.FixCommand
                    RunCommand(fixCommand)
                    // Check our fix worked
                    result = RunCommand(checkCommand)
                    if result {
                        resultText = "\033[34mFIXED \033[39m"
                    }
                }

                if !result {
                    failCount++
                    resultText = "\033[31mFAILED\033[39m"
                }
            }

            if !result || !*hidePasses {
                fmt.Printf("[%s] %s\n", resultText, rule.Title)
            }
        }
    }

	// Print summary
	if !*hideSummary {
		fmt.Printf("-------------------------------------------------------------------------------\n")
		t := time.Now()
		fmt.Printf("Date: %s\n", t.Format("2006-01-02T15:04:05-07:00"))
		sysinfo := GetSystemInfo()
		fmt.Printf("SerialNumber: %s\nHardwareUUID: %s\n", sysinfo.SerialNumber, sysinfo.HardwareUUID)
		fmt.Printf("Final Score %d%%; Pass rate: %d/%d\n",
			CalculateScore(ruleCount, failCount),
			(ruleCount-failCount), ruleCount)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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 main

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/golang/protobuf/proto"
	"k8s.io/test-infra/prow/jobs"
	config "k8s.io/test-infra/testgrid/config/pb"
	"k8s.io/test-infra/testgrid/config/yaml2proto"
)

func main() {
	args := os.Args[1:]

	if len(args) != 3 {
		fmt.Println("Missing args - usage: go run jenkins_validate.go <path/to/job_collection> <path/to/prow> <path/to/testgrid_config>")
		os.Exit(1)
	}

	jobPath := args[0]
	prowPath := args[1]
	configPath := args[2]

	jenkinsjobs := make(map[string]bool)
	files, err := filepath.Glob(jobPath + "/*")
	if err != nil {
		fmt.Println("Failed to collect outputs.")
		os.Exit(1)
	}

	for _, file := range files {
		file = strings.TrimPrefix(file, jobPath+"/")
		jenkinsjobs[file] = false
	}

	data, err := ioutil.ReadFile(configPath)
	protobufData, err := yaml2proto.Yaml2Proto(data)

	config := &config.Configuration{}
	if err := proto.Unmarshal(protobufData, config); err != nil {
		fmt.Printf("Failed to parse config: %v\n", err)
		os.Exit(1)
	}

	ja := jobs.JobAgent{}
	if err := ja.LoadOnce(prowPath+"/presubmit.yaml", prowPath+"/postsubmit.yaml"); err != nil {
		fmt.Printf("Could not load prow configs: %v\n", err)
		os.Exit(1)
	}

	// For now anything outsite k8s-jenkins/logs are considered to be fine
	testgroups := make(map[string]bool)
	for _, testgroup := range config.TestGroups {
		if strings.Contains(testgroup.GcsPrefix, "kubernetes-jenkins/logs/") {
			job := strings.TrimPrefix(testgroup.GcsPrefix, "kubernetes-jenkins/logs/")
			testgroups[job] = false
		}
	}

	// Cross check
	// -- Each jenkins job need to have a match testgrid group
	for jenkinsjob, _ := range jenkinsjobs {
		if _, ok := testgroups[jenkinsjob]; ok {
			testgroups[jenkinsjob] = true
			jenkinsjobs[jenkinsjob] = true
		}
	}

	// Also check prow jobs
	for _, job := range ja.AllJobNames() {
		if _, ok := testgroups[job]; ok {
			testgroups[job] = true
			jenkinsjobs[job] = true
		}
	}

	// Conclusion
	badjobs := []string{}
	for jenkinsjob, valid := range jenkinsjobs {
		if !valid {
			badjobs = append(badjobs, jenkinsjob)
			fmt.Printf("Job %v does not have a matching testgrid testgroup\n", jenkinsjob)
		}
	}

	badconfigs := []string{}
	for testgroup, valid := range testgroups {
		if !valid {
			badconfigs = append(badconfigs, testgroup)
			fmt.Printf("Testgrid group %v does not have a matching jenkins or prow job\n", testgroup)
		}
	}

	if len(badconfigs) > 0 {
		fmt.Printf("Total bad config - %v\n", len(badconfigs))
	}

	if len(badjobs) > 0 {
		fmt.Printf("Total bad jenkins job - %v\n", len(badjobs))
	}

	if len(badconfigs) > 0 || len(badjobs) > 0 {
		os.Exit(1)
	}
}
<commit_msg>handle err  when convert yaml to protobuf<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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 main

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/golang/protobuf/proto"
	"k8s.io/test-infra/prow/jobs"
	config "k8s.io/test-infra/testgrid/config/pb"
	"k8s.io/test-infra/testgrid/config/yaml2proto"
)

func main() {
	args := os.Args[1:]

	if len(args) != 3 {
		fmt.Println("Missing args - usage: go run jenkins_validate.go <path/to/job_collection> <path/to/prow> <path/to/testgrid_config>")
		os.Exit(1)
	}

	jobPath := args[0]
	prowPath := args[1]
	configPath := args[2]

	jenkinsjobs := make(map[string]bool)
	files, err := filepath.Glob(jobPath + "/*")
	if err != nil {
		fmt.Println("Failed to collect outputs.")
		os.Exit(1)
	}

	for _, file := range files {
		file = strings.TrimPrefix(file, jobPath+"/")
		jenkinsjobs[file] = false
	}

	data, err := ioutil.ReadFile(configPath)
	protobufData, err := yaml2proto.Yaml2Proto(data)
	if err != nil {
		fmt.Printf("Failed to convert yaml to protobuf: %v\n", err)
		os.Exit(1)
	}

	config := &config.Configuration{}
	if err := proto.Unmarshal(protobufData, config); err != nil {
		fmt.Printf("Failed to parse config: %v\n", err)
		os.Exit(1)
	}

	ja := jobs.JobAgent{}
	if err := ja.LoadOnce(prowPath+"/presubmit.yaml", prowPath+"/postsubmit.yaml"); err != nil {
		fmt.Printf("Could not load prow configs: %v\n", err)
		os.Exit(1)
	}

	// For now anything outsite k8s-jenkins/logs are considered to be fine
	testgroups := make(map[string]bool)
	for _, testgroup := range config.TestGroups {
		if strings.Contains(testgroup.GcsPrefix, "kubernetes-jenkins/logs/") {
			job := strings.TrimPrefix(testgroup.GcsPrefix, "kubernetes-jenkins/logs/")
			testgroups[job] = false
		}
	}

	// Cross check
	// -- Each jenkins job need to have a match testgrid group
	for jenkinsjob, _ := range jenkinsjobs {
		if _, ok := testgroups[jenkinsjob]; ok {
			testgroups[jenkinsjob] = true
			jenkinsjobs[jenkinsjob] = true
		}
	}

	// Also check prow jobs
	for _, job := range ja.AllJobNames() {
		if _, ok := testgroups[job]; ok {
			testgroups[job] = true
			jenkinsjobs[job] = true
		}
	}

	// Conclusion
	badjobs := []string{}
	for jenkinsjob, valid := range jenkinsjobs {
		if !valid {
			badjobs = append(badjobs, jenkinsjob)
			fmt.Printf("Job %v does not have a matching testgrid testgroup\n", jenkinsjob)
		}
	}

	badconfigs := []string{}
	for testgroup, valid := range testgroups {
		if !valid {
			badconfigs = append(badconfigs, testgroup)
			fmt.Printf("Testgrid group %v does not have a matching jenkins or prow job\n", testgroup)
		}
	}

	if len(badconfigs) > 0 {
		fmt.Printf("Total bad config - %v\n", len(badconfigs))
	}

	if len(badjobs) > 0 {
		fmt.Printf("Total bad jenkins job - %v\n", len(badjobs))
	}

	if len(badconfigs) > 0 || len(badjobs) > 0 {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>// Copyright The OpenTelemetry Authors
//
// 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 telemetry // import "go.opentelemetry.io/collector/service/internal/telemetry"

import (
	"os"
	"runtime"
	"sync"
	"time"

	"github.com/shirou/gopsutil/v3/process"
	"go.opencensus.io/metric"
	"go.opencensus.io/stats"
)

// processMetrics is a struct that contains views related to process metrics (cpu, mem, etc)
type processMetrics struct {
	startTimeUnixNano int64
	ballastSizeBytes  uint64
	proc              *process.Process

	processUptime *metric.Float64DerivedCumulative
	allocMem      *metric.Int64DerivedGauge
	totalAllocMem *metric.Int64DerivedCumulative
	sysMem        *metric.Int64DerivedGauge
	cpuSeconds    *metric.Float64DerivedCumulative
	rssMemory     *metric.Int64DerivedGauge

	// mu protects everything bellow.
	mu         sync.Mutex
	lastMsRead time.Time
	ms         *runtime.MemStats
}

// RegisterProcessMetrics creates a new set of processMetrics (mem, cpu) that can be used to measure
// basic information about this process.
func RegisterProcessMetrics(registry *metric.Registry, ballastSizeBytes uint64) error {
	pm := &processMetrics{
		startTimeUnixNano: time.Now().UnixNano(),
		ballastSizeBytes:  ballastSizeBytes,
		ms:                &runtime.MemStats{},
	}
	var err error
	pm.proc, err = process.NewProcess(int32(os.Getpid()))
	if err != nil {
		return err
	}

	pm.processUptime, err = registry.AddFloat64DerivedCumulative(
		"process/uptime",
		metric.WithDescription("Uptime of the process"),
		metric.WithUnit(stats.UnitSeconds))
	if err != nil {
		return err
	}
	if err = pm.processUptime.UpsertEntry(pm.updateProcessUptime); err != nil {
		return err
	}

	pm.allocMem, err = registry.AddInt64DerivedGauge(
		"process/runtime/heap_alloc_bytes",
		metric.WithDescription("Bytes of allocated heap objects (see 'go doc runtime.MemStats.HeapAlloc')"),
		metric.WithUnit(stats.UnitBytes))
	if err != nil {
		return err
	}
	if err = pm.allocMem.UpsertEntry(pm.updateAllocMem); err != nil {
		return err
	}

	pm.totalAllocMem, err = registry.AddInt64DerivedCumulative(
		"process/runtime/total_alloc_bytes",
		metric.WithDescription("Cumulative bytes allocated for heap objects (see 'go doc runtime.MemStats.TotalAlloc')"),
		metric.WithUnit(stats.UnitBytes))
	if err != nil {
		return err
	}
	if err = pm.totalAllocMem.UpsertEntry(pm.updateTotalAllocMem); err != nil {
		return err
	}

	pm.sysMem, err = registry.AddInt64DerivedGauge(
		"process/runtime/total_sys_memory_bytes",
		metric.WithDescription("Total bytes of memory obtained from the OS (see 'go doc runtime.MemStats.Sys')"),
		metric.WithUnit(stats.UnitBytes))
	if err != nil {
		return err
	}
	if err = pm.sysMem.UpsertEntry(pm.updateSysMem); err != nil {
		return err
	}

	pm.cpuSeconds, err = registry.AddFloat64DerivedCumulative(
		"process/cpu_seconds",
		metric.WithDescription("Total CPU user and system time in seconds"),
		metric.WithUnit(stats.UnitSeconds))
	if err != nil {
		return err
	}
	if err = pm.cpuSeconds.UpsertEntry(pm.updateCPUSeconds); err != nil {
		return err
	}

	pm.rssMemory, err = registry.AddInt64DerivedGauge(
		"process/memory/rss",
		metric.WithDescription("Total physical memory (resident set size)"),
		metric.WithUnit(stats.UnitBytes))
	if err != nil {
		return err
	}
	if err = pm.rssMemory.UpsertEntry(pm.updateRSSMemory); err != nil {
		return err
	}

	return nil
}

func (pm *processMetrics) updateProcessUptime() float64 {
	now := time.Now().UnixNano()
	return float64(now-pm.startTimeUnixNano) / 1e9
}

func (pm *processMetrics) updateAllocMem() int64 {
	pm.mu.Lock()
	defer pm.mu.Unlock()
	pm.readMemStatsIfNeeded()
	return int64(pm.ms.Alloc)
}

func (pm *processMetrics) updateTotalAllocMem() int64 {
	pm.mu.Lock()
	defer pm.mu.Unlock()
	pm.readMemStatsIfNeeded()
	return int64(pm.ms.TotalAlloc)
}

func (pm *processMetrics) updateSysMem() int64 {
	pm.mu.Lock()
	defer pm.mu.Unlock()
	pm.readMemStatsIfNeeded()
	return int64(pm.ms.Sys)
}

func (pm *processMetrics) updateCPUSeconds() float64 {
	times, err := pm.proc.Times()
	if err != nil {
		return 0
	}

	return times.Total()
}

func (pm *processMetrics) updateRSSMemory() int64 {
	mem, err := pm.proc.MemoryInfo()
	if err != nil {
		return 0
	}
	return int64(mem.RSS)
}

func (pm *processMetrics) readMemStatsIfNeeded() {
	now := time.Now()
	// If last time we read was less than one second ago just reuse the values
	if now.Sub(pm.lastMsRead) < time.Second {
		return
	}
	pm.lastMsRead = now
	runtime.ReadMemStats(pm.ms)
	if pm.ballastSizeBytes > 0 {
		pm.ms.Alloc -= pm.ballastSizeBytes
		pm.ms.HeapAlloc -= pm.ballastSizeBytes
		pm.ms.HeapSys -= pm.ballastSizeBytes
		pm.ms.HeapInuse -= pm.ballastSizeBytes
	}
}
<commit_msg>Fix lint error due to the usage of deprecated method (#5989)<commit_after>// Copyright The OpenTelemetry Authors
//
// 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 telemetry // import "go.opentelemetry.io/collector/service/internal/telemetry"

import (
	"os"
	"runtime"
	"sync"
	"time"

	"github.com/shirou/gopsutil/v3/process"
	"go.opencensus.io/metric"
	"go.opencensus.io/stats"
)

// processMetrics is a struct that contains views related to process metrics (cpu, mem, etc)
type processMetrics struct {
	startTimeUnixNano int64
	ballastSizeBytes  uint64
	proc              *process.Process

	processUptime *metric.Float64DerivedCumulative
	allocMem      *metric.Int64DerivedGauge
	totalAllocMem *metric.Int64DerivedCumulative
	sysMem        *metric.Int64DerivedGauge
	cpuSeconds    *metric.Float64DerivedCumulative
	rssMemory     *metric.Int64DerivedGauge

	// mu protects everything bellow.
	mu         sync.Mutex
	lastMsRead time.Time
	ms         *runtime.MemStats
}

// RegisterProcessMetrics creates a new set of processMetrics (mem, cpu) that can be used to measure
// basic information about this process.
func RegisterProcessMetrics(registry *metric.Registry, ballastSizeBytes uint64) error {
	pm := &processMetrics{
		startTimeUnixNano: time.Now().UnixNano(),
		ballastSizeBytes:  ballastSizeBytes,
		ms:                &runtime.MemStats{},
	}
	var err error
	pm.proc, err = process.NewProcess(int32(os.Getpid()))
	if err != nil {
		return err
	}

	pm.processUptime, err = registry.AddFloat64DerivedCumulative(
		"process/uptime",
		metric.WithDescription("Uptime of the process"),
		metric.WithUnit(stats.UnitSeconds))
	if err != nil {
		return err
	}
	if err = pm.processUptime.UpsertEntry(pm.updateProcessUptime); err != nil {
		return err
	}

	pm.allocMem, err = registry.AddInt64DerivedGauge(
		"process/runtime/heap_alloc_bytes",
		metric.WithDescription("Bytes of allocated heap objects (see 'go doc runtime.MemStats.HeapAlloc')"),
		metric.WithUnit(stats.UnitBytes))
	if err != nil {
		return err
	}
	if err = pm.allocMem.UpsertEntry(pm.updateAllocMem); err != nil {
		return err
	}

	pm.totalAllocMem, err = registry.AddInt64DerivedCumulative(
		"process/runtime/total_alloc_bytes",
		metric.WithDescription("Cumulative bytes allocated for heap objects (see 'go doc runtime.MemStats.TotalAlloc')"),
		metric.WithUnit(stats.UnitBytes))
	if err != nil {
		return err
	}
	if err = pm.totalAllocMem.UpsertEntry(pm.updateTotalAllocMem); err != nil {
		return err
	}

	pm.sysMem, err = registry.AddInt64DerivedGauge(
		"process/runtime/total_sys_memory_bytes",
		metric.WithDescription("Total bytes of memory obtained from the OS (see 'go doc runtime.MemStats.Sys')"),
		metric.WithUnit(stats.UnitBytes))
	if err != nil {
		return err
	}
	if err = pm.sysMem.UpsertEntry(pm.updateSysMem); err != nil {
		return err
	}

	pm.cpuSeconds, err = registry.AddFloat64DerivedCumulative(
		"process/cpu_seconds",
		metric.WithDescription("Total CPU user and system time in seconds"),
		metric.WithUnit(stats.UnitSeconds))
	if err != nil {
		return err
	}
	if err = pm.cpuSeconds.UpsertEntry(pm.updateCPUSeconds); err != nil {
		return err
	}

	pm.rssMemory, err = registry.AddInt64DerivedGauge(
		"process/memory/rss",
		metric.WithDescription("Total physical memory (resident set size)"),
		metric.WithUnit(stats.UnitBytes))
	if err != nil {
		return err
	}
	if err = pm.rssMemory.UpsertEntry(pm.updateRSSMemory); err != nil {
		return err
	}

	return nil
}

func (pm *processMetrics) updateProcessUptime() float64 {
	now := time.Now().UnixNano()
	return float64(now-pm.startTimeUnixNano) / 1e9
}

func (pm *processMetrics) updateAllocMem() int64 {
	pm.mu.Lock()
	defer pm.mu.Unlock()
	pm.readMemStatsIfNeeded()
	return int64(pm.ms.Alloc)
}

func (pm *processMetrics) updateTotalAllocMem() int64 {
	pm.mu.Lock()
	defer pm.mu.Unlock()
	pm.readMemStatsIfNeeded()
	return int64(pm.ms.TotalAlloc)
}

func (pm *processMetrics) updateSysMem() int64 {
	pm.mu.Lock()
	defer pm.mu.Unlock()
	pm.readMemStatsIfNeeded()
	return int64(pm.ms.Sys)
}

func (pm *processMetrics) updateCPUSeconds() float64 {
	times, err := pm.proc.Times()
	if err != nil {
		return 0
	}

	return times.User + times.System + times.Idle + times.Nice +
		times.Iowait + times.Irq + times.Softirq + times.Steal
}

func (pm *processMetrics) updateRSSMemory() int64 {
	mem, err := pm.proc.MemoryInfo()
	if err != nil {
		return 0
	}
	return int64(mem.RSS)
}

func (pm *processMetrics) readMemStatsIfNeeded() {
	now := time.Now()
	// If last time we read was less than one second ago just reuse the values
	if now.Sub(pm.lastMsRead) < time.Second {
		return
	}
	pm.lastMsRead = now
	runtime.ReadMemStats(pm.ms)
	if pm.ballastSizeBytes > 0 {
		pm.ms.Alloc -= pm.ballastSizeBytes
		pm.ms.HeapAlloc -= pm.ballastSizeBytes
		pm.ms.HeapSys -= pm.ballastSizeBytes
		pm.ms.HeapInuse -= pm.ballastSizeBytes
	}
}
<|endoftext|>


<commit_before>package jobfile

import (
	"bytes"
	"github.com/dshearer/jobber/Godeps/_workspace/src/github.com/stretchr/testify/require"
	"testing"
)

const NewJobFileEx string = `
[prefs]
notifyProgram: ~/handleError

[jobs]
- name: DailyBackup
  cmd: backup daily
  time: 0 0 14
  onError: Stop
  notifyOnError: false
  notifyOnFailure: true

- name: WeeklyBackup
  cmd: |
    multi-
    line
    script
  time: 0 0 14 * * 1
  onError: Backoff
  notifyOnError: true
  notifyOnFailure: false
`

const LegacyJobFileEx string = `---
- name: DailyBackup
  cmd: backup daily
  time: 0 0 14
  onError: Stop
  notifyOnError: false
  notifyOnFailure: true

- name: WeeklyBackup
  cmd: |
    multi-
    line
    script
  time: 0 0 14 * * 1
  onError: Backoff
  notifyOnError: true
  notifyOnFailure: false

- name: JobA
  cmd: whatever
  time: "* * * * * *"
  onError: Backoff
  notifyOnError: true
  notifyOnFailure: false

- name: JobB
  cmd: whatever
  time: '*'
  onError: Backoff
  notifyOnError: true
  notifyOnFailure: false`

const UsernameEx string = "bob"

var EverySecTimeSpec FullTimeSpec = FullTimeSpec{WildcardTimeSpec{},
	WildcardTimeSpec{},
	WildcardTimeSpec{},
	WildcardTimeSpec{},
	WildcardTimeSpec{},
	WildcardTimeSpec{}}

func TestParseFullTimeSpec(t *testing.T) {
	evens := []int{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22}
	threes := []int{1, 4, 7, 10, 13, 16, 19, 22}
	cases := []struct {
		str  string
		spec FullTimeSpec
	}{
		{"0 0 14", FullTimeSpec{OneValTimeSpec{0},
			OneValTimeSpec{0},
			OneValTimeSpec{14},
			WildcardTimeSpec{},
			WildcardTimeSpec{},
			WildcardTimeSpec{}}},
		{"0 0 14 * * 1", FullTimeSpec{OneValTimeSpec{0},
			OneValTimeSpec{0},
			OneValTimeSpec{14},
			WildcardTimeSpec{},
			WildcardTimeSpec{},
			OneValTimeSpec{1}}},
		{"0 0 */2 * * 1", FullTimeSpec{OneValTimeSpec{0},
			OneValTimeSpec{0},
			SetTimeSpec{"*/2", evens},
			WildcardTimeSpec{},
			WildcardTimeSpec{},
			OneValTimeSpec{1}}},
		{"0 0 1,4,7,10,13,16,19,22 * * 1", FullTimeSpec{OneValTimeSpec{0},
			OneValTimeSpec{0},
			SetTimeSpec{"1,4,7,10,13,16,19,22", threes},
			WildcardTimeSpec{},
			WildcardTimeSpec{},
			OneValTimeSpec{1}}},
	}

	for _, c := range cases {
		/*
		 * Call
		 */
		var result *FullTimeSpec
		var err error
		result, err = ParseFullTimeSpec(c.str)

		/*
		 * Test
		 */
		if err != nil {
			t.Fatalf("Got error: %v", err)
		}
		require.Equal(t, c.spec, *result)
	}
}

func TestReadNewJobberFile(t *testing.T) {
	/*
	 * Set up
	 */
	buf := bytes.NewBufferString(NewJobFileEx)

	/*
	 * Call
	 */
	var file *JobberFile
	file, err := readJobberFile(buf, UsernameEx)

	/*
	 * Test
	 */
	if err != nil {
		t.Fatalf("Got error: %v", err)
	}
	if file == nil {
		t.Fatalf("jobs == nil")
	}

	// test prefs
	require.NotNil(t, file.Prefs.Notifier)

	// test jobs
	require.Equal(t, 2, len(file.Jobs))

	// test DailyBackup
	daily := file.Jobs[0]
	require.Equal(t, "DailyBackup", daily.Name)
	require.Equal(t, "backup daily", daily.Cmd)
	require.Equal(t, &ErrorHandlerStop, daily.ErrorHandler)
	require.Equal(t, false, daily.NotifyOnError)
	require.Equal(t, true, daily.NotifyOnFailure)

	// test WeeklyBackup
	weekly := file.Jobs[1]
	require.Equal(t, "WeeklyBackup", weekly.Name)
	require.Equal(t, `multi-
line
script
`, weekly.Cmd)
	require.Equal(t, &ErrorHandlerBackoff, weekly.ErrorHandler)
	require.Equal(t, true, weekly.NotifyOnError)
	require.Equal(t, false, weekly.NotifyOnFailure)
}

func TestReadLegacyJobberFile(t *testing.T) {
	/*
	 * Set up
	 */
	buf := bytes.NewBufferString(LegacyJobFileEx)

	/*
	 * Call
	 */
	var file *JobberFile
	file, err := readJobberFile(buf, UsernameEx)

	/*
	 * Test
	 */
	if err != nil {
		t.Fatalf("Got error: %v", err)
	}
	if file == nil {
		t.Fatalf("jobs == nil")
	}
	require.Equal(t, 4, len(file.Jobs))

	// test DailyBackup
	daily := file.Jobs[0]
	require.Equal(t, "DailyBackup", daily.Name)
	require.Equal(t, "backup daily", daily.Cmd)
	require.Equal(t, &ErrorHandlerStop, daily.ErrorHandler)
	require.Equal(t, false, daily.NotifyOnError)
	require.Equal(t, true, daily.NotifyOnFailure)

	// test WeeklyBackup
	weekly := file.Jobs[1]
	require.Equal(t, "WeeklyBackup", weekly.Name)
	require.Equal(t, `multi-
line
script
`, weekly.Cmd)
	require.Equal(t, &ErrorHandlerBackoff, weekly.ErrorHandler)
	require.Equal(t, true, weekly.NotifyOnError)
	require.Equal(t, false, weekly.NotifyOnFailure)

	// test JobA
	jobA := file.Jobs[2]
	require.Equal(t, "JobA", jobA.Name)
	require.Equal(t, EverySecTimeSpec, jobA.FullTimeSpec)

	// test JobB
	jobB := file.Jobs[3]
	require.Equal(t, "JobB", jobB.Name)
	require.Equal(t, EverySecTimeSpec, jobB.FullTimeSpec)
}
<commit_msg>Add test cases for "10,20" and "0-5" in time spec<commit_after>package jobfile

import (
	"bytes"
	"github.com/dshearer/jobber/Godeps/_workspace/src/github.com/stretchr/testify/require"
	"testing"
)

const NewJobFileEx string = `
[prefs]
notifyProgram: ~/handleError

[jobs]
- name: DailyBackup
  cmd: backup daily
  time: 0 0 14
  onError: Stop
  notifyOnError: false
  notifyOnFailure: true

- name: WeeklyBackup
  cmd: |
    multi-
    line
    script
  time: 0 0 14 * * 1
  onError: Backoff
  notifyOnError: true
  notifyOnFailure: false
`

const LegacyJobFileEx string = `---
- name: DailyBackup
  cmd: backup daily
  time: 0 0 14
  onError: Stop
  notifyOnError: false
  notifyOnFailure: true

- name: WeeklyBackup
  cmd: |
    multi-
    line
    script
  time: 0 0 14 * * 1
  onError: Backoff
  notifyOnError: true
  notifyOnFailure: false

- name: JobA
  cmd: whatever
  time: "* * * * * *"
  onError: Backoff
  notifyOnError: true
  notifyOnFailure: false

- name: JobB
  cmd: whatever
  time: '*'
  onError: Backoff
  notifyOnError: true
  notifyOnFailure: false`

const UsernameEx string = "bob"

var EverySecTimeSpec FullTimeSpec = FullTimeSpec{WildcardTimeSpec{},
	WildcardTimeSpec{},
	WildcardTimeSpec{},
	WildcardTimeSpec{},
	WildcardTimeSpec{},
	WildcardTimeSpec{}}

func TestParseFullTimeSpec(t *testing.T) {
	evens := []int{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22}
	threes := []int{1, 4, 7, 10, 13, 16, 19, 22}
	cases := []struct {
		str  string
		spec FullTimeSpec
	}{
		{"0 0 14", FullTimeSpec{
		    OneValTimeSpec{0},
			OneValTimeSpec{0},
			OneValTimeSpec{14},
			WildcardTimeSpec{},
			WildcardTimeSpec{},
			WildcardTimeSpec{}}},
		{"0 0 14 * * 1", FullTimeSpec{
		    OneValTimeSpec{0},
			OneValTimeSpec{0},
			OneValTimeSpec{14},
			WildcardTimeSpec{},
			WildcardTimeSpec{},
			OneValTimeSpec{1}}},
		{"0 0 */2 * * 1", FullTimeSpec{
		    OneValTimeSpec{0},
			OneValTimeSpec{0},
			SetTimeSpec{"*/2", evens},
			WildcardTimeSpec{},
			WildcardTimeSpec{},
			OneValTimeSpec{1}}},
		{"0 0 1,4,7,10,13,16,19,22 * * 1", FullTimeSpec{
		    OneValTimeSpec{0},
			OneValTimeSpec{0},
			SetTimeSpec{"1,4,7,10,13,16,19,22", threes},
			WildcardTimeSpec{},
			WildcardTimeSpec{},
			OneValTimeSpec{1}}},
		{"10,20 0 14 1 8 0-5", FullTimeSpec{
    		SetTimeSpec{"10,20", []int{10,20}},
			OneValTimeSpec{0},
			OneValTimeSpec{14},
			OneValTimeSpec{1},
			OneValTimeSpec{8},
			SetTimeSpec{"0-5", []int{0,1,2,3,4,5}}}},
	}

	for _, c := range cases {
		/*
		 * Call
		 */
		var result *FullTimeSpec
		var err error
		result, err = ParseFullTimeSpec(c.str)

		/*
		 * Test
		 */
		if err != nil {
			t.Fatalf("Got error: %v", err)
		}
		require.Equal(t, c.spec, *result)
	}
}

func TestReadNewJobberFile(t *testing.T) {
	/*
	 * Set up
	 */
	buf := bytes.NewBufferString(NewJobFileEx)

	/*
	 * Call
	 */
	var file *JobberFile
	file, err := readJobberFile(buf, UsernameEx)

	/*
	 * Test
	 */
	if err != nil {
		t.Fatalf("Got error: %v", err)
	}
	if file == nil {
		t.Fatalf("jobs == nil")
	}

	// test prefs
	require.NotNil(t, file.Prefs.Notifier)

	// test jobs
	require.Equal(t, 2, len(file.Jobs))

	// test DailyBackup
	daily := file.Jobs[0]
	require.Equal(t, "DailyBackup", daily.Name)
	require.Equal(t, "backup daily", daily.Cmd)
	require.Equal(t, &ErrorHandlerStop, daily.ErrorHandler)
	require.Equal(t, false, daily.NotifyOnError)
	require.Equal(t, true, daily.NotifyOnFailure)

	// test WeeklyBackup
	weekly := file.Jobs[1]
	require.Equal(t, "WeeklyBackup", weekly.Name)
	require.Equal(t, `multi-
line
script
`, weekly.Cmd)
	require.Equal(t, &ErrorHandlerBackoff, weekly.ErrorHandler)
	require.Equal(t, true, weekly.NotifyOnError)
	require.Equal(t, false, weekly.NotifyOnFailure)
}

func TestReadLegacyJobberFile(t *testing.T) {
	/*
	 * Set up
	 */
	buf := bytes.NewBufferString(LegacyJobFileEx)

	/*
	 * Call
	 */
	var file *JobberFile
	file, err := readJobberFile(buf, UsernameEx)

	/*
	 * Test
	 */
	if err != nil {
		t.Fatalf("Got error: %v", err)
	}
	if file == nil {
		t.Fatalf("jobs == nil")
	}
	require.Equal(t, 4, len(file.Jobs))

	// test DailyBackup
	daily := file.Jobs[0]
	require.Equal(t, "DailyBackup", daily.Name)
	require.Equal(t, "backup daily", daily.Cmd)
	require.Equal(t, &ErrorHandlerStop, daily.ErrorHandler)
	require.Equal(t, false, daily.NotifyOnError)
	require.Equal(t, true, daily.NotifyOnFailure)

	// test WeeklyBackup
	weekly := file.Jobs[1]
	require.Equal(t, "WeeklyBackup", weekly.Name)
	require.Equal(t, `multi-
line
script
`, weekly.Cmd)
	require.Equal(t, &ErrorHandlerBackoff, weekly.ErrorHandler)
	require.Equal(t, true, weekly.NotifyOnError)
	require.Equal(t, false, weekly.NotifyOnFailure)

	// test JobA
	jobA := file.Jobs[2]
	require.Equal(t, "JobA", jobA.Name)
	require.Equal(t, EverySecTimeSpec, jobA.FullTimeSpec)

	// test JobB
	jobB := file.Jobs[3]
	require.Equal(t, "JobB", jobB.Name)
	require.Equal(t, EverySecTimeSpec, jobB.FullTimeSpec)
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The srv package provides definitions and functions used to implement
// a 9P2000 file client.
package clnt

import (
	"fmt"
	"log"
	"net"
	"sync"
	"syscall"
	"go9p.googlecode.com/hg/p"
)

// Debug flags
const (
	DbgPrintFcalls  = (1 << iota) // print all 9P messages on stderr
	DbgPrintPackets               // print the raw packets on stderr
	DbgLogFcalls                  // keep the last N 9P messages (can be accessed over http)
	DbgLogPackets                 // keep the last N 9P messages (can be accessed over http)
)

type StatsOps interface {
	statsRegister()
	statsUnregister()
}

// The Clnt type represents a 9P2000 client. The client is connected to
// a 9P2000 file server and its methods can be used to access and manipulate
// the files exported by the server.
type Clnt struct {
	sync.Mutex
	Debuglevel int    // =0 don't print anything, >0 print Fcalls, >1 print raw packets
	Msize      uint32 // Maximum size of the 9P messages
	Dotu       bool   // If true, 9P2000.u protocol is spoken
	Root       *Fid   // Fid that points to the rood directory
	Id         string // Used when printing debug messages
	Log        *p.Logger

	conn     net.Conn
	tagpool  *pool
	fidpool  *pool
	reqout   chan *Req
	done     chan bool
	reqfirst *Req
	reqlast  *Req
	err      *p.Error

	reqchan chan *Req
	tchan   chan *p.Fcall

	next, prev *Clnt
}

// A Fid type represents a file on the server. Fids are used for the
// low level methods that correspond directly to the 9P2000 message requests
type Fid struct {
	sync.Mutex
	Clnt   *Clnt // Client the fid belongs to
	Iounit uint32
	p.Qid         // The Qid description for the file
	Mode   uint8  // Open mode (one of p.O* values) (if file is open)
	Fid    uint32 // Fid number
	p.User        // The user the fid belongs to
	walked bool   // true if the fid points to a walked file on the server
}

// The file is similar to the Fid, but is used in the high-level client
// interface.
type File struct {
	fid    *Fid
	offset uint64
}

type pool struct {
	sync.Mutex
	need  int
	nchan chan uint32
	maxid uint32
	imap  []byte
}

type Req struct {
	sync.Mutex
	Clnt       *Clnt
	Tc         *p.Fcall
	Rc         *p.Fcall
	Err        *p.Error
	Done       chan *Req
	tag        uint16
	prev, next *Req
	fid        *Fid
}

type ClntList struct {
	sync.Mutex
	clntList, clntLast *Clnt
}

var clnts *ClntList
var DefaultDebuglevel int
var DefaultLogger *p.Logger

func (clnt *Clnt) Rpcnb(r *Req) *p.Error {
	var tag uint16

	if r.Tc.Type == p.Tversion {
		tag = p.NOTAG
	} else {
		tag = r.tag
	}

	p.SetTag(r.Tc, tag)
	clnt.Lock()
	if clnt.err != nil {
		clnt.Unlock()
		return clnt.err
	}

	if clnt.reqlast != nil {
		clnt.reqlast.next = r
	} else {
		clnt.reqfirst = r
	}

	r.prev = clnt.reqlast
	clnt.reqlast = r
	clnt.Unlock()

	clnt.reqout <- r
	return nil
}

func (clnt *Clnt) Rpc(tc *p.Fcall) (rc *p.Fcall, err *p.Error) {
	r := clnt.ReqAlloc()
	r.Tc = tc
	r.Done = make(chan *Req)
	err = clnt.Rpcnb(r)
	if err != nil {
		return
	}

	<-r.Done
	rc = r.Rc
	err = r.Err
	clnt.ReqFree(r)
	return
}

func (clnt *Clnt) recv() {
	var err *p.Error

	err = nil
	buf := make([]byte, clnt.Msize*8)
	pos := 0
	for {
		if len(buf) < int(clnt.Msize) {
		resize:
			b := make([]byte, clnt.Msize*8)
			copy(b, buf[0:pos])
			buf = b
			b = nil
		}

		n, oerr := clnt.conn.Read(buf[pos:len(buf)])
		if oerr != nil || n == 0 {
			err = &p.Error{oerr.String(), syscall.EIO}
			goto closed
		}

		pos += n
		for pos > 4 {
			sz, _ := p.Gint32(buf)
			if pos < int(sz) {
				if len(buf) < int(sz) {
					goto resize
				}

				break
			}

			fc, err, fcsize := p.Unpack(buf, clnt.Dotu)
			clnt.Lock()
			if err != nil {
				clnt.err = err
				clnt.conn.Close()
				clnt.Unlock()
				goto closed
			}

			if clnt.Debuglevel > 0 {
				clnt.logFcall(fc)
				if clnt.Debuglevel&DbgPrintPackets != 0 {
					log.Println("}-}", clnt.Id, fmt.Sprint(fc.Pkt))
				}

				if clnt.Debuglevel&DbgPrintFcalls != 0 {
					log.Println("}}}", clnt.Id, fc.String())
				}
			}

			var r *Req = nil
			for r = clnt.reqfirst; r != nil; r = r.next {
				if r.Tc.Tag == fc.Tag {
					break
				}
			}

			if r == nil {
				clnt.err = &p.Error{"unexpected response", syscall.EINVAL}
				clnt.conn.Close()
				clnt.Unlock()
				goto closed
			}

			r.Rc = fc
			if r.prev != nil {
				r.prev.next = r.next
			} else {
				clnt.reqfirst = r.next
			}

			if r.next != nil {
				r.next.prev = r.prev
			} else {
				clnt.reqlast = r.prev
			}
			clnt.Unlock()

			if r.Tc.Type != r.Rc.Type-1 {
				if r.Rc.Type != p.Rerror {
					r.Err = &p.Error{"invalid response", syscall.EINVAL}
					log.Println(fmt.Sprintf("TTT %v", r.Tc))
					log.Println(fmt.Sprintf("RRR %v", r.Rc))
				} else {
					if r.Err == nil {
						r.Err = &p.Error{r.Rc.Error, int(r.Rc.Errornum)}
					}
				}
			}

			if r.Done != nil {
				r.Done <- r
			}

			pos -= fcsize
			buf = buf[fcsize:]
		}
	}

closed:
	clnt.done <- true

	/* send error to all pending requests */
	clnt.Lock()
	r := clnt.reqfirst
	clnt.reqfirst = nil
	clnt.reqlast = nil
	if err == nil {
		err = clnt.err
	}
	clnt.Unlock()
	for ; r != nil; r = r.next {
		r.Err = err
		if r.Done != nil {
			r.Done <- r
		}
	}

	clnts.Lock()
	if clnt.prev != nil {
		clnt.prev.next = clnt.next
	} else {
		clnts.clntList = clnt.next
	}

	if clnt.next != nil {
		clnt.next.prev = clnt.prev
	} else {
		clnts.clntLast = clnt.prev
	}
	clnts.Unlock()

	if sop, ok := (interface{}(clnt)).(StatsOps); ok {
		sop.statsUnregister()
	}
}

func (clnt *Clnt) send() {
	for {
		select {
		case <-clnt.done:
			return

		case req := <-clnt.reqout:
			if clnt.Debuglevel > 0 {
				clnt.logFcall(req.Tc)
				if clnt.Debuglevel&DbgPrintPackets != 0 {
					log.Println("{-{", clnt.Id, fmt.Sprint(req.Tc.Pkt))
				}

				if clnt.Debuglevel&DbgPrintFcalls != 0 {
					log.Println("{{{", clnt.Id, req.Tc.String())
				}
			}

			for buf := req.Tc.Pkt; len(buf) > 0; {
				n, err := clnt.conn.Write(buf)
				if err != nil {
					/* just close the socket, will get signal on clnt.done */
					clnt.conn.Close()
					break
				}

				buf = buf[n:len(buf)]
			}
		}
	}
}

// Creates and initializes a new Clnt object. Doesn't send any data
// on the wire.
func NewClnt(c net.Conn, msize uint32, dotu bool) *Clnt {
	clnt := new(Clnt)
	clnt.conn = c
	clnt.Msize = msize
	clnt.Dotu = dotu
	clnt.Debuglevel = DefaultDebuglevel
	clnt.Log = DefaultLogger
	clnt.tagpool = newPool(uint32(p.NOTAG))
	clnt.fidpool = newPool(p.NOFID)
	clnt.reqout = make(chan *Req)
	clnt.done = make(chan bool)
	clnt.reqchan = make(chan *Req, 16)
	clnt.tchan = make(chan *p.Fcall, 16)

	go clnt.recv()
	go clnt.send()

	clnts.Lock()
	if clnts.clntLast != nil {
		clnts.clntLast.next = clnt
	} else {
		clnts.clntList = clnt
	}

	clnt.prev = clnts.clntLast
	clnts.clntLast = clnt
	clnts.Unlock()

	if sop, ok := (interface{}(clnt)).(StatsOps); ok {
		sop.statsRegister()
	}

	return clnt
}

// Establishes a new socket connection to the 9P server and creates
// a client object for it. Negotiates the dialect and msize for the
// connection. Returns a Clnt object, or Error.
func Connect(c net.Conn, msize uint32, dotu bool) (*Clnt, *p.Error) {
	clnt := NewClnt(c, msize, dotu)
	clnt.Id = c.RemoteAddr().String() + ":"
	ver := "9P2000"
	if clnt.Dotu {
		ver = "9P2000.u"
	}

	tc := p.NewFcall(clnt.Msize)
	err := p.PackTversion(tc, clnt.Msize, ver)
	if err != nil {
		return nil, err
	}

	rc, err := clnt.Rpc(tc)
	if err != nil {
		return nil, err
	}

	if rc.Msize < clnt.Msize {
		clnt.Msize = rc.Msize
	}

	clnt.Dotu = rc.Version == "9P2000.u" && clnt.Dotu
	return clnt, nil
}

// Creates a new Fid object for the client
func (clnt *Clnt) FidAlloc() *Fid {
	fid := new(Fid)
	fid.Fid = clnt.fidpool.getId()
	fid.Clnt = clnt

	return fid
}

func (clnt *Clnt) NewFcall() *p.Fcall {
	select {
	case tc := <-clnt.tchan:
		return tc
	default:
	}
	return p.NewFcall(clnt.Msize)
}

func (clnt *Clnt) FreeFcall(fc *p.Fcall) {
	if fc != nil && len(fc.Buf) >= int(clnt.Msize) {
		select {
		case clnt.tchan <- fc:
			break
		default:
		}
	}
}

func (clnt *Clnt) ReqAlloc() *Req {
	var req *Req
	select {
	case req = <-clnt.reqchan:
		break
	default:
		req = new(Req)
		req.Clnt = clnt
		req.tag = uint16(clnt.tagpool.getId())
	}
	return req
}

func (clnt *Clnt) ReqFree(req *Req) {
	clnt.FreeFcall(req.Tc)
	req.Tc = nil
	req.Rc = nil
	req.Err = nil
	req.Done = nil
	req.next = nil
	req.prev = nil

	select {
	case clnt.reqchan <- req:
		break
	default:
		clnt.tagpool.putId(uint32(req.tag))
	}
}

func (clnt *Clnt) logFcall(fc *p.Fcall) {
	if clnt.Debuglevel&DbgLogPackets != 0 {
		pkt := make([]byte, len(fc.Pkt))
		copy(pkt, fc.Pkt)
		clnt.Log.Log(pkt, clnt, DbgLogPackets)
	}

	if clnt.Debuglevel&DbgLogFcalls != 0 {
		f := new(p.Fcall)
		*f = *fc
		f.Pkt = nil
		clnt.Log.Log(f, clnt, DbgLogFcalls)
	}
}

func init() {
	clnts = new(ClntList)
	if sop, ok := (interface{}(clnts)).(StatsOps); ok {
		sop.statsRegister()
	}
}
<commit_msg>fix issue #14<commit_after>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The srv package provides definitions and functions used to implement
// a 9P2000 file client.
package clnt

import (
	"fmt"
	"log"
	"net"
	"sync"
	"syscall"
	"go9p.googlecode.com/hg/p"
)

// Debug flags
const (
	DbgPrintFcalls  = (1 << iota) // print all 9P messages on stderr
	DbgPrintPackets               // print the raw packets on stderr
	DbgLogFcalls                  // keep the last N 9P messages (can be accessed over http)
	DbgLogPackets                 // keep the last N 9P messages (can be accessed over http)
)

type StatsOps interface {
	statsRegister()
	statsUnregister()
}

// The Clnt type represents a 9P2000 client. The client is connected to
// a 9P2000 file server and its methods can be used to access and manipulate
// the files exported by the server.
type Clnt struct {
	sync.Mutex
	Debuglevel int    // =0 don't print anything, >0 print Fcalls, >1 print raw packets
	Msize      uint32 // Maximum size of the 9P messages
	Dotu       bool   // If true, 9P2000.u protocol is spoken
	Root       *Fid   // Fid that points to the rood directory
	Id         string // Used when printing debug messages
	Log        *p.Logger

	conn     net.Conn
	tagpool  *pool
	fidpool  *pool
	reqout   chan *Req
	done     chan bool
	reqfirst *Req
	reqlast  *Req
	err      *p.Error

	reqchan chan *Req
	tchan   chan *p.Fcall

	next, prev *Clnt
}

// A Fid type represents a file on the server. Fids are used for the
// low level methods that correspond directly to the 9P2000 message requests
type Fid struct {
	sync.Mutex
	Clnt   *Clnt // Client the fid belongs to
	Iounit uint32
	p.Qid         // The Qid description for the file
	Mode   uint8  // Open mode (one of p.O* values) (if file is open)
	Fid    uint32 // Fid number
	p.User        // The user the fid belongs to
	walked bool   // true if the fid points to a walked file on the server
}

// The file is similar to the Fid, but is used in the high-level client
// interface.
type File struct {
	fid    *Fid
	offset uint64
}

type pool struct {
	sync.Mutex
	need  int
	nchan chan uint32
	maxid uint32
	imap  []byte
}

type Req struct {
	sync.Mutex
	Clnt       *Clnt
	Tc         *p.Fcall
	Rc         *p.Fcall
	Err        *p.Error
	Done       chan *Req
	tag        uint16
	prev, next *Req
	fid        *Fid
}

type ClntList struct {
	sync.Mutex
	clntList, clntLast *Clnt
}

var clnts *ClntList
var DefaultDebuglevel int
var DefaultLogger *p.Logger

func (clnt *Clnt) Rpcnb(r *Req) *p.Error {
	var tag uint16

	if r.Tc.Type == p.Tversion {
		tag = p.NOTAG
	} else {
		tag = r.tag
	}

	p.SetTag(r.Tc, tag)
	clnt.Lock()
	if clnt.err != nil {
		clnt.Unlock()
		return clnt.err
	}

	if clnt.reqlast != nil {
		clnt.reqlast.next = r
	} else {
		clnt.reqfirst = r
	}

	r.prev = clnt.reqlast
	clnt.reqlast = r
	clnt.Unlock()

	clnt.reqout <- r
	return nil
}

func (clnt *Clnt) Rpc(tc *p.Fcall) (rc *p.Fcall, err *p.Error) {
	r := clnt.ReqAlloc()
	r.Tc = tc
	r.Done = make(chan *Req)
	err = clnt.Rpcnb(r)
	if err != nil {
		return
	}

	<-r.Done
	rc = r.Rc
	err = r.Err
	clnt.ReqFree(r)
	return
}

func (clnt *Clnt) recv() {
	var err *p.Error

	err = nil
	buf := make([]byte, clnt.Msize*8)
	pos := 0
	for {
		if len(buf) < int(clnt.Msize) {
		resize:
			b := make([]byte, clnt.Msize*8)
			copy(b, buf[0:pos])
			buf = b
			b = nil
		}

		n, oerr := clnt.conn.Read(buf[pos:len(buf)])
		if oerr != nil || n == 0 {
			err = &p.Error{oerr.String(), syscall.EIO}
			clnt.Lock()
			clnt.err = err
			clnt.Unlock()
			goto closed
		}

		pos += n
		for pos > 4 {
			sz, _ := p.Gint32(buf)
			if pos < int(sz) {
				if len(buf) < int(sz) {
					goto resize
				}

				break
			}

			fc, err, fcsize := p.Unpack(buf, clnt.Dotu)
			clnt.Lock()
			if err != nil {
				clnt.err = err
				clnt.conn.Close()
				clnt.Unlock()
				goto closed
			}

			if clnt.Debuglevel > 0 {
				clnt.logFcall(fc)
				if clnt.Debuglevel&DbgPrintPackets != 0 {
					log.Println("}-}", clnt.Id, fmt.Sprint(fc.Pkt))
				}

				if clnt.Debuglevel&DbgPrintFcalls != 0 {
					log.Println("}}}", clnt.Id, fc.String())
				}
			}

			var r *Req = nil
			for r = clnt.reqfirst; r != nil; r = r.next {
				if r.Tc.Tag == fc.Tag {
					break
				}
			}

			if r == nil {
				clnt.err = &p.Error{"unexpected response", syscall.EINVAL}
				clnt.conn.Close()
				clnt.Unlock()
				goto closed
			}

			r.Rc = fc
			if r.prev != nil {
				r.prev.next = r.next
			} else {
				clnt.reqfirst = r.next
			}

			if r.next != nil {
				r.next.prev = r.prev
			} else {
				clnt.reqlast = r.prev
			}
			clnt.Unlock()

			if r.Tc.Type != r.Rc.Type-1 {
				if r.Rc.Type != p.Rerror {
					r.Err = &p.Error{"invalid response", syscall.EINVAL}
					log.Println(fmt.Sprintf("TTT %v", r.Tc))
					log.Println(fmt.Sprintf("RRR %v", r.Rc))
				} else {
					if r.Err == nil {
						r.Err = &p.Error{r.Rc.Error, int(r.Rc.Errornum)}
					}
				}
			}

			if r.Done != nil {
				r.Done <- r
			}

			pos -= fcsize
			buf = buf[fcsize:]
		}
	}

closed:
	clnt.done <- true

	/* send error to all pending requests */
	clnt.Lock()
	r := clnt.reqfirst
	clnt.reqfirst = nil
	clnt.reqlast = nil
	if err == nil {
		err = clnt.err
	}
	clnt.Unlock()
	for ; r != nil; r = r.next {
		r.Err = err
		if r.Done != nil {
			r.Done <- r
		}
	}

	clnts.Lock()
	if clnt.prev != nil {
		clnt.prev.next = clnt.next
	} else {
		clnts.clntList = clnt.next
	}

	if clnt.next != nil {
		clnt.next.prev = clnt.prev
	} else {
		clnts.clntLast = clnt.prev
	}
	clnts.Unlock()

	if sop, ok := (interface{}(clnt)).(StatsOps); ok {
		sop.statsUnregister()
	}
}

func (clnt *Clnt) send() {
	for {
		select {
		case <-clnt.done:
			return

		case req := <-clnt.reqout:
			if clnt.Debuglevel > 0 {
				clnt.logFcall(req.Tc)
				if clnt.Debuglevel&DbgPrintPackets != 0 {
					log.Println("{-{", clnt.Id, fmt.Sprint(req.Tc.Pkt))
				}

				if clnt.Debuglevel&DbgPrintFcalls != 0 {
					log.Println("{{{", clnt.Id, req.Tc.String())
				}
			}

			for buf := req.Tc.Pkt; len(buf) > 0; {
				n, err := clnt.conn.Write(buf)
				if err != nil {
					/* just close the socket, will get signal on clnt.done */
					clnt.conn.Close()
					break
				}

				buf = buf[n:len(buf)]
			}
		}
	}
}

// Creates and initializes a new Clnt object. Doesn't send any data
// on the wire.
func NewClnt(c net.Conn, msize uint32, dotu bool) *Clnt {
	clnt := new(Clnt)
	clnt.conn = c
	clnt.Msize = msize
	clnt.Dotu = dotu
	clnt.Debuglevel = DefaultDebuglevel
	clnt.Log = DefaultLogger
	clnt.tagpool = newPool(uint32(p.NOTAG))
	clnt.fidpool = newPool(p.NOFID)
	clnt.reqout = make(chan *Req)
	clnt.done = make(chan bool)
	clnt.reqchan = make(chan *Req, 16)
	clnt.tchan = make(chan *p.Fcall, 16)

	go clnt.recv()
	go clnt.send()

	clnts.Lock()
	if clnts.clntLast != nil {
		clnts.clntLast.next = clnt
	} else {
		clnts.clntList = clnt
	}

	clnt.prev = clnts.clntLast
	clnts.clntLast = clnt
	clnts.Unlock()

	if sop, ok := (interface{}(clnt)).(StatsOps); ok {
		sop.statsRegister()
	}

	return clnt
}

// Establishes a new socket connection to the 9P server and creates
// a client object for it. Negotiates the dialect and msize for the
// connection. Returns a Clnt object, or Error.
func Connect(c net.Conn, msize uint32, dotu bool) (*Clnt, *p.Error) {
	clnt := NewClnt(c, msize, dotu)
	clnt.Id = c.RemoteAddr().String() + ":"
	ver := "9P2000"
	if clnt.Dotu {
		ver = "9P2000.u"
	}

	tc := p.NewFcall(clnt.Msize)
	err := p.PackTversion(tc, clnt.Msize, ver)
	if err != nil {
		return nil, err
	}

	rc, err := clnt.Rpc(tc)
	if err != nil {
		return nil, err
	}

	if rc.Msize < clnt.Msize {
		clnt.Msize = rc.Msize
	}

	clnt.Dotu = rc.Version == "9P2000.u" && clnt.Dotu
	return clnt, nil
}

// Creates a new Fid object for the client
func (clnt *Clnt) FidAlloc() *Fid {
	fid := new(Fid)
	fid.Fid = clnt.fidpool.getId()
	fid.Clnt = clnt

	return fid
}

func (clnt *Clnt) NewFcall() *p.Fcall {
	select {
	case tc := <-clnt.tchan:
		return tc
	default:
	}
	return p.NewFcall(clnt.Msize)
}

func (clnt *Clnt) FreeFcall(fc *p.Fcall) {
	if fc != nil && len(fc.Buf) >= int(clnt.Msize) {
		select {
		case clnt.tchan <- fc:
			break
		default:
		}
	}
}

func (clnt *Clnt) ReqAlloc() *Req {
	var req *Req
	select {
	case req = <-clnt.reqchan:
		break
	default:
		req = new(Req)
		req.Clnt = clnt
		req.tag = uint16(clnt.tagpool.getId())
	}
	return req
}

func (clnt *Clnt) ReqFree(req *Req) {
	clnt.FreeFcall(req.Tc)
	req.Tc = nil
	req.Rc = nil
	req.Err = nil
	req.Done = nil
	req.next = nil
	req.prev = nil

	select {
	case clnt.reqchan <- req:
		break
	default:
		clnt.tagpool.putId(uint32(req.tag))
	}
}

func (clnt *Clnt) logFcall(fc *p.Fcall) {
	if clnt.Debuglevel&DbgLogPackets != 0 {
		pkt := make([]byte, len(fc.Pkt))
		copy(pkt, fc.Pkt)
		clnt.Log.Log(pkt, clnt, DbgLogPackets)
	}

	if clnt.Debuglevel&DbgLogFcalls != 0 {
		f := new(p.Fcall)
		*f = *fc
		f.Pkt = nil
		clnt.Log.Log(f, clnt, DbgLogFcalls)
	}
}

func init() {
	clnts = new(ClntList)
	if sop, ok := (interface{}(clnts)).(StatsOps); ok {
		sop.statsRegister()
	}
}
<|endoftext|>