<commit_before>// Copyright 2019 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.

// Package nettest provides utilities for network testing.
package nettest

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	stackOnce          sync.Once
	ipv4Enabled        bool
	ipv6Enabled        bool
	unStrmDgramEnabled bool
	rawSocketSess      bool

	aLongTimeAgo = time.Unix(233431200, 0)
	neverTimeout = time.Time{}

	errNoAvailableInterface = errors.New("no available interface")
	errNoAvailableAddress   = errors.New("no available address")
)

func probeStack() {
	if ln, err := net.Listen("tcp4", "127.0.0.1:0"); err == nil {
		ln.Close()
		ipv4Enabled = true
	}
	if ln, err := net.Listen("tcp6", "[::1]:0"); err == nil {
		ln.Close()
		ipv6Enabled = true
	}
	rawSocketSess = supportsRawSocket()
	switch runtime.GOOS {
	case "aix":
		// Unix network isn't properly working on AIX 7.2 with
		// Technical Level < 2.
		out, _ := exec.Command("oslevel", "-s").Output()
		if len(out) >= len("7200-XX-ZZ-YYMM") { // AIX 7.2, Tech Level XX, Service Pack ZZ, date YYMM
			ver := string(out[:4])
			tl, _ := strconv.Atoi(string(out[5:7]))
			unStrmDgramEnabled = ver > "7200" || (ver == "7200" && tl >= 2)
		}
	default:
		unStrmDgramEnabled = true
	}
}

func unixStrmDgramEnabled() bool {
	stackOnce.Do(probeStack)
	return unStrmDgramEnabled
}

// SupportsIPv4 reports whether the platform supports IPv4 networking
// functionality.
func SupportsIPv4() bool {
	stackOnce.Do(probeStack)
	return ipv4Enabled
}

// SupportsIPv6 reports whether the platform supports IPv6 networking
// functionality.
func SupportsIPv6() bool {
	stackOnce.Do(probeStack)
	return ipv6Enabled
}

// SupportsRawSocket reports whether the current session is available
// to use raw sockets.
func SupportsRawSocket() bool {
	stackOnce.Do(probeStack)
	return rawSocketSess
}

// TestableNetwork reports whether network is testable on the current
// platform configuration.
//
// See func Dial of the standard library for the supported networks.
func TestableNetwork(network string) bool {
	ss := strings.Split(network, ":")
	switch ss[0] {
	case "ip+nopriv":
		// This is an internal network name for testing on the
		// package net of the standard library.
		switch runtime.GOOS {
		case "android", "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
			return false
		case "darwin", "ios":
			// iOS doesn't support it.
			if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
				return false
			}
		}
	case "ip", "ip4", "ip6":
		switch runtime.GOOS {
		case "fuchsia", "hurd", "js", "nacl", "plan9":
			return false
		default:
			if os.Getuid() != 0 {
				return false
			}
		}
	case "unix", "unixgram":
		switch runtime.GOOS {
		case "android", "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
			return false
		case "aix":
			return unixStrmDgramEnabled()
		case "darwin", "ios":
			// iOS does not support unix, unixgram.
			if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
				return false
			}
		}
	case "unixpacket":
		switch runtime.GOOS {
		case "aix", "android", "fuchsia", "hurd", "darwin", "ios", "js", "nacl", "plan9", "windows", "zos":
			return false
		case "netbsd":
			// It passes on amd64 at least. 386 fails
			// (Issue 22927). arm is unknown.
			if runtime.GOARCH == "386" {
				return false
			}
		}
	}
	switch ss[0] {
	case "tcp4", "udp4", "ip4":
		return SupportsIPv4()
	case "tcp6", "udp6", "ip6":
		return SupportsIPv6()
	}
	return true
}

// TestableAddress reports whether address of network is testable on
// the current platform configuration.
func TestableAddress(network, address string) bool {
	switch ss := strings.Split(network, ":"); ss[0] {
	case "unix", "unixgram", "unixpacket":
		// Abstract unix domain sockets, a Linux-ism.
		if address[0] == '@' && runtime.GOOS != "linux" {
			return false
		}
	}
	return true
}

// NewLocalListener returns a listener which listens to a loopback IP
// address or local file system path.
//
// The provided network must be "tcp", "tcp4", "tcp6", "unix" or
// "unixpacket".
func NewLocalListener(network string) (net.Listener, error) {
	switch network {
	case "tcp":
		if SupportsIPv4() {
			if ln, err := net.Listen("tcp4", "127.0.0.1:0"); err == nil {
				return ln, nil
			}
		}
		if SupportsIPv6() {
			return net.Listen("tcp6", "[::1]:0")
		}
	case "tcp4":
		if SupportsIPv4() {
			return net.Listen("tcp4", "127.0.0.1:0")
		}
	case "tcp6":
		if SupportsIPv6() {
			return net.Listen("tcp6", "[::1]:0")
		}
	case "unix", "unixpacket":
		path, err := LocalPath()
		if err != nil {
			return nil, err
		}
		return net.Listen(network, path)
	}
	return nil, fmt.Errorf("%s is not supported on %s/%s", network, runtime.GOOS, runtime.GOARCH)
}

// NewLocalPacketListener returns a packet listener which listens to a
// loopback IP address or local file system path.
//
// The provided network must be "udp", "udp4", "udp6" or "unixgram".
func NewLocalPacketListener(network string) (net.PacketConn, error) {
	switch network {
	case "udp":
		if SupportsIPv4() {
			if c, err := net.ListenPacket("udp4", "127.0.0.1:0"); err == nil {
				return c, nil
			}
		}
		if SupportsIPv6() {
			return net.ListenPacket("udp6", "[::1]:0")
		}
	case "udp4":
		if SupportsIPv4() {
			return net.ListenPacket("udp4", "127.0.0.1:0")
		}
	case "udp6":
		if SupportsIPv6() {
			return net.ListenPacket("udp6", "[::1]:0")
		}
	case "unixgram":
		path, err := LocalPath()
		if err != nil {
			return nil, err
		}
		return net.ListenPacket(network, path)
	}
	return nil, fmt.Errorf("%s is not supported on %s/%s", network, runtime.GOOS, runtime.GOARCH)
}

// LocalPath returns a local path that can be used for Unix-domain
// protocol testing.
func LocalPath() (string, error) {
	f, err := ioutil.TempFile("", "go-nettest")
	if err != nil {
		return "", err
	}
	path := f.Name()
	f.Close()
	os.Remove(path)
	return path, nil
}

// MulticastSource returns a unicast IP address on ifi when ifi is an
// IP multicast-capable network interface.
//
// The provided network must be "ip", "ip4" or "ip6".
func MulticastSource(network string, ifi *net.Interface) (net.IP, error) {
	switch network {
	case "ip", "ip4", "ip6":
	default:
		return nil, errNoAvailableAddress
	}
	if ifi == nil || ifi.Flags&net.FlagUp == 0 || ifi.Flags&net.FlagMulticast == 0 {
		return nil, errNoAvailableAddress
	}
	ip, ok := hasRoutableIP(network, ifi)
	if !ok {
		return nil, errNoAvailableAddress
	}
	return ip, nil
}

// LoopbackInterface returns an available logical network interface
// for loopback test.
func LoopbackInterface() (*net.Interface, error) {
	ift, err := net.Interfaces()
	if err != nil {
		return nil, errNoAvailableInterface
	}
	for _, ifi := range ift {
		if ifi.Flags&net.FlagLoopback != 0 && ifi.Flags&net.FlagUp != 0 {
			return &ifi, nil
		}
	}
	return nil, errNoAvailableInterface
}

// RoutedInterface returns a network interface that can route IP
// traffic and satisfies flags.
//
// The provided network must be "ip", "ip4" or "ip6".
func RoutedInterface(network string, flags net.Flags) (*net.Interface, error) {
	switch network {
	case "ip", "ip4", "ip6":
	default:
		return nil, errNoAvailableInterface
	}
	ift, err := net.Interfaces()
	if err != nil {
		return nil, errNoAvailableInterface
	}
	for _, ifi := range ift {
		if ifi.Flags&flags != flags {
			continue
		}
		if _, ok := hasRoutableIP(network, &ifi); !ok {
			continue
		}
		return &ifi, nil
	}
	return nil, errNoAvailableInterface
}

func hasRoutableIP(network string, ifi *net.Interface) (net.IP, bool) {
	ifat, err := ifi.Addrs()
	if err != nil {
		return nil, false
	}
	for _, ifa := range ifat {
		switch ifa := ifa.(type) {
		case *net.IPAddr:
			if ip, ok := routableIP(network, ifa.IP); ok {
				return ip, true
			}
		case *net.IPNet:
			if ip, ok := routableIP(network, ifa.IP); ok {
				return ip, true
			}
		}
	}
	return nil, false
}

func routableIP(network string, ip net.IP) (net.IP, bool) {
	if !ip.IsLoopback() && !ip.IsLinkLocalUnicast() && !ip.IsGlobalUnicast() {
		return nil, false
	}
	switch network {
	case "ip4":
		if ip := ip.To4(); ip != nil {
			return ip, true
		}
	case "ip6":
		if ip.IsLoopback() { // addressing scope of the loopback address depends on each implementation
			return nil, false
		}
		if ip := ip.To16(); ip != nil && ip.To4() == nil {
			return ip, true
		}
	default:
		if ip := ip.To4(); ip != nil {
			return ip, true
		}
		if ip := ip.To16(); ip != nil {
			return ip, true
		}
	}
	return nil, false
}
<commit_msg>nettest: simplify iOS detection in TestableNetwork<commit_after>// Copyright 2019 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.

// Package nettest provides utilities for network testing.
package nettest

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	stackOnce          sync.Once
	ipv4Enabled        bool
	ipv6Enabled        bool
	unStrmDgramEnabled bool
	rawSocketSess      bool

	aLongTimeAgo = time.Unix(233431200, 0)
	neverTimeout = time.Time{}

	errNoAvailableInterface = errors.New("no available interface")
	errNoAvailableAddress   = errors.New("no available address")
)

func probeStack() {
	if ln, err := net.Listen("tcp4", "127.0.0.1:0"); err == nil {
		ln.Close()
		ipv4Enabled = true
	}
	if ln, err := net.Listen("tcp6", "[::1]:0"); err == nil {
		ln.Close()
		ipv6Enabled = true
	}
	rawSocketSess = supportsRawSocket()
	switch runtime.GOOS {
	case "aix":
		// Unix network isn't properly working on AIX 7.2 with
		// Technical Level < 2.
		out, _ := exec.Command("oslevel", "-s").Output()
		if len(out) >= len("7200-XX-ZZ-YYMM") { // AIX 7.2, Tech Level XX, Service Pack ZZ, date YYMM
			ver := string(out[:4])
			tl, _ := strconv.Atoi(string(out[5:7]))
			unStrmDgramEnabled = ver > "7200" || (ver == "7200" && tl >= 2)
		}
	default:
		unStrmDgramEnabled = true
	}
}

func unixStrmDgramEnabled() bool {
	stackOnce.Do(probeStack)
	return unStrmDgramEnabled
}

// SupportsIPv4 reports whether the platform supports IPv4 networking
// functionality.
func SupportsIPv4() bool {
	stackOnce.Do(probeStack)
	return ipv4Enabled
}

// SupportsIPv6 reports whether the platform supports IPv6 networking
// functionality.
func SupportsIPv6() bool {
	stackOnce.Do(probeStack)
	return ipv6Enabled
}

// SupportsRawSocket reports whether the current session is available
// to use raw sockets.
func SupportsRawSocket() bool {
	stackOnce.Do(probeStack)
	return rawSocketSess
}

// TestableNetwork reports whether network is testable on the current
// platform configuration.
//
// See func Dial of the standard library for the supported networks.
func TestableNetwork(network string) bool {
	ss := strings.Split(network, ":")
	switch ss[0] {
	case "ip+nopriv":
		// This is an internal network name for testing on the
		// package net of the standard library.
		switch runtime.GOOS {
		case "android", "fuchsia", "hurd", "ios", "js", "nacl", "plan9", "windows":
			return false
		}
	case "ip", "ip4", "ip6":
		switch runtime.GOOS {
		case "fuchsia", "hurd", "js", "nacl", "plan9":
			return false
		default:
			if os.Getuid() != 0 {
				return false
			}
		}
	case "unix", "unixgram":
		switch runtime.GOOS {
		case "android", "fuchsia", "hurd", "ios", "js", "nacl", "plan9", "windows":
			return false
		case "aix":
			return unixStrmDgramEnabled()
		}
	case "unixpacket":
		switch runtime.GOOS {
		case "aix", "android", "fuchsia", "hurd", "darwin", "ios", "js", "nacl", "plan9", "windows", "zos":
			return false
		case "netbsd":
			// It passes on amd64 at least. 386 fails
			// (Issue 22927). arm is unknown.
			if runtime.GOARCH == "386" {
				return false
			}
		}
	}
	switch ss[0] {
	case "tcp4", "udp4", "ip4":
		return SupportsIPv4()
	case "tcp6", "udp6", "ip6":
		return SupportsIPv6()
	}
	return true
}

// TestableAddress reports whether address of network is testable on
// the current platform configuration.
func TestableAddress(network, address string) bool {
	switch ss := strings.Split(network, ":"); ss[0] {
	case "unix", "unixgram", "unixpacket":
		// Abstract unix domain sockets, a Linux-ism.
		if address[0] == '@' && runtime.GOOS != "linux" {
			return false
		}
	}
	return true
}

// NewLocalListener returns a listener which listens to a loopback IP
// address or local file system path.
//
// The provided network must be "tcp", "tcp4", "tcp6", "unix" or
// "unixpacket".
func NewLocalListener(network string) (net.Listener, error) {
	switch network {
	case "tcp":
		if SupportsIPv4() {
			if ln, err := net.Listen("tcp4", "127.0.0.1:0"); err == nil {
				return ln, nil
			}
		}
		if SupportsIPv6() {
			return net.Listen("tcp6", "[::1]:0")
		}
	case "tcp4":
		if SupportsIPv4() {
			return net.Listen("tcp4", "127.0.0.1:0")
		}
	case "tcp6":
		if SupportsIPv6() {
			return net.Listen("tcp6", "[::1]:0")
		}
	case "unix", "unixpacket":
		path, err := LocalPath()
		if err != nil {
			return nil, err
		}
		return net.Listen(network, path)
	}
	return nil, fmt.Errorf("%s is not supported on %s/%s", network, runtime.GOOS, runtime.GOARCH)
}

// NewLocalPacketListener returns a packet listener which listens to a
// loopback IP address or local file system path.
//
// The provided network must be "udp", "udp4", "udp6" or "unixgram".
func NewLocalPacketListener(network string) (net.PacketConn, error) {
	switch network {
	case "udp":
		if SupportsIPv4() {
			if c, err := net.ListenPacket("udp4", "127.0.0.1:0"); err == nil {
				return c, nil
			}
		}
		if SupportsIPv6() {
			return net.ListenPacket("udp6", "[::1]:0")
		}
	case "udp4":
		if SupportsIPv4() {
			return net.ListenPacket("udp4", "127.0.0.1:0")
		}
	case "udp6":
		if SupportsIPv6() {
			return net.ListenPacket("udp6", "[::1]:0")
		}
	case "unixgram":
		path, err := LocalPath()
		if err != nil {
			return nil, err
		}
		return net.ListenPacket(network, path)
	}
	return nil, fmt.Errorf("%s is not supported on %s/%s", network, runtime.GOOS, runtime.GOARCH)
}

// LocalPath returns a local path that can be used for Unix-domain
// protocol testing.
func LocalPath() (string, error) {
	f, err := ioutil.TempFile("", "go-nettest")
	if err != nil {
		return "", err
	}
	path := f.Name()
	f.Close()
	os.Remove(path)
	return path, nil
}

// MulticastSource returns a unicast IP address on ifi when ifi is an
// IP multicast-capable network interface.
//
// The provided network must be "ip", "ip4" or "ip6".
func MulticastSource(network string, ifi *net.Interface) (net.IP, error) {
	switch network {
	case "ip", "ip4", "ip6":
	default:
		return nil, errNoAvailableAddress
	}
	if ifi == nil || ifi.Flags&net.FlagUp == 0 || ifi.Flags&net.FlagMulticast == 0 {
		return nil, errNoAvailableAddress
	}
	ip, ok := hasRoutableIP(network, ifi)
	if !ok {
		return nil, errNoAvailableAddress
	}
	return ip, nil
}

// LoopbackInterface returns an available logical network interface
// for loopback test.
func LoopbackInterface() (*net.Interface, error) {
	ift, err := net.Interfaces()
	if err != nil {
		return nil, errNoAvailableInterface
	}
	for _, ifi := range ift {
		if ifi.Flags&net.FlagLoopback != 0 && ifi.Flags&net.FlagUp != 0 {
			return &ifi, nil
		}
	}
	return nil, errNoAvailableInterface
}

// RoutedInterface returns a network interface that can route IP
// traffic and satisfies flags.
//
// The provided network must be "ip", "ip4" or "ip6".
func RoutedInterface(network string, flags net.Flags) (*net.Interface, error) {
	switch network {
	case "ip", "ip4", "ip6":
	default:
		return nil, errNoAvailableInterface
	}
	ift, err := net.Interfaces()
	if err != nil {
		return nil, errNoAvailableInterface
	}
	for _, ifi := range ift {
		if ifi.Flags&flags != flags {
			continue
		}
		if _, ok := hasRoutableIP(network, &ifi); !ok {
			continue
		}
		return &ifi, nil
	}
	return nil, errNoAvailableInterface
}

func hasRoutableIP(network string, ifi *net.Interface) (net.IP, bool) {
	ifat, err := ifi.Addrs()
	if err != nil {
		return nil, false
	}
	for _, ifa := range ifat {
		switch ifa := ifa.(type) {
		case *net.IPAddr:
			if ip, ok := routableIP(network, ifa.IP); ok {
				return ip, true
			}
		case *net.IPNet:
			if ip, ok := routableIP(network, ifa.IP); ok {
				return ip, true
			}
		}
	}
	return nil, false
}

func routableIP(network string, ip net.IP) (net.IP, bool) {
	if !ip.IsLoopback() && !ip.IsLinkLocalUnicast() && !ip.IsGlobalUnicast() {
		return nil, false
	}
	switch network {
	case "ip4":
		if ip := ip.To4(); ip != nil {
			return ip, true
		}
	case "ip6":
		if ip.IsLoopback() { // addressing scope of the loopback address depends on each implementation
			return nil, false
		}
		if ip := ip.To16(); ip != nil && ip.To4() == nil {
			return ip, true
		}
	default:
		if ip := ip.To4(); ip != nil {
			return ip, true
		}
		if ip := ip.To16(); ip != nil {
			return ip, true
		}
	}
	return nil, false
}
<|endoftext|>


<commit_before>package ethereum

import (
	"github.com/SmartPool/smartpool-client"
	"sync"
	"time"
)

// workpool keeps track of pending works to ensure that each submitted solution
// can actually be accepted by a real pow work.
// workpool also implements ShareReceiver interface.
type WorkPool struct {
	mu    sync.RWMutex
	works map[string]*Work
}

const (
	WORKPOOL_FILE     string = "workpool"
	FullBlockSolution int    = 2
	ValidShare        int    = 1
	InvalidShare      int    = 0
)

// AcceptSolution takes solution and find corresponding work and return
// associated share.
// It returns nil if the work is not found.
func (wp *WorkPool) AcceptSolution(s smartpool.Solution) smartpool.Share {
	wp.mu.RLock()
	defer wp.mu.RUnlock()
	work := wp.works[s.WorkID()]
	if work == nil {
		smartpool.Output.Printf("work (%v) doesn't exist in workpool (len: %d)\n", s, len(wp.works))
		return nil
	}
	share := work.AcceptSolution(s).(*Share)
	if share.SolutionState == InvalidShare {
		smartpool.Output.Printf("Solution (%v) is invalid\n", s)
		return nil
	} else {
		// smartpool.Output.Printf(
		// 	"Create share for work: ID: %s - createdAt: %s - timestamp: 0x%s\n",
		// 	work.ID(),
		// 	work.CreatedAt(),
		// 	work.BlockHeader().Time.Text(16),
		// )
		return share
	}
}

func (wp *WorkPool) AddWork(w *Work) {
	wp.mu.Lock()
	defer wp.mu.Unlock()
	wp.works[w.ID()] = w
}

func (wp *WorkPool) RemoveWork(hash string) {
	wp.mu.Lock()
	defer wp.mu.Unlock()
	delete(wp.works, hash)
}

func (wp *WorkPool) oldHashes() []string {
	wp.mu.RLock()
	defer wp.mu.RUnlock()
	result := []string{}
	for hash, work := range wp.works {
		if time.Since(work.CreatedAt) > 7*(12*time.Second) {
			result = append(result, hash)
		}
	}
	return result
}

func (wp *WorkPool) Clean() {
	oldHashes := wp.oldHashes()
	for _, hash := range oldHashes {
		wp.RemoveWork(hash)
	}
	if len(oldHashes) > 0 {
		smartpool.Output.Printf("Cleaned %d old works.\n", len(oldHashes))
	}
}

func (wp *WorkPool) RunCleaner() {
	ticker := time.Tick(140 * time.Second)
	for _ = range ticker {
		wp.Clean()
	}
}

func (wp *WorkPool) Persist(storage smartpool.PersistentStorage) error {
	wp.mu.RLock()
	defer wp.mu.RUnlock()
	smartpool.Output.Printf("Saving workpool to disk...")
	err := storage.Persist(wp.works, WORKPOOL_FILE)
	if err == nil {
		smartpool.Output.Printf("Done.\n")
	} else {
		smartpool.Output.Printf("Failed. (%s)\n", err.Error())
	}
	return err
}

func NewWorkPool(storage smartpool.PersistentStorage) *WorkPool {
	wp, err := loadWorkPool(storage)
	if err != nil {
		smartpool.Output.Printf("Couldn't load workpool from last session (%s). Initialize with empty workpool.\n", err)
	}
	smartpool.Output.Printf("Loaded %d works from last session.\n", len(wp.works))
	return wp
}

func loadWorkPool(storage smartpool.PersistentStorage) (*WorkPool, error) {
	wp := &WorkPool{}
	works := map[string]*Work{}
	loadedWorks, err := storage.Load(works, WORKPOOL_FILE)
	if err != nil {
		return wp, err
	}
	wp.works = loadedWorks.(map[string]*Work)
	return wp, err
}
<commit_msg>fix workpool initialization<commit_after>package ethereum

import (
	"github.com/SmartPool/smartpool-client"
	"sync"
	"time"
)

// workpool keeps track of pending works to ensure that each submitted solution
// can actually be accepted by a real pow work.
// workpool also implements ShareReceiver interface.
type WorkPool struct {
	mu    sync.RWMutex
	works map[string]*Work
}

const (
	WORKPOOL_FILE     string = "workpool"
	FullBlockSolution int    = 2
	ValidShare        int    = 1
	InvalidShare      int    = 0
)

// AcceptSolution takes solution and find corresponding work and return
// associated share.
// It returns nil if the work is not found.
func (wp *WorkPool) AcceptSolution(s smartpool.Solution) smartpool.Share {
	wp.mu.RLock()
	defer wp.mu.RUnlock()
	work := wp.works[s.WorkID()]
	if work == nil {
		smartpool.Output.Printf("work (%v) doesn't exist in workpool (len: %d)\n", s, len(wp.works))
		return nil
	}
	share := work.AcceptSolution(s).(*Share)
	if share.SolutionState == InvalidShare {
		smartpool.Output.Printf("Solution (%v) is invalid\n", s)
		return nil
	} else {
		// smartpool.Output.Printf(
		// 	"Create share for work: ID: %s - createdAt: %s - timestamp: 0x%s\n",
		// 	work.ID(),
		// 	work.CreatedAt(),
		// 	work.BlockHeader().Time.Text(16),
		// )
		return share
	}
}

func (wp *WorkPool) AddWork(w *Work) {
	wp.mu.Lock()
	defer wp.mu.Unlock()
	wp.works[w.ID()] = w
}

func (wp *WorkPool) RemoveWork(hash string) {
	wp.mu.Lock()
	defer wp.mu.Unlock()
	delete(wp.works, hash)
}

func (wp *WorkPool) oldHashes() []string {
	wp.mu.RLock()
	defer wp.mu.RUnlock()
	result := []string{}
	for hash, work := range wp.works {
		if time.Since(work.CreatedAt) > 7*(12*time.Second) {
			result = append(result, hash)
		}
	}
	return result
}

func (wp *WorkPool) Clean() {
	oldHashes := wp.oldHashes()
	for _, hash := range oldHashes {
		wp.RemoveWork(hash)
	}
	if len(oldHashes) > 0 {
		smartpool.Output.Printf("Cleaned %d old works.\n", len(oldHashes))
	}
}

func (wp *WorkPool) RunCleaner() {
	ticker := time.Tick(140 * time.Second)
	for _ = range ticker {
		wp.Clean()
	}
}

func (wp *WorkPool) Persist(storage smartpool.PersistentStorage) error {
	wp.mu.RLock()
	defer wp.mu.RUnlock()
	smartpool.Output.Printf("Saving workpool to disk...")
	err := storage.Persist(wp.works, WORKPOOL_FILE)
	if err == nil {
		smartpool.Output.Printf("Done.\n")
	} else {
		smartpool.Output.Printf("Failed. (%s)\n", err.Error())
	}
	return err
}

func NewWorkPool(storage smartpool.PersistentStorage) *WorkPool {
	wp, err := loadWorkPool(storage)
	if err != nil {
		smartpool.Output.Printf("Couldn't load workpool from last session (%s). Initialize with empty workpool.\n", err)
	}
	smartpool.Output.Printf("Loaded %d works from last session.\n", len(wp.works))
	return wp
}

func loadWorkPool(storage smartpool.PersistentStorage) (*WorkPool, error) {
	wp := &WorkPool{sync.RWMutex{}, map[string]*Work{}}
	works := map[string]*Work{}
	loadedWorks, err := storage.Load(works, WORKPOOL_FILE)
	if err != nil {
		return wp, err
	}
	wp.works = loadedWorks.(map[string]*Work)
	return wp, err
}
<|endoftext|>


<commit_before>/* Copyright 2014 Ooyala, Inc. All rights reserved.
 *
 * This file is 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 client

import (
	. "atlantis/common"
	. "atlantis/manager/rpc/types"
	"errors"
)

type StatusCommand struct {
	ID string `short:"i" long:"id" description:"the task ID to fetch the status for"`
}

func (c *StatusCommand) Execute(args []string) error {
	err := Init()
	if err != nil {
		return OutputError(err)
	}
	args = ExtractArgs([]*string{&c.ID}, args)
	Log("Task Status...")
	arg := c.ID
	var reply TaskStatus
	err = rpcClient.Call("Status", arg, &reply)
	if err != nil {
		return OutputError(err)
	}
	Log("-> %s", reply.String())
	return Output(reply.Map(), reply.Status, nil)
}

type ResultCommand struct {
	ID string `short:"i" long:"id" description:"the task ID to fetch the result for"`
}

func (c *ResultCommand) Execute(args []string) error {
	err := Init()
	if err != nil {
		return OutputError(err)
	}
	args = ExtractArgs([]*string{&c.ID}, args)
	arg := c.ID
	var reply TaskStatus
	err = rpcClient.Call("Status", arg, &reply)
	if err != nil {
		return OutputError(err)
	}
	switch reply.Name {
	case "Deploy":
		return (&DeployResultCommand{c.ID}).Execute(args)
	case "Teardown":
		return (&TeardownResultCommand{c.ID}).Execute(args)
	case "RegisterManager":
		return (&RegisterManagerResultCommand{c.ID}).Execute(args)
	case "UnregisterManager":
		return (&UnregisterManagerResultCommand{c.ID}).Execute(args)
	case "RegisterRouter":
		return (&RegisterRouterResultCommand{c.ID}).Execute(args)
	case "UnregisterRouter":
		return (&UnregisterRouterResultCommand{c.ID}).Execute(args)
	case "RegisterSupervisor":
		return (&RegisterSupervisorResultCommand{c.ID}).Execute(args)
	case "UnregisterSupervisor":
		return (&UnregisterSupervisorResultCommand{c.ID}).Execute(args)
	default:
		return OutputError(errors.New("Invalid Task Name: " + reply.Name))
	}
}

type WaitCommand struct {
	ID string `short:"i" long:"id" description:"the task ID to wait on"`
}

func (c *WaitCommand) Execute(args []string) error {
	err := Init()
	if err != nil {
		return OutputError(err)
	}
	args = ExtractArgs([]*string{&c.ID}, args)
	Log("Waiting...")
	arg := c.ID
	var statusReply TaskStatus
	var currentStatus string
	if err := rpcClient.Call("Status", arg, &statusReply); err != nil {
		return OutputError(err)
	}
	for !statusReply.Done {
		if currentStatus != statusReply.Status {
			currentStatus = statusReply.Status
			Log(currentStatus)
		}
		if err := rpcClient.Call("Status", c.ID, &statusReply); err != nil {
			return OutputError(err)
		}
	}
	return (&ResultCommand{c.ID}).Execute(args)
}

type ListTaskIDsCommand struct {
}

func (c *ListTaskIDsCommand) Execute(args []string) error {
	if err := Init(); err != nil {
		return OutputError(err)
	}
	Log("List Task IDs...")
	user, secret, err := GetSecret()
	if err != nil {
		return err
	}
	authArg := ManagerAuthArg{user, "", secret}
	var ids []string
	if err := rpcClient.Call("ListTaskIDs", authArg, &ids); err != nil {
		return OutputError(err)
	}
	return Output(map[string]interface{}{"ids": ids}, ids, nil)
}
<commit_msg>Add poll delay to client.  When waiting, check with the server every 3 seconds, not continuously.<commit_after>/* Copyright 2014 Ooyala, Inc. All rights reserved.
 *
 * This file is 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 client

import (
	. "atlantis/common"
	. "atlantis/manager/rpc/types"
	"errors"
	"time"
)

const waitPollInterval = 3 * time.Second

type StatusCommand struct {
	ID string `short:"i" long:"id" description:"the task ID to fetch the status for"`
}

func (c *StatusCommand) Execute(args []string) error {
	err := Init()
	if err != nil {
		return OutputError(err)
	}
	args = ExtractArgs([]*string{&c.ID}, args)
	Log("Task Status...")
	arg := c.ID
	var reply TaskStatus
	err = rpcClient.Call("Status", arg, &reply)
	if err != nil {
		return OutputError(err)
	}
	Log("-> %s", reply.String())
	return Output(reply.Map(), reply.Status, nil)
}

type ResultCommand struct {
	ID string `short:"i" long:"id" description:"the task ID to fetch the result for"`
}

func (c *ResultCommand) Execute(args []string) error {
	err := Init()
	if err != nil {
		return OutputError(err)
	}
	args = ExtractArgs([]*string{&c.ID}, args)
	arg := c.ID
	var reply TaskStatus
	err = rpcClient.Call("Status", arg, &reply)
	if err != nil {
		return OutputError(err)
	}
	switch reply.Name {
	case "Deploy":
		return (&DeployResultCommand{c.ID}).Execute(args)
	case "Teardown":
		return (&TeardownResultCommand{c.ID}).Execute(args)
	case "RegisterManager":
		return (&RegisterManagerResultCommand{c.ID}).Execute(args)
	case "UnregisterManager":
		return (&UnregisterManagerResultCommand{c.ID}).Execute(args)
	case "RegisterRouter":
		return (&RegisterRouterResultCommand{c.ID}).Execute(args)
	case "UnregisterRouter":
		return (&UnregisterRouterResultCommand{c.ID}).Execute(args)
	case "RegisterSupervisor":
		return (&RegisterSupervisorResultCommand{c.ID}).Execute(args)
	case "UnregisterSupervisor":
		return (&UnregisterSupervisorResultCommand{c.ID}).Execute(args)
	default:
		return OutputError(errors.New("Invalid Task Name: " + reply.Name))
	}
}

type WaitCommand struct {
	ID string `short:"i" long:"id" description:"the task ID to wait on"`
}

func (c *WaitCommand) Execute(args []string) error {
	err := Init()
	if err != nil {
		return OutputError(err)
	}
	args = ExtractArgs([]*string{&c.ID}, args)
	Log("Waiting...")
	arg := c.ID
	var statusReply TaskStatus
	var currentStatus string
	if err := rpcClient.Call("Status", arg, &statusReply); err != nil {
		return OutputError(err)
	}
	for !statusReply.Done {
		time.Sleep(waitPollInterval)
		if currentStatus != statusReply.Status {
			currentStatus = statusReply.Status
			Log(currentStatus)
		}
		if err := rpcClient.Call("Status", c.ID, &statusReply); err != nil {
			return OutputError(err)
		}
	}
	return (&ResultCommand{c.ID}).Execute(args)
}

type ListTaskIDsCommand struct {
}

func (c *ListTaskIDsCommand) Execute(args []string) error {
	if err := Init(); err != nil {
		return OutputError(err)
	}
	Log("List Task IDs...")
	user, secret, err := GetSecret()
	if err != nil {
		return err
	}
	authArg := ManagerAuthArg{user, "", secret}
	var ids []string
	if err := rpcClient.Call("ListTaskIDs", authArg, &ids); err != nil {
		return OutputError(err)
	}
	return Output(map[string]interface{}{"ids": ids}, ids, nil)
}
<|endoftext|>


<commit_before>/*
 * Minimal multicast DNS server.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import "log"
import "os"

import "github.com/docopt/docopt-go"

import "mcast"
import "mdns"

func main() {
	log.SetFlags(0);

	usage := `Usage: moodns [options]

Options:
  -H <hostname>, --host <hostname>      Name of the local host.
  -l <addr:port>, --listen <addr:port>  Listen on this address and port [default: 0.0.0.0:5353].
  -s, --silent                          Print fatal errors only.
  -h, --help                            Show the program's help message and exit.`

	args, err := docopt.Parse(usage, nil, true, "", false)
	if err != nil {
		log.Fatal("Invalid arguments: ", err);
	}

	listen   := args["--listen"].(string);
	hostname := "";

	if args["--host"] == nil {
		hostname, err = os.Hostname();
		if err != nil {
			log.Fatal("Error retrieving hostname: ", err);
		}
	} else {
		hostname = args["--host"].(string);
	}

	localname := hostname + ".local.";

	maddr, server, err := mcast.NewServer(listen, "224.0.0.251:5353");
	if err != nil {
		log.Fatal("Error starting server: ", err);
	}

	pkt := make([]byte, 65536);

	for {
		n, local4, local6, client, err := mcast.Read(server, pkt);
		if err != nil {
			if args["--silent"].(bool) != true {
				log.Print("Error reading from network: ", err);
			}
		}

		req, err := mdns.Unpack(pkt[:n]);
		if err != nil {
			if args["--silent"].(bool) != true {
				log.Print("Error unpacking request: ", err);
			}
			continue;
		}

		if len(req.Question) == 0 || len(req.Answer) > 0 {
			continue;
		}

		rsp := new(mdns.Message);

		rsp.Header.Flags |= mdns.FlagQR;
		rsp.Header.Flags |= mdns.FlagAA;

		if client.Port != 5353 {
			rsp.Header.Id = req.Header.Id;
		}

		for _, q := range req.Question {
			if string(q.Name) != localname {
				continue;
			}

			switch (q.Type) {
				case mdns.TypeA:
					an := mdns.NewA(local4.IP);
					rsp.AppendAN(q, an);

				case mdns.TypeAAAA:
					an := mdns.NewAAAA(local6.IP);
					rsp.AppendAN(q, an);

				default:
					continue;
			}
		}

		if len(rsp.Answer) == 0 {
			continue;
		}

		out, err := mdns.Pack(rsp);
		if err != nil {
			log.Fatal("Error packing response: ", err);
		}

		if client.Port == 5353 {
			client = maddr;
		}

		_, err = server.WriteToUDP(out, client);
		if err != nil {
			log.Fatal("Error writing to network: ", err);
		}
	}
}
<commit_msg>moodns: properly build legacy unicast dns reponse<commit_after>/*
 * Minimal multicast DNS server.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import "log"
import "os"

import "github.com/docopt/docopt-go"

import "mcast"
import "mdns"

func main() {
	log.SetFlags(0);

	usage := `Usage: moodns [options]

Options:
  -H <hostname>, --host <hostname>      Name of the local host.
  -l <addr:port>, --listen <addr:port>  Listen on this address and port [default: 0.0.0.0:5353].
  -s, --silent                          Print fatal errors only.
  -h, --help                            Show the program's help message and exit.`

	args, err := docopt.Parse(usage, nil, true, "", false)
	if err != nil {
		log.Fatal("Invalid arguments: ", err);
	}

	listen   := args["--listen"].(string);
	hostname := "";

	if args["--host"] == nil {
		hostname, err = os.Hostname();
		if err != nil {
			log.Fatal("Error retrieving hostname: ", err);
		}
	} else {
		hostname = args["--host"].(string);
	}

	localname := hostname + ".local.";

	maddr, server, err := mcast.NewServer(listen, "224.0.0.251:5353");
	if err != nil {
		log.Fatal("Error starting server: ", err);
	}

	pkt := make([]byte, 65536);

	for {
		n, local4, local6, client, err := mcast.Read(server, pkt);
		if err != nil {
			if args["--silent"].(bool) != true {
				log.Print("Error reading from network: ", err);
			}
		}

		req, err := mdns.Unpack(pkt[:n]);
		if err != nil {
			if args["--silent"].(bool) != true {
				log.Print("Error unpacking request: ", err);
			}
			continue;
		}

		if len(req.Question) == 0 || len(req.Answer) > 0 {
			continue;
		}

		rsp := new(mdns.Message);

		rsp.Header.Flags |= mdns.FlagQR;
		rsp.Header.Flags |= mdns.FlagAA;

		if req.Header.Flags & mdns.FlagRD != 0 {
			rsp.Header.Flags |= mdns.FlagRD;
			rsp.Header.Flags |= mdns.FlagRA
		}

		if client.Port != 5353 {
			rsp.Header.Id = req.Header.Id;
		}

		for _, q := range req.Question {
			if string(q.Name) != localname {
				continue;
			}

			switch (q.Type) {
				case mdns.TypeA:
					an := mdns.NewA(local4.IP);
					rsp.AppendAN(q, an);

				case mdns.TypeAAAA:
					an := mdns.NewAAAA(local6.IP);
					rsp.AppendAN(q, an);

				default:
					continue;
			}

			if client.Port != 5353 {
				rsp.Question = append(rsp.Question, q);
				rsp.Header.QDCount++;
			}
		}

		if len(rsp.Answer) == 0 {
			continue;
		}

		out, err := mdns.Pack(rsp);
		if err != nil {
			log.Fatal("Error packing response: ", err);
		}

		if client.Port == 5353 {
			client = maddr;
		}

		_, err = server.WriteToUDP(out, client);
		if err != nil {
			log.Fatal("Error writing to network: ", err);
		}
	}
}
<|endoftext|>


<commit_before>package cc_messages

import (
	"encoding/json"

	"github.com/cloudfoundry-incubator/bbs/models"
)

type HealthCheckType string

const UnspecifiedHealthCheckType HealthCheckType = "" // backwards-compatibility
const PortHealthCheckType HealthCheckType = "port"
const NoneHealthCheckType HealthCheckType = "none"

const CC_HTTP_ROUTES = "http_routes"

const CC_TCP_ROUTES = "tcp_routes"

type DesireAppRequestFromCC struct {
	ProcessGuid                 string                        `json:"process_guid"`
	DropletUri                  string                        `json:"droplet_uri"`
	DockerImageUrl              string                        `json:"docker_image"`
	DockerLoginServer           string                        `json:"docker_login_server,omitempty"`
	DockerUser                  string                        `json:"docker_user,omitempty"`
	DockerPassword              string                        `json:"docker_password,omitempty"`
	DockerEmail                 string                        `json:"docker_email,omitempty"`
	Stack                       string                        `json:"stack"`
	StartCommand                string                        `json:"start_command"`
	ExecutionMetadata           string                        `json:"execution_metadata"`
	Environment                 []*models.EnvironmentVariable `json:"environment"`
	MemoryMB                    int                           `json:"memory_mb"`
	DiskMB                      int                           `json:"disk_mb"`
	FileDescriptors             uint64                        `json:"file_descriptors"`
	NumInstances                int                           `json:"num_instances"`
	RoutingInfo                 CCRouteInfo                   `json:"routing_info"`
	AllowSSH                    bool                          `json:"allow_ssh"`
	LogGuid                     string                        `json:"log_guid"`
	HealthCheckType             HealthCheckType               `json:"health_check_type"`
	HealthCheckTimeoutInSeconds uint                          `json:"health_check_timeout_in_seconds"`
	EgressRules                 []*models.SecurityGroupRule   `json:"egress_rules,omitempty"`
	ETag                        string                        `json:"etag"`
	Ports                       []uint32                      `json:"ports,omitempty"`
}

type CCRouteInfo map[string]*json.RawMessage

type CCHTTPRoutes []CCHTTPRoute

func (r CCHTTPRoutes) CCRouteInfo() (CCRouteInfo, error) {
	routesJson, err := json.Marshal(r)
	if err != nil {
		return nil, err
	}

	routesPayload := json.RawMessage(routesJson)
	routingInfo := make(map[string]*json.RawMessage)
	routingInfo[CC_HTTP_ROUTES] = &routesPayload
	return routingInfo, nil
}

type CCHTTPRoute struct {
	Hostname        string `json:"hostname"`
	RouteServiceUrl string `json:"route_service_url,omitempty"`
	Port            uint32 `json:"port,omitempty"`
}

type CCTCPRoutes []CCTCPRoute

type CCTCPRoute struct {
	RouterGroupGuid string `json:"router_group_guid"`
	ExternalPort    uint32 `json:"external_port,omitempty"`
	ContainerPort   uint32 `json:"container_port,omitempty"`
}

func (r CCTCPRoutes) CCRouteInfo() (CCRouteInfo, error) {
	routesJson, err := json.Marshal(r)
	if err != nil {
		return nil, err
	}

	routesPayload := json.RawMessage(routesJson)
	routingInfo := make(map[string]*json.RawMessage)
	routingInfo[CC_TCP_ROUTES] = &routesPayload
	return routingInfo, nil
}

type CCDesiredStateServerResponse struct {
	Apps        []DesireAppRequestFromCC `json:"apps"`
	CCBulkToken *json.RawMessage         `json:"token"`
}

type CCDesiredAppFingerprint struct {
	ProcessGuid string `json:"process_guid"`
	ETag        string `json:"etag"`
}

type CCDesiredStateFingerprintResponse struct {
	Fingerprints []CCDesiredAppFingerprint `json:"fingerprints"`
	CCBulkToken  *json.RawMessage          `json:"token"`
}

type CCBulkToken struct {
	Id int `json:"id"`
}

type TaskErrorID string

type TaskRequestFromCC struct {
	TaskGuid              string                        `json:"task_guid"`
	LogGuid               string                        `json:"log_guid"`
	MemoryMb              int                           `json:"memory_mb"`
	DiskMb                int                           `json:"disk_mb"`
	Lifecycle             string                        `json:"lifecycle"`
	EnvironmentVariables  []*models.EnvironmentVariable `json:"environment"`
	EgressRules           []*models.SecurityGroupRule   `json:"egress_rules,omitempty"`
	DropletUri            string                        `json:"droplet_uri"`
	DockerPath            string                        `json:"docker_path"`
	RootFs                string                        `json:"rootfs"`
	CompletionCallbackUrl string                        `json:"completion_callback"`
	Command               string                        `json:"command"`
}

type TaskError struct {
	Id      TaskErrorID `json:"id"`
	Message string      `json:"message"`
}
<commit_msg>Add log source to task request from cc<commit_after>package cc_messages

import (
	"encoding/json"

	"github.com/cloudfoundry-incubator/bbs/models"
)

type HealthCheckType string

const UnspecifiedHealthCheckType HealthCheckType = "" // backwards-compatibility
const PortHealthCheckType HealthCheckType = "port"
const NoneHealthCheckType HealthCheckType = "none"

const CC_HTTP_ROUTES = "http_routes"

const CC_TCP_ROUTES = "tcp_routes"

type DesireAppRequestFromCC struct {
	ProcessGuid                 string                        `json:"process_guid"`
	DropletUri                  string                        `json:"droplet_uri"`
	DockerImageUrl              string                        `json:"docker_image"`
	DockerLoginServer           string                        `json:"docker_login_server,omitempty"`
	DockerUser                  string                        `json:"docker_user,omitempty"`
	DockerPassword              string                        `json:"docker_password,omitempty"`
	DockerEmail                 string                        `json:"docker_email,omitempty"`
	Stack                       string                        `json:"stack"`
	StartCommand                string                        `json:"start_command"`
	ExecutionMetadata           string                        `json:"execution_metadata"`
	Environment                 []*models.EnvironmentVariable `json:"environment"`
	MemoryMB                    int                           `json:"memory_mb"`
	DiskMB                      int                           `json:"disk_mb"`
	FileDescriptors             uint64                        `json:"file_descriptors"`
	NumInstances                int                           `json:"num_instances"`
	RoutingInfo                 CCRouteInfo                   `json:"routing_info"`
	AllowSSH                    bool                          `json:"allow_ssh"`
	LogGuid                     string                        `json:"log_guid"`
	HealthCheckType             HealthCheckType               `json:"health_check_type"`
	HealthCheckTimeoutInSeconds uint                          `json:"health_check_timeout_in_seconds"`
	EgressRules                 []*models.SecurityGroupRule   `json:"egress_rules,omitempty"`
	ETag                        string                        `json:"etag"`
	Ports                       []uint32                      `json:"ports,omitempty"`
}

type CCRouteInfo map[string]*json.RawMessage

type CCHTTPRoutes []CCHTTPRoute

func (r CCHTTPRoutes) CCRouteInfo() (CCRouteInfo, error) {
	routesJson, err := json.Marshal(r)
	if err != nil {
		return nil, err
	}

	routesPayload := json.RawMessage(routesJson)
	routingInfo := make(map[string]*json.RawMessage)
	routingInfo[CC_HTTP_ROUTES] = &routesPayload
	return routingInfo, nil
}

type CCHTTPRoute struct {
	Hostname        string `json:"hostname"`
	RouteServiceUrl string `json:"route_service_url,omitempty"`
	Port            uint32 `json:"port,omitempty"`
}

type CCTCPRoutes []CCTCPRoute

type CCTCPRoute struct {
	RouterGroupGuid string `json:"router_group_guid"`
	ExternalPort    uint32 `json:"external_port,omitempty"`
	ContainerPort   uint32 `json:"container_port,omitempty"`
}

func (r CCTCPRoutes) CCRouteInfo() (CCRouteInfo, error) {
	routesJson, err := json.Marshal(r)
	if err != nil {
		return nil, err
	}

	routesPayload := json.RawMessage(routesJson)
	routingInfo := make(map[string]*json.RawMessage)
	routingInfo[CC_TCP_ROUTES] = &routesPayload
	return routingInfo, nil
}

type CCDesiredStateServerResponse struct {
	Apps        []DesireAppRequestFromCC `json:"apps"`
	CCBulkToken *json.RawMessage         `json:"token"`
}

type CCDesiredAppFingerprint struct {
	ProcessGuid string `json:"process_guid"`
	ETag        string `json:"etag"`
}

type CCDesiredStateFingerprintResponse struct {
	Fingerprints []CCDesiredAppFingerprint `json:"fingerprints"`
	CCBulkToken  *json.RawMessage          `json:"token"`
}

type CCBulkToken struct {
	Id int `json:"id"`
}

type TaskErrorID string

type TaskRequestFromCC struct {
	TaskGuid              string                        `json:"task_guid"`
	LogGuid               string                        `json:"log_guid"`
	MemoryMb              int                           `json:"memory_mb"`
	DiskMb                int                           `json:"disk_mb"`
	Lifecycle             string                        `json:"lifecycle"`
	EnvironmentVariables  []*models.EnvironmentVariable `json:"environment"`
	EgressRules           []*models.SecurityGroupRule   `json:"egress_rules,omitempty"`
	DropletUri            string                        `json:"droplet_uri"`
	DockerPath            string                        `json:"docker_path"`
	RootFs                string                        `json:"rootfs"`
	CompletionCallbackUrl string                        `json:"completion_callback"`
	Command               string                        `json:"command"`
	LogSource             string                        `json:"log_source,omit_empty"`
}

type TaskError struct {
	Id      TaskErrorID `json:"id"`
	Message string      `json:"message"`
}
<|endoftext|>


<commit_before>// Copyright 2014 Hajime Hoshi
//
// 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"
	"github.com/hajimehoshi/ebiten"
	"github.com/hajimehoshi/ebiten/ebitenutil"
	"image/color"
	"log"
	"math"
)

const (
	screenWidth  = 320
	screenHeight = 240
)

var (
	count              int
	brushRenderTarget  *ebiten.Image
	canvasRenderTarget *ebiten.Image
)

func update(screen *ebiten.Image) error {
	if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
		count++
	}

	mx, my := ebiten.CursorPosition()

	if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
		op := &ebiten.DrawImageOptions{}
		op.GeoM.Translate(float64(mx), float64(my))
		op.ColorM.Scale(1.0, 0.25, 0.25, 1.0)
		theta := 2.0 * math.Pi * float64(count%60) / 60.0
		op.ColorM.Concat(ebiten.RotateHue(theta))
		if err := canvasRenderTarget.DrawImage(brushRenderTarget, op); err != nil {
			return err
		}
	}

	if err := screen.DrawImage(canvasRenderTarget, nil); err != nil {
		return err
	}

	if err := ebitenutil.DebugPrint(screen, fmt.Sprintf("(%d, %d)", mx, my)); err != nil {
		return err
	}
	return nil
}

func main() {
	var err error
	brushRenderTarget, err = ebiten.NewImage(4, 4, ebiten.FilterNearest)
	if err != nil {
		log.Fatal(err)
	}
	brushRenderTarget.Fill(color.White)

	canvasRenderTarget, err = ebiten.NewImage(screenWidth, screenHeight, ebiten.FilterNearest)
	if err != nil {
		log.Fatal(err)
	}
	canvasRenderTarget.Fill(color.White)

	if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Paint (Ebiten Demo)"); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Improve example/paint<commit_after>// Copyright 2014 Hajime Hoshi
//
// 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"
	"github.com/hajimehoshi/ebiten"
	"github.com/hajimehoshi/ebiten/ebitenutil"
	"image"
	"image/color"
	"log"
	"math"
)

const (
	screenWidth  = 320
	screenHeight = 240
)

var (
	count       int
	brushImage  *ebiten.Image
	canvasImage *ebiten.Image
)

func update(screen *ebiten.Image) error {
	if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
		count++
	}

	mx, my := ebiten.CursorPosition()

	if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
		op := &ebiten.DrawImageOptions{}
		op.GeoM.Translate(float64(mx), float64(my))
		op.ColorM.Scale(1.0, 0.25, 0.25, 1.0)
		theta := 2.0 * math.Pi * float64(count%60) / 60.0
		op.ColorM.Concat(ebiten.RotateHue(theta))
		if err := canvasImage.DrawImage(brushImage, op); err != nil {
			return err
		}
	}

	if err := screen.DrawImage(canvasImage, nil); err != nil {
		return err
	}

	if err := ebitenutil.DebugPrint(screen, fmt.Sprintf("(%d, %d)", mx, my)); err != nil {
		return err
	}
	return nil
}

func main() {
	var err error
	const a0, a1, a2 = 0x40, 0xc0, 0xff
	pixels := []uint8{
		a0, a1, a1, a0,
		a1, a2, a2, a1,
		a1, a2, a2, a1,
		a0, a1, a1, a0,
	}
	brushImage, err = ebiten.NewImageFromImage(&image.Alpha{
		Pix:    pixels,
		Stride: 4,
		Rect:   image.Rect(0, 0, 4, 4),
	}, ebiten.FilterNearest)
	if err != nil {
		log.Fatal(err)
	}

	canvasImage, err = ebiten.NewImage(screenWidth, screenHeight, ebiten.FilterNearest)
	if err != nil {
		log.Fatal(err)
	}
	canvasImage.Fill(color.White)

	if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Paint (Ebiten Demo)"); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/Sirupsen/logrus"
	"github.com/gemnasium/logrus-airbrake-hook"
)

var log = logrus.New()

func init() {
	log.Formatter = new(logrus.TextFormatter) // default
	log.Hooks.Add(airbrake.NewHook("https://example.com", "xyz", "development"))
}

func main() {
	log.WithFields(logrus.Fields{
		"animal": "walrus",
		"size":   10,
	}).Info("A group of walrus emerges from the ocean")

	log.WithFields(logrus.Fields{
		"omg":    true,
		"number": 122,
	}).Warn("The group's number increased tremendously!")

	log.WithFields(logrus.Fields{
		"omg":    true,
		"number": 100,
	}).Fatal("The ice breaks!")
}
<commit_msg>hook.go matches their gopkg.in/gemnasium/logrus-airbrake-hook.v2 now<commit_after>package main

import (
	"github.com/Sirupsen/logrus"
	"gopkg.in/gemnasium/logrus-airbrake-hook.v2"
)

var log = logrus.New()

func init() {
	log.Formatter = new(logrus.TextFormatter) // default
	log.Hooks.Add(airbrake.NewHook(123, "xyz", "development"))
}

func main() {
	log.WithFields(logrus.Fields{
		"animal": "walrus",
		"size":   10,
	}).Info("A group of walrus emerges from the ocean")

	log.WithFields(logrus.Fields{
		"omg":    true,
		"number": 122,
	}).Warn("The group's number increased tremendously!")

	log.WithFields(logrus.Fields{
		"omg":    true,
		"number": 100,
	}).Fatal("The ice breaks!")
}
<|endoftext|>


<commit_before>package checktcp

import (
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"strconv"
	"testing"
	"time"

	"github.com/mackerelio/checkers"
	"github.com/stretchr/testify/assert"
)

func TestEscapedString(t *testing.T) {
	assert.Equal(t, "\n", escapedString(`\n`), "something went wrong")
	assert.Equal(t, "hoge\\", escapedString(`hoge\`), "something went wrong")
	assert.Equal(t, "ho\rge", escapedString(`ho\rge`), "something went wrong")
	assert.Equal(t, "ho\\oge", escapedString(`ho\oge`), "something went wrong")
	assert.Equal(t, "", escapedString(``), "something went wrong")
}

func TestTLS(t *testing.T) {
	opts, err := parseArgs([]string{"-S", "-H", "www.verisign.com", "-p", "443"})
	assert.Equal(t, nil, err, "no errors")
	ckr := opts.run()
	assert.Equal(t, checkers.OK, ckr.Status, "should be OK")
}

func TestFTP(t *testing.T) {
	opts, err := parseArgs([]string{"--service=ftp", "-H", "ftp.iij.ad.jp"})
	assert.Equal(t, nil, err, "no errors")
	ckr := opts.run()
	assert.Equal(t, checkers.OK, ckr.Status, "should be OK")
}

type mockGearmanServer struct {
	listener net.Listener
	terdown  chan struct{}
	done     chan struct{}
}

func makeGearmandMockServer() (*mockGearmanServer, error) {
	listener, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		return nil, err
	}
	server := &mockGearmanServer{
		listener: listener,
		terdown:  make(chan struct{}, 1),
		done:     make(chan struct{}, 1),
	}
	return server, nil
}

func (s *mockGearmanServer) port() (int, error) {
	_, port, err := net.SplitHostPort(s.listener.Addr().String())
	if err != nil {
		return 0, err
	}
	return strconv.Atoi(port)
}

func (s *mockGearmanServer) shutdown() {
	s.terdown <- struct{}{}
	s.listener.Close()
	<-s.done
}

func (s *mockGearmanServer) run() {
loop:
	for {
		select {
		case <-s.terdown:
			break loop
		default:
			conn, err := s.listener.Accept()
			if err != nil {
				continue loop
			}

			buf := make([]byte, 16)
			i, err := conn.Read(buf)
			if err != nil {
				switch err {
				case io.EOF:
					// nothing to do
				default:
					panic(err)
				}
			}
			req := string(buf[:i])
			res := "ERR unknown_command Unknown+server+command\n"
			if req == "version\n" {
				res = "1.11\n"
			}
			_, err = conn.Write([]byte(res))
			if err != nil {
				panic(err)
			}
			conn.Close()
		}
	}
	s.done <- struct{}{}
}

func TestGEARMAN(t *testing.T) {
	server, err := makeGearmandMockServer()
	if err != nil {
		panic(err)
	}
	port, err := server.port()
	if err != nil {
		panic(err)
	}
	go server.run()
	opts, err := parseArgs([]string{"--service=gearman", "-H", "127.0.0.1", "-p", strconv.Itoa(port)})
	assert.Equal(t, nil, err, "no errors")
	ckr := opts.run()
	assert.Equal(t, checkers.OK, ckr.Status, "should be OK\n")
	server.shutdown()
}

func TestHTTP(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		time.Sleep(time.Second / 5)
		w.WriteHeader(200)
		w.Header().Set("Content-Type", "text/plain")
		fmt.Fprint(w, "OKOK")
	}))
	defer ts.Close()

	u, _ := url.Parse(ts.URL)

	host, port, _ := net.SplitHostPort(u.Host)

	testOk := func() {
		opts, err := parseArgs([]string{"-H", host, "-p", port, "--send", `GET / HTTP/1.0\r\n\r\n`, "-E", "-e", "OKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		fmt.Println(ckr)
		assert.Equal(t, checkers.OK, ckr.Status, "should be OK")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOk()

	testUnexpected := func() {
		opts, err := parseArgs(
			[]string{"-H", host, "-p", port, "--send", `GET / HTTP/1.0\r\n\r\n`, "-E", "-e", "OKOKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be CRITICAL")
		assert.Regexp(t, `Unexpected response from`, ckr.Message, "Unexpected response")
	}
	testUnexpected()

	testOverWarn := func() {
		opts, err := parseArgs(
			[]string{"-H", host, "-p", port, "--send", `GET / HTTP/1.0\r\n\r\n`, "-E", "-e", "OKOK", "-w", "0.1"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.WARNING, ckr.Status, "should be Warning")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverWarn()

	testOverCrit := func() {
		opts, err := parseArgs(
			[]string{"-H", host, "-p", port, "--send", "GET / HTTP/1.0\r\n\r\n", "-e", "OKOK", "-c", "0.1"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be Critical")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverCrit()
}

func TestUnixDomainSocket(t *testing.T) {
	dir, err := ioutil.TempDir(os.TempDir(), "")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)

	sock := fmt.Sprintf("%s/test.sock", dir)

	l, err := net.Listen("unix", sock)
	if err != nil {
		t.Error(err)
	}

	go func() {
		for {
			ls, err := l.Accept()
			if err != nil {
				t.Error(err)
			}
			go func(c net.Conn) {
				defer c.Close()

				buf := make([]byte, 1024)

				_, err := c.Read(buf)

				if err == io.EOF {
					return
				}

				c.Write([]byte("OKOK"))
			}(ls)
		}
	}()

	testOk := func() {
		opts, err := parseArgs([]string{"-U", sock, "--send", `PING`, "-E", "-e", "OKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.OK, ckr.Status, "should be OK")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOk()

	testUnexpected := func() {
		opts, err := parseArgs([]string{"-U", sock, "--send", `PING`, "-E", "-e", "OKOKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be CRITICAL")
		assert.Regexp(t, `Unexpected response from`, ckr.Message, "Unexpected response")
	}
	testUnexpected()

	testOverWarn := func() {
		opts, err := parseArgs([]string{"-U", sock, "--send", `PING`, "-E", "-e", "OKOK", "-w", "0.000000001"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.WARNING, ckr.Status, "should be Warning")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverWarn()

	testOverCrit := func() {
		opts, err := parseArgs([]string{"-U", sock, "--send", `PING`, "-E", "-e", "OKOK", "-c", "0.000000001"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be Critical")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverCrit()
}

func TestHTTPIPv6(t *testing.T) {
	http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		time.Sleep(time.Second / 5)
		w.WriteHeader(200)
		w.Header().Set("Content-Type", "text/plain")
		fmt.Fprint(w, "OKOK")
	})

	l, err := net.Listen("tcp", "[::1]:0")
	if err != nil {
		t.Error(err)
	}
	defer l.Close()
	h, port, _ := net.SplitHostPort(l.Addr().String())
	host := fmt.Sprintf("[%s]", h)

	go func() {
		for {
			http.Serve(l, nil)
		}
	}()

	testOk := func() {
		opts, err := parseArgs([]string{"-H", host, "-p", port, "--send", `GET / HTTP/1.0\r\n\r\n`, "-E", "-e", "OKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.OK, ckr.Status, "should be OK")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOk()

	testUnexpected := func() {
		opts, err := parseArgs(
			[]string{"-H", host, "-p", port, "--send", `GET / HTTP/1.0\r\n\r\n`, "-E", "-e", "OKOKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be CRITICAL")
		assert.Regexp(t, `Unexpected response from`, ckr.Message, "Unexpected response")
	}
	testUnexpected()

	testOverWarn := func() {
		opts, err := parseArgs(
			[]string{"-H", host, "-p", port, "--send", `GET / HTTP/1.0\r\n\r\n`, "-E", "-e", "OKOK", "-w", "0.1"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.WARNING, ckr.Status, "should be Warning")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverWarn()

	testOverCrit := func() {
		opts, err := parseArgs(
			[]string{"-H", host, "-p", port, "--send", "GET / HTTP/1.0\r\n\r\n", "-e", "OKOK", "-c", "0.1"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be Critical")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverCrit()
}
<commit_msg>Skip IPv6 tests in Travis<commit_after>package checktcp

import (
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"strconv"
	"testing"
	"time"

	"github.com/mackerelio/checkers"
	"github.com/stretchr/testify/assert"
)

func TestEscapedString(t *testing.T) {
	assert.Equal(t, "\n", escapedString(`\n`), "something went wrong")
	assert.Equal(t, "hoge\\", escapedString(`hoge\`), "something went wrong")
	assert.Equal(t, "ho\rge", escapedString(`ho\rge`), "something went wrong")
	assert.Equal(t, "ho\\oge", escapedString(`ho\oge`), "something went wrong")
	assert.Equal(t, "", escapedString(``), "something went wrong")
}

func TestTLS(t *testing.T) {
	opts, err := parseArgs([]string{"-S", "-H", "www.verisign.com", "-p", "443"})
	assert.Equal(t, nil, err, "no errors")
	ckr := opts.run()
	assert.Equal(t, checkers.OK, ckr.Status, "should be OK")
}

func TestFTP(t *testing.T) {
	opts, err := parseArgs([]string{"--service=ftp", "-H", "ftp.iij.ad.jp"})
	assert.Equal(t, nil, err, "no errors")
	ckr := opts.run()
	assert.Equal(t, checkers.OK, ckr.Status, "should be OK")
}

type mockGearmanServer struct {
	listener net.Listener
	terdown  chan struct{}
	done     chan struct{}
}

func makeGearmandMockServer() (*mockGearmanServer, error) {
	listener, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		return nil, err
	}
	server := &mockGearmanServer{
		listener: listener,
		terdown:  make(chan struct{}, 1),
		done:     make(chan struct{}, 1),
	}
	return server, nil
}

func (s *mockGearmanServer) port() (int, error) {
	_, port, err := net.SplitHostPort(s.listener.Addr().String())
	if err != nil {
		return 0, err
	}
	return strconv.Atoi(port)
}

func (s *mockGearmanServer) shutdown() {
	s.terdown <- struct{}{}
	s.listener.Close()
	<-s.done
}

func (s *mockGearmanServer) run() {
loop:
	for {
		select {
		case <-s.terdown:
			break loop
		default:
			conn, err := s.listener.Accept()
			if err != nil {
				continue loop
			}

			buf := make([]byte, 16)
			i, err := conn.Read(buf)
			if err != nil {
				switch err {
				case io.EOF:
					// nothing to do
				default:
					panic(err)
				}
			}
			req := string(buf[:i])
			res := "ERR unknown_command Unknown+server+command\n"
			if req == "version\n" {
				res = "1.11\n"
			}
			_, err = conn.Write([]byte(res))
			if err != nil {
				panic(err)
			}
			conn.Close()
		}
	}
	s.done <- struct{}{}
}

func TestGEARMAN(t *testing.T) {
	server, err := makeGearmandMockServer()
	if err != nil {
		panic(err)
	}
	port, err := server.port()
	if err != nil {
		panic(err)
	}
	go server.run()
	opts, err := parseArgs([]string{"--service=gearman", "-H", "127.0.0.1", "-p", strconv.Itoa(port)})
	assert.Equal(t, nil, err, "no errors")
	ckr := opts.run()
	assert.Equal(t, checkers.OK, ckr.Status, "should be OK\n")
	server.shutdown()
}

func TestHTTP(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		time.Sleep(time.Second / 5)
		w.WriteHeader(200)
		w.Header().Set("Content-Type", "text/plain")
		fmt.Fprint(w, "OKOK")
	}))
	defer ts.Close()

	u, _ := url.Parse(ts.URL)

	host, port, _ := net.SplitHostPort(u.Host)

	testOk := func() {
		opts, err := parseArgs([]string{"-H", host, "-p", port, "--send", `GET / HTTP/1.0\r\n\r\n`, "-E", "-e", "OKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		fmt.Println(ckr)
		assert.Equal(t, checkers.OK, ckr.Status, "should be OK")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOk()

	testUnexpected := func() {
		opts, err := parseArgs(
			[]string{"-H", host, "-p", port, "--send", `GET / HTTP/1.0\r\n\r\n`, "-E", "-e", "OKOKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be CRITICAL")
		assert.Regexp(t, `Unexpected response from`, ckr.Message, "Unexpected response")
	}
	testUnexpected()

	testOverWarn := func() {
		opts, err := parseArgs(
			[]string{"-H", host, "-p", port, "--send", `GET / HTTP/1.0\r\n\r\n`, "-E", "-e", "OKOK", "-w", "0.1"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.WARNING, ckr.Status, "should be Warning")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverWarn()

	testOverCrit := func() {
		opts, err := parseArgs(
			[]string{"-H", host, "-p", port, "--send", "GET / HTTP/1.0\r\n\r\n", "-e", "OKOK", "-c", "0.1"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be Critical")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverCrit()
}

func TestUnixDomainSocket(t *testing.T) {
	dir, err := ioutil.TempDir(os.TempDir(), "")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)

	sock := fmt.Sprintf("%s/test.sock", dir)

	l, err := net.Listen("unix", sock)
	if err != nil {
		t.Error(err)
	}

	go func() {
		for {
			ls, err := l.Accept()
			if err != nil {
				t.Error(err)
			}
			go func(c net.Conn) {
				defer c.Close()

				buf := make([]byte, 1024)

				_, err := c.Read(buf)

				if err == io.EOF {
					return
				}

				c.Write([]byte("OKOK"))
			}(ls)
		}
	}()

	testOk := func() {
		opts, err := parseArgs([]string{"-U", sock, "--send", `PING`, "-E", "-e", "OKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.OK, ckr.Status, "should be OK")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOk()

	testUnexpected := func() {
		opts, err := parseArgs([]string{"-U", sock, "--send", `PING`, "-E", "-e", "OKOKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be CRITICAL")
		assert.Regexp(t, `Unexpected response from`, ckr.Message, "Unexpected response")
	}
	testUnexpected()

	testOverWarn := func() {
		opts, err := parseArgs([]string{"-U", sock, "--send", `PING`, "-E", "-e", "OKOK", "-w", "0.000000001"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.WARNING, ckr.Status, "should be Warning")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverWarn()

	testOverCrit := func() {
		opts, err := parseArgs([]string{"-U", sock, "--send", `PING`, "-E", "-e", "OKOK", "-c", "0.000000001"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be Critical")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverCrit()
}

func TestHTTPIPv6(t *testing.T) {
	http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		time.Sleep(time.Second / 5)
		w.WriteHeader(200)
		w.Header().Set("Content-Type", "text/plain")
		fmt.Fprint(w, "OKOK")
	})

	l, err := net.Listen("tcp", "[::1]:0")
	if err != nil {
		if os.Getenv("TRAVIS") != "" {
			t.Skip("Skip: in Travis, ipv6 networking seems not working.")
		}
		t.Error(err)
	}
	defer l.Close()
	h, port, _ := net.SplitHostPort(l.Addr().String())
	host := fmt.Sprintf("[%s]", h)

	go func() {
		for {
			http.Serve(l, nil)
		}
	}()

	testOk := func() {
		opts, err := parseArgs([]string{"-H", host, "-p", port, "--send", `GET / HTTP/1.0\r\n\r\n`, "-E", "-e", "OKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.OK, ckr.Status, "should be OK")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOk()

	testUnexpected := func() {
		opts, err := parseArgs(
			[]string{"-H", host, "-p", port, "--send", `GET / HTTP/1.0\r\n\r\n`, "-E", "-e", "OKOKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be CRITICAL")
		assert.Regexp(t, `Unexpected response from`, ckr.Message, "Unexpected response")
	}
	testUnexpected()

	testOverWarn := func() {
		opts, err := parseArgs(
			[]string{"-H", host, "-p", port, "--send", `GET / HTTP/1.0\r\n\r\n`, "-E", "-e", "OKOK", "-w", "0.1"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.WARNING, ckr.Status, "should be Warning")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverWarn()

	testOverCrit := func() {
		opts, err := parseArgs(
			[]string{"-H", host, "-p", port, "--send", "GET / HTTP/1.0\r\n\r\n", "-e", "OKOK", "-c", "0.1"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be Critical")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverCrit()
}
<|endoftext|>


<commit_before>package endpoint

import (
	"bytes"
	"fmt"
	"math"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/bluele/gcache"
	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
)

const (
	bufSize              = 8 * 1024 * 1024 // 8MB
	maxReverseDNSrecords = 10000
)

// DNSSnooper is a snopper of DNS queries
type DNSSnooper struct {
	stop            chan struct{}
	pcapHandle      *pcap.Handle
	reverseDNSCache gcache.Cache
}

// NewDNSSnooper creates a new snooper of DNS queries
func NewDNSSnooper() (*DNSSnooper, error) {
	pcapHandle, err := newPcapHandle()
	if err != nil {
		return nil, err
	}
	reverseDNSCache := gcache.New(maxReverseDNSrecords).LRU().Build()

	s := &DNSSnooper{
		stop:            make(chan struct{}),
		pcapHandle:      pcapHandle,
		reverseDNSCache: reverseDNSCache,
	}
	go s.run()
	return s, nil
}

func newPcapHandle() (*pcap.Handle, error) {
	inactive, err := pcap.NewInactiveHandle("any")
	if err != nil {
		return nil, err
	}
	defer inactive.CleanUp()
	// pcap timeout blackmagic copied from Weave Net to reduce CPU consumption
	// see https://github.com/weaveworks/weave/commit/025315363d5ea8b8265f1b3ea800f24df2be51a4
	if err = inactive.SetTimeout(time.Duration(math.MaxInt64)); err != nil {
		return nil, err
	}
	if err = inactive.SetImmediateMode(true); err != nil {
		// If gopacket is compiled against an older pcap.h that
		// doesn't have pcap_set_immediate_mode, it supplies a dummy
		// definition that always returns PCAP_ERROR.  That becomes
		// "Generic error", which is not very helpful.  The real
		// pcap_set_immediate_mode never returns PCAP_ERROR, so this
		// turns it into a more informative message.
		if fmt.Sprint(err) == "Generic error" {
			return nil, fmt.Errorf("compiled against an old version of libpcap; please compile against libpcap-1.5.0 or later")
		}

		return nil, err
	}
	if err = inactive.SetBufferSize(bufSize); err != nil {
		return nil, err
	}
	pcapHandle, err := inactive.Activate()
	if err != nil {
		return nil, err
	}
	if err := pcapHandle.SetDirection(pcap.DirectionIn); err != nil {
		pcapHandle.Close()
		return nil, err
	}
	if err := pcapHandle.SetBPFFilter("inbound and port 53"); err != nil {
		pcapHandle.Close()
		return nil, err
	}

	return pcapHandle, nil
}

// CachedNamesForIP obtains the domains associated to an IP,
// obtained while snooping A-record queries
func (s *DNSSnooper) CachedNamesForIP(ip string) []string {
	result := []string{}
	if s == nil {
		return result
	}
	domains, err := s.reverseDNSCache.Get(ip)
	if err != nil {
		return result
	}

	for domain := range domains.(map[string]struct{}) {
		result = append(result, domain)
	}

	return result
}

// Stop makes the snooper stop inspecting DNS communications
func (s *DNSSnooper) Stop() {
	if s != nil {
		close(s.stop)
	}
}

func (s *DNSSnooper) run() {
	var (
		decodedLayers []gopacket.LayerType
		dns           layers.DNS
		udp           layers.UDP
		tcp           layers.TCP
		ip4           layers.IPv4
		ip6           layers.IPv6
		eth           layers.Ethernet
		sll           layers.LinuxSLL
	)

	// assumes that the "any" interface is being used (see https://wiki.wireshark.org/SLL)
	packetParser := gopacket.NewDecodingLayerParser(layers.LayerTypeLinuxSLL, &sll, &eth, &ip4, &ip6, &udp, &tcp, &dns)

	for {
		select {
		case <-s.stop:
			s.pcapHandle.Close()
			return
		default:
		}

		packet, _, err := s.pcapHandle.ZeroCopyReadPacketData()
		if err != nil {
			// TimeoutExpired is acceptable due to the Timeout black magic
			// on the handle
			if err != pcap.NextErrorTimeoutExpired {
				log.Errorf("DNSSnooper: error reading packet data: %s", err)
			}
			continue
		}

		if err := packetParser.DecodeLayers(packet, &decodedLayers); err != nil {
			log.Errorf("DNSSnooper: error decoding packet: %s", err)
			continue
		}

		for _, layerType := range decodedLayers {
			if layerType == layers.LayerTypeDNS {
				s.processDNSMessage(&dns)
			}
		}
	}
}

func (s *DNSSnooper) processDNSMessage(dns *layers.DNS) {

	// Only consider responses to singleton, A-record questions
	if !dns.QR || dns.ResponseCode != 0 || len(dns.Questions) != 1 {
		return
	}
	question := dns.Questions[0]
	if question.Type != layers.DNSTypeA || question.Class != layers.DNSClassIN {
		return
	}

	var (
		domainQueried = question.Name
		records       = append(dns.Answers, dns.Additionals...)
		ips           = map[string]struct{}{}
		alias         []byte
	)

	// Traverse records for a CNAME first since the DNS RFCs don't seem to guarantee it
	// appearing before its A-records
	for _, record := range records {
		if record.Type == layers.DNSTypeCNAME && record.Class == layers.DNSClassIN && bytes.Equal(domainQueried, record.Name) {
			alias = record.CNAME
			break
		}
	}

	// Finally, get the answer
	for _, record := range records {
		if record.Type != layers.DNSTypeA || record.Class != layers.DNSClassIN {
			continue
		}
		if bytes.Equal(domainQueried, record.Name) || (alias != nil && bytes.Equal(alias, record.Name)) {
			ips[record.IP.String()] = struct{}{}
		}
	}

	// Update cache
	newDomain := string(domainQueried)
	log.Debugf("DNSSnooper: caught DNS lookup: %s -> %v", newDomain, ips)
	for ip := range ips {
		if existingDomains, err := s.reverseDNSCache.Get(ip); err != nil {
			s.reverseDNSCache.Set(ip, map[string]struct{}{newDomain: {}})
		} else {
			// TODO: Be smarter about the expiration of entries with pre-existing associated domains
			existingDomains.(map[string]struct{})[newDomain] = struct{}{}
		}
	}
}
<commit_msg>Add support for snooping DNS over TCP<commit_after>package endpoint

import (
	"bytes"
	"fmt"
	"math"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/bluele/gcache"
	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
)

const (
	bufSize              = 8 * 1024 * 1024 // 8MB
	maxReverseDNSrecords = 10000
)

// DNSSnooper is a snopper of DNS queries
type DNSSnooper struct {
	stop            chan struct{}
	pcapHandle      *pcap.Handle
	reverseDNSCache gcache.Cache
}

// NewDNSSnooper creates a new snooper of DNS queries
func NewDNSSnooper() (*DNSSnooper, error) {
	pcapHandle, err := newPcapHandle()
	if err != nil {
		return nil, err
	}
	reverseDNSCache := gcache.New(maxReverseDNSrecords).LRU().Build()

	s := &DNSSnooper{
		stop:            make(chan struct{}),
		pcapHandle:      pcapHandle,
		reverseDNSCache: reverseDNSCache,
	}
	go s.run()
	return s, nil
}

func newPcapHandle() (*pcap.Handle, error) {
	inactive, err := pcap.NewInactiveHandle("any")
	if err != nil {
		return nil, err
	}
	defer inactive.CleanUp()
	// pcap timeout blackmagic copied from Weave Net to reduce CPU consumption
	// see https://github.com/weaveworks/weave/commit/025315363d5ea8b8265f1b3ea800f24df2be51a4
	if err = inactive.SetTimeout(time.Duration(math.MaxInt64)); err != nil {
		return nil, err
	}
	if err = inactive.SetImmediateMode(true); err != nil {
		// If gopacket is compiled against an older pcap.h that
		// doesn't have pcap_set_immediate_mode, it supplies a dummy
		// definition that always returns PCAP_ERROR.  That becomes
		// "Generic error", which is not very helpful.  The real
		// pcap_set_immediate_mode never returns PCAP_ERROR, so this
		// turns it into a more informative message.
		if fmt.Sprint(err) == "Generic error" {
			return nil, fmt.Errorf("compiled against an old version of libpcap; please compile against libpcap-1.5.0 or later")
		}

		return nil, err
	}
	if err = inactive.SetBufferSize(bufSize); err != nil {
		return nil, err
	}
	pcapHandle, err := inactive.Activate()
	if err != nil {
		return nil, err
	}
	if err := pcapHandle.SetDirection(pcap.DirectionIn); err != nil {
		pcapHandle.Close()
		return nil, err
	}
	if err := pcapHandle.SetBPFFilter("inbound and port 53"); err != nil {
		pcapHandle.Close()
		return nil, err
	}

	return pcapHandle, nil
}

// CachedNamesForIP obtains the domains associated to an IP,
// obtained while snooping A-record queries
func (s *DNSSnooper) CachedNamesForIP(ip string) []string {
	result := []string{}
	if s == nil {
		return result
	}
	domains, err := s.reverseDNSCache.Get(ip)
	if err != nil {
		return result
	}

	for domain := range domains.(map[string]struct{}) {
		result = append(result, domain)
	}

	return result
}

// Stop makes the snooper stop inspecting DNS communications
func (s *DNSSnooper) Stop() {
	if s != nil {
		close(s.stop)
	}
}

// Gopacket doesn't provide direct support for DNS over TCP, see https://github.com/google/gopacket/issues/236
type tcpWithDNSSupport struct {
	tcp layers.TCP
}

func (m *tcpWithDNSSupport) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	return m.tcp.DecodeFromBytes(data, df)
}
func (m *tcpWithDNSSupport) CanDecode() gopacket.LayerClass { return m.tcp.CanDecode() }
func (m *tcpWithDNSSupport) NextLayerType() gopacket.LayerType {
	if m.tcp.SrcPort == 53 || m.tcp.DstPort == 53 {
		return layers.LayerTypeDNS
	}
	return m.tcp.NextLayerType()
}
func (m *tcpWithDNSSupport) LayerPayload() []byte { return m.tcp.LayerPayload() }

func (s *DNSSnooper) run() {
	var (
		decodedLayers []gopacket.LayerType
		dns           layers.DNS
		udp           layers.UDP
		tcp           tcpWithDNSSupport
		ip4           layers.IPv4
		ip6           layers.IPv6
		eth           layers.Ethernet
		sll           layers.LinuxSLL
	)

	// assumes that the "any" interface is being used (see https://wiki.wireshark.org/SLL)
	packetParser := gopacket.NewDecodingLayerParser(layers.LayerTypeLinuxSLL, &sll, &eth, &ip4, &ip6, &udp, &tcp, &dns)

	for {
		select {
		case <-s.stop:
			s.pcapHandle.Close()
			return
		default:
		}

		packet, _, err := s.pcapHandle.ZeroCopyReadPacketData()
		if err != nil {
			// TimeoutExpired is acceptable due to the Timeout black magic
			// on the handle
			if err != pcap.NextErrorTimeoutExpired {
				log.Errorf("DNSSnooper: error reading packet data: %s", err)
			}
			continue
		}

		if err := packetParser.DecodeLayers(packet, &decodedLayers); err != nil {
			log.Errorf("DNSSnooper: error decoding packet: %s", err)
			continue
		}

		for _, layerType := range decodedLayers {
			if layerType == layers.LayerTypeDNS {
				s.processDNSMessage(&dns)
			}
		}
	}
}

func (s *DNSSnooper) processDNSMessage(dns *layers.DNS) {

	// Only consider responses to singleton, A-record questions
	if !dns.QR || dns.ResponseCode != 0 || len(dns.Questions) != 1 {
		return
	}
	question := dns.Questions[0]
	if question.Type != layers.DNSTypeA || question.Class != layers.DNSClassIN {
		return
	}

	var (
		domainQueried = question.Name
		records       = append(dns.Answers, dns.Additionals...)
		ips           = map[string]struct{}{}
		alias         []byte
	)

	// Traverse records for a CNAME first since the DNS RFCs don't seem to guarantee it
	// appearing before its A-records
	for _, record := range records {
		if record.Type == layers.DNSTypeCNAME && record.Class == layers.DNSClassIN && bytes.Equal(domainQueried, record.Name) {
			alias = record.CNAME
			break
		}
	}

	// Finally, get the answer
	for _, record := range records {
		if record.Type != layers.DNSTypeA || record.Class != layers.DNSClassIN {
			continue
		}
		if bytes.Equal(domainQueried, record.Name) || (alias != nil && bytes.Equal(alias, record.Name)) {
			ips[record.IP.String()] = struct{}{}
		}
	}

	// Update cache
	newDomain := string(domainQueried)
	log.Debugf("DNSSnooper: caught DNS lookup: %s -> %v", newDomain, ips)
	for ip := range ips {
		if existingDomains, err := s.reverseDNSCache.Get(ip); err != nil {
			s.reverseDNSCache.Set(ip, map[string]struct{}{newDomain: {}})
		} else {
			// TODO: Be smarter about the expiration of entries with pre-existing associated domains
			existingDomains.(map[string]struct{})[newDomain] = struct{}{}
		}
	}
}
<|endoftext|>


<commit_before>package executor

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/hashicorp/nomad/client/allocdir"
	"github.com/hashicorp/nomad/nomad/mock"
	"github.com/hashicorp/nomad/nomad/structs"

	ctestutil "github.com/hashicorp/nomad/client/testutil"
)

var (
	constraint = &structs.Resources{
		CPU:      0.5,
		MemoryMB: 256,
		Networks: []*structs.NetworkResource{
			&structs.NetworkResource{
				MBits:        50,
				DynamicPorts: []string{"http"},
			},
		},
	}
)

func mockAllocDir(t *testing.T) (string, *allocdir.AllocDir) {
	alloc := mock.Alloc()
	task := alloc.Job.TaskGroups[0].Tasks[0]

	allocDir := allocdir.NewAllocDir(filepath.Join(os.TempDir(), alloc.ID))
	if err := allocDir.Build([]*structs.Task{task}); err != nil {
		t.Fatalf("allocDir.Build() failed: %v", err)
	}

	return task.Name, allocDir
}

func TestExecutorLinux_Start_Invalid(t *testing.T) {
	ctestutil.ExecCompatible(t)
	invalid := "/bin/foobar"
	e := Command(invalid, "1")

	if err := e.Limit(constraint); err != nil {
		t.Fatalf("Limit() failed: %v", err)
	}

	task, alloc := mockAllocDir(t)
	defer alloc.Destroy()
	if err := e.ConfigureTaskDir(task, alloc); err != nil {
		t.Fatalf("ConfigureTaskDir(%v, %v) failed: %v", task, alloc, err)
	}

	if err := e.Start(); err == nil {
		t.Fatalf("Start(%v) should have failed", invalid)
	}
}

func TestExecutorLinux_Start_Wait_Failure_Code(t *testing.T) {
	ctestutil.ExecCompatible(t)
	e := Command("/bin/date", "-invalid")

	if err := e.Limit(constraint); err != nil {
		t.Fatalf("Limit() failed: %v", err)
	}

	task, alloc := mockAllocDir(t)
	defer alloc.Destroy()
	if err := e.ConfigureTaskDir(task, alloc); err != nil {
		t.Fatalf("ConfigureTaskDir(%v, %v) failed: %v", task, alloc, err)
	}

	if err := e.Start(); err != nil {
		t.Fatalf("Start() failed: %v", err)
	}

	if err := e.Wait(); err == nil {
		t.Fatalf("Wait() should have failed")
	}
}

func TestExecutorLinux_Start_Wait(t *testing.T) {
	ctestutil.ExecCompatible(t)
	task, alloc := mockAllocDir(t)
	defer alloc.Destroy()

	taskDir, ok := alloc.TaskDirs[task]
	if !ok {
		t.Fatalf("No task directory found for task %v", task)
	}

	expected := "hello world"
	file := filepath.Join(allocdir.TaskLocal, "output.txt")
	absFilePath := filepath.Join(taskDir, file)
	cmd := fmt.Sprintf("%v \"%v\" >> %v", "sleep 1 ; echo -n", expected, file)
	e := Command("/bin/bash", "-c", cmd)

	if err := e.Limit(constraint); err != nil {
		t.Fatalf("Limit() failed: %v", err)
	}

	if err := e.ConfigureTaskDir(task, alloc); err != nil {
		t.Fatalf("ConfigureTaskDir(%v, %v) failed: %v", task, alloc, err)
	}

	if err := e.Start(); err != nil {
		t.Fatalf("Start() failed: %v", err)
	}

	if err := e.Wait(); err != nil {
		t.Fatalf("Wait() failed: %v", err)
	}

	output, err := ioutil.ReadFile(absFilePath)
	if err != nil {
		t.Fatalf("Couldn't read file %v", absFilePath)
	}

	act := string(output)
	if act != expected {
		t.Fatalf("Command output incorrectly: want %v; got %v", expected, act)
	}
}

func TestExecutorLinux_Start_Kill(t *testing.T) {
	ctestutil.ExecCompatible(t)
	task, alloc := mockAllocDir(t)
	defer alloc.Destroy()

	taskDir, ok := alloc.TaskDirs[task]
	if !ok {
		t.Fatalf("No task directory found for task %v", task)
	}

	filePath := filepath.Join(taskDir, "output")
	e := Command("/bin/bash", "-c", "sleep 1 ; echo \"failure\" > "+filePath)

	// This test can only be run if cgroups are enabled.
	if !e.(*LinuxExecutor).cgroupEnabled {
		t.SkipNow()
	}

	if err := e.Limit(constraint); err != nil {
		t.Fatalf("Limit() failed: %v", err)
	}

	if err := e.ConfigureTaskDir(task, alloc); err != nil {
		t.Fatalf("ConfigureTaskDir(%v, %v) failed: %v", task, alloc, err)
	}

	if err := e.Start(); err != nil {
		t.Fatalf("Start() failed: %v", err)
	}

	if err := e.Shutdown(); err != nil {
		t.Fatalf("Shutdown() failed: %v", err)
	}

	time.Sleep(1500 * time.Millisecond)

	// Check that the file doesn't exist.
	if _, err := os.Stat(filePath); err == nil {
		t.Fatalf("Stat(%v) should have failed: task not killed", filePath)
	}
}

func TestExecutorLinux_Open(t *testing.T) {
	ctestutil.ExecCompatible(t)
	task, alloc := mockAllocDir(t)
	defer alloc.Destroy()

	taskDir, ok := alloc.TaskDirs[task]
	if !ok {
		t.Fatalf("No task directory found for task %v", task)
	}

	filePath := filepath.Join(taskDir, "output")
	e := Command("/bin/bash", "-c", "sleep 1 ; echo \"failure\" > "+filePath)

	// This test can only be run if cgroups are enabled.
	if !e.(*LinuxExecutor).cgroupEnabled {
		t.SkipNow()
	}

	if err := e.Limit(constraint); err != nil {
		t.Fatalf("Limit() failed: %v", err)
	}

	if err := e.ConfigureTaskDir(task, alloc); err != nil {
		t.Fatalf("ConfigureTaskDir(%v, %v) failed: %v", task, alloc, err)
	}

	if err := e.Start(); err != nil {
		t.Fatalf("Start() failed: %v", err)
	}

	id, err := e.ID()
	if err != nil {
		t.Fatalf("ID() failed: %v", err)
	}

	if _, err := OpenId(id); err == nil {
		t.Fatalf("Open(%v) should have failed", id)
	}

	time.Sleep(1500 * time.Millisecond)

	// Check that the file doesn't exist, open should have killed the process.
	if _, err := os.Stat(filePath); err == nil {
		t.Fatalf("Stat(%v) should have failed: task not killed", filePath)
	}
}
<commit_msg>Update CPU limit to be an int<commit_after>package executor

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/hashicorp/nomad/client/allocdir"
	"github.com/hashicorp/nomad/nomad/mock"
	"github.com/hashicorp/nomad/nomad/structs"

	ctestutil "github.com/hashicorp/nomad/client/testutil"
)

var (
	constraint = &structs.Resources{
		CPU:      250,
		MemoryMB: 256,
		Networks: []*structs.NetworkResource{
			&structs.NetworkResource{
				MBits:        50,
				DynamicPorts: []string{"http"},
			},
		},
	}
)

func mockAllocDir(t *testing.T) (string, *allocdir.AllocDir) {
	alloc := mock.Alloc()
	task := alloc.Job.TaskGroups[0].Tasks[0]

	allocDir := allocdir.NewAllocDir(filepath.Join(os.TempDir(), alloc.ID))
	if err := allocDir.Build([]*structs.Task{task}); err != nil {
		t.Fatalf("allocDir.Build() failed: %v", err)
	}

	return task.Name, allocDir
}

func TestExecutorLinux_Start_Invalid(t *testing.T) {
	ctestutil.ExecCompatible(t)
	invalid := "/bin/foobar"
	e := Command(invalid, "1")

	if err := e.Limit(constraint); err != nil {
		t.Fatalf("Limit() failed: %v", err)
	}

	task, alloc := mockAllocDir(t)
	defer alloc.Destroy()
	if err := e.ConfigureTaskDir(task, alloc); err != nil {
		t.Fatalf("ConfigureTaskDir(%v, %v) failed: %v", task, alloc, err)
	}

	if err := e.Start(); err == nil {
		t.Fatalf("Start(%v) should have failed", invalid)
	}
}

func TestExecutorLinux_Start_Wait_Failure_Code(t *testing.T) {
	ctestutil.ExecCompatible(t)
	e := Command("/bin/date", "-invalid")

	if err := e.Limit(constraint); err != nil {
		t.Fatalf("Limit() failed: %v", err)
	}

	task, alloc := mockAllocDir(t)
	defer alloc.Destroy()
	if err := e.ConfigureTaskDir(task, alloc); err != nil {
		t.Fatalf("ConfigureTaskDir(%v, %v) failed: %v", task, alloc, err)
	}

	if err := e.Start(); err != nil {
		t.Fatalf("Start() failed: %v", err)
	}

	if err := e.Wait(); err == nil {
		t.Fatalf("Wait() should have failed")
	}
}

func TestExecutorLinux_Start_Wait(t *testing.T) {
	ctestutil.ExecCompatible(t)
	task, alloc := mockAllocDir(t)
	defer alloc.Destroy()

	taskDir, ok := alloc.TaskDirs[task]
	if !ok {
		t.Fatalf("No task directory found for task %v", task)
	}

	expected := "hello world"
	file := filepath.Join(allocdir.TaskLocal, "output.txt")
	absFilePath := filepath.Join(taskDir, file)
	cmd := fmt.Sprintf("%v \"%v\" >> %v", "sleep 1 ; echo -n", expected, file)
	e := Command("/bin/bash", "-c", cmd)

	if err := e.Limit(constraint); err != nil {
		t.Fatalf("Limit() failed: %v", err)
	}

	if err := e.ConfigureTaskDir(task, alloc); err != nil {
		t.Fatalf("ConfigureTaskDir(%v, %v) failed: %v", task, alloc, err)
	}

	if err := e.Start(); err != nil {
		t.Fatalf("Start() failed: %v", err)
	}

	if err := e.Wait(); err != nil {
		t.Fatalf("Wait() failed: %v", err)
	}

	output, err := ioutil.ReadFile(absFilePath)
	if err != nil {
		t.Fatalf("Couldn't read file %v", absFilePath)
	}

	act := string(output)
	if act != expected {
		t.Fatalf("Command output incorrectly: want %v; got %v", expected, act)
	}
}

func TestExecutorLinux_Start_Kill(t *testing.T) {
	ctestutil.ExecCompatible(t)
	task, alloc := mockAllocDir(t)
	defer alloc.Destroy()

	taskDir, ok := alloc.TaskDirs[task]
	if !ok {
		t.Fatalf("No task directory found for task %v", task)
	}

	filePath := filepath.Join(taskDir, "output")
	e := Command("/bin/bash", "-c", "sleep 1 ; echo \"failure\" > "+filePath)

	// This test can only be run if cgroups are enabled.
	if !e.(*LinuxExecutor).cgroupEnabled {
		t.SkipNow()
	}

	if err := e.Limit(constraint); err != nil {
		t.Fatalf("Limit() failed: %v", err)
	}

	if err := e.ConfigureTaskDir(task, alloc); err != nil {
		t.Fatalf("ConfigureTaskDir(%v, %v) failed: %v", task, alloc, err)
	}

	if err := e.Start(); err != nil {
		t.Fatalf("Start() failed: %v", err)
	}

	if err := e.Shutdown(); err != nil {
		t.Fatalf("Shutdown() failed: %v", err)
	}

	time.Sleep(1500 * time.Millisecond)

	// Check that the file doesn't exist.
	if _, err := os.Stat(filePath); err == nil {
		t.Fatalf("Stat(%v) should have failed: task not killed", filePath)
	}
}

func TestExecutorLinux_Open(t *testing.T) {
	ctestutil.ExecCompatible(t)
	task, alloc := mockAllocDir(t)
	defer alloc.Destroy()

	taskDir, ok := alloc.TaskDirs[task]
	if !ok {
		t.Fatalf("No task directory found for task %v", task)
	}

	filePath := filepath.Join(taskDir, "output")
	e := Command("/bin/bash", "-c", "sleep 1 ; echo \"failure\" > "+filePath)

	// This test can only be run if cgroups are enabled.
	if !e.(*LinuxExecutor).cgroupEnabled {
		t.SkipNow()
	}

	if err := e.Limit(constraint); err != nil {
		t.Fatalf("Limit() failed: %v", err)
	}

	if err := e.ConfigureTaskDir(task, alloc); err != nil {
		t.Fatalf("ConfigureTaskDir(%v, %v) failed: %v", task, alloc, err)
	}

	if err := e.Start(); err != nil {
		t.Fatalf("Start() failed: %v", err)
	}

	id, err := e.ID()
	if err != nil {
		t.Fatalf("ID() failed: %v", err)
	}

	if _, err := OpenId(id); err == nil {
		t.Fatalf("Open(%v) should have failed", id)
	}

	time.Sleep(1500 * time.Millisecond)

	// Check that the file doesn't exist, open should have killed the process.
	if _, err := os.Stat(filePath); err == nil {
		t.Fatalf("Stat(%v) should have failed: task not killed", filePath)
	}
}
<|endoftext|>


<commit_before>// +build nokeychain freebsd openbsd 386 arm arm64 windows

package internal

var keychainEnabled = false

//storeTokens store tokens into keychain
func storeTokens(contextName string, tokens ContextTokens) error {
	//nothing to do here, token is already in cdsrc file
	return nil
}

//getTokens rerieves a CDS Context from CDSContext
func (c CDSContext) getTokens(contextName string) (*ContextTokens, error) {
	return &ContextTokens{Session: c.Session, Token: c.Token}, nil
}
<commit_msg>chore(cdsctl): let ppc64 (#4869)<commit_after>// +build nokeychain freebsd openbsd 386 arm arm64 windows ppc64 ppc64le

package internal

var keychainEnabled = false

//storeTokens store tokens into keychain
func storeTokens(contextName string, tokens ContextTokens) error {
	//nothing to do here, token is already in cdsrc file
	return nil
}

//getTokens rerieves a CDS Context from CDSContext
func (c CDSContext) getTokens(contextName string) (*ContextTokens, error) {
	return &ContextTokens{Session: c.Session, Token: c.Token}, nil
}
<|endoftext|>