<commit_before>package osc

import (
	"bytes"
	"net"
	"testing"
)

func TestInvalidAddress(t *testing.T) {
	dispatcher := map[string]Method{
		"/address*/test": func(msg *Message) error {
			return nil
		},
	}
	laddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	server, err := ListenUDP("udp", laddr)
	if err != nil {
		t.Fatal(err)
	}
	defer func() { _ = server.Close() }() // Best effort.

	if err := server.Serve(dispatcher); err != ErrInvalidAddress {
		t.Fatal("expected invalid address error")
	}
	if server != nil {
		_ = server.Close()
	}
}

func TestMessageDispatching(t *testing.T) {
	// dispatcher := map[string]Method{
	// 	"/address/test": func(msg *Message) error {
	// 		val, err := msg.ReadInt32()
	// 		if err != nil {
	// 			return err
	// 		}
	// 		if expected, got := int32(1122), val; expected != got {
	// 			return fmt.Errorf("Expected %d got %d", expected, got)
	// 		}
	// 		return nil
	// 	},
	// }

	laddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}

	server, err := ListenUDP("udp", laddr)
	if err != nil {
		t.Fatal(err)
	}
	defer func() { _ = server.Close() }() // Best effort.
}

func TestSend(t *testing.T) {
	var (
		doneChan = make(chan *Message)
		errChan  = make(chan error, 1)
	)

	dispatcher := map[string]Method{
		"/osc/address": func(msg *Message) error {
			doneChan <- msg
			return nil
		},
	}

	laddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}

	server, err := ListenUDP("udp", laddr)
	if err != nil {
		t.Fatal(err)
	}
	defer func() { _ = server.Close() }() // Best effort.

	serverAddr := server.LocalAddr()
	raddr, err := net.ResolveUDPAddr(serverAddr.Network(), serverAddr.String())
	if err != nil {
		t.Fatal(err)
	}

	client, err := DialUDP("udp", nil, raddr)
	if err != nil {
		t.Fatal(err)
	}

	go func() {
		errChan <- server.Serve(dispatcher) // Best effort.
	}()

	msg, err := NewMessage("/osc/address")
	if err != nil {
		t.Fatal(err)
	}
	if err := msg.WriteInt32(111); err != nil {
		t.Fatal(err)
	}
	if err := msg.WriteBool(true); err != nil {
		t.Fatal(err)
	}
	if err := msg.WriteString("hello"); err != nil {
		t.Fatal(err)
	}

	// Send a message.
	if err := client.Send(msg); err != nil {
		t.Fatal(err)
	}

	select {
	default:
	case err := <-errChan:
		if err != nil {
			t.Fatal(err)
		}
	}

	recvMsg := <-doneChan

	recvData, err := recvMsg.bytes()
	if err != nil {
		t.Fatal(err)
	}

	data, err := msg.bytes()
	if err != nil {
		t.Fatal(err)
	}

	if 0 != bytes.Compare(data, recvData[0:len(data)]) {
		t.Fatalf("Expected %s got %s", data, recvData)
	}
}
<commit_msg>clean up TestSend<commit_after>package osc

import (
	"bytes"
	"net"
	"testing"
)

func TestInvalidAddress(t *testing.T) {
	dispatcher := map[string]Method{
		"/address*/test": func(msg *Message) error {
			return nil
		},
	}
	laddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	server, err := ListenUDP("udp", laddr)
	if err != nil {
		t.Fatal(err)
	}
	defer func() { _ = server.Close() }() // Best effort.

	if err := server.Serve(dispatcher); err != ErrInvalidAddress {
		t.Fatal("expected invalid address error")
	}
	if server != nil {
		_ = server.Close()
	}
}

func TestMessageDispatching(t *testing.T) {
	// dispatcher := map[string]Method{
	// 	"/address/test": func(msg *Message) error {
	// 		val, err := msg.ReadInt32()
	// 		if err != nil {
	// 			return err
	// 		}
	// 		if expected, got := int32(1122), val; expected != got {
	// 			return fmt.Errorf("Expected %d got %d", expected, got)
	// 		}
	// 		return nil
	// 	},
	// }

	laddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}

	server, err := ListenUDP("udp", laddr)
	if err != nil {
		t.Fatal(err)
	}
	defer func() { _ = server.Close() }() // Best effort.
}

func TestSend(t *testing.T) {
	var (
		doneChan = make(chan *Message)
		errChan  = make(chan error, 1)
	)

	dispatcher := map[string]Method{
		"/osc/address": func(msg *Message) error {
			doneChan <- msg
			return nil
		},
	}

	laddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}

	server, err := ListenUDP("udp", laddr)
	if err != nil {
		t.Fatal(err)
	}
	defer func() { _ = server.Close() }() // Best effort.

	go func() {
		errChan <- server.Serve(dispatcher) // Best effort.
	}()

	serverAddr := server.LocalAddr()
	raddr, err := net.ResolveUDPAddr(serverAddr.Network(), serverAddr.String())
	if err != nil {
		t.Fatal(err)
	}

	client, err := DialUDP("udp", nil, raddr)
	if err != nil {
		t.Fatal(err)
	}

	msg, err := NewMessage("/osc/address")
	if err != nil {
		t.Fatal(err)
	}
	if err := msg.WriteInt32(111); err != nil {
		t.Fatal(err)
	}
	if err := msg.WriteBool(true); err != nil {
		t.Fatal(err)
	}
	if err := msg.WriteString("hello"); err != nil {
		t.Fatal(err)
	}

	// Send a message.
	if err := client.Send(msg); err != nil {
		t.Fatal(err)
	}

	select {
	default:
	case err := <-errChan:
		if err != nil {
			t.Fatal(err)
		}
	}

	recvMsg := <-doneChan

	recvData, err := recvMsg.bytes()
	if err != nil {
		t.Fatal(err)
	}

	data, err := msg.bytes()
	if err != nil {
		t.Fatal(err)
	}

	if 0 != bytes.Compare(data, recvData[0:len(data)]) {
		t.Fatalf("Expected %s got %s", data, recvData)
	}
}
<|endoftext|>


<commit_before>package wca

const (
	AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED       = 0x10000000
	AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE            = 0x20000000
	AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED = 0x40000000
)

const (
	AUDCLNT_STREAMOPTIONS_NONE = iota
	AUDCLNT_STREAMOPTIONS_RAW
	AUDCLNT_STREAMOPTIONS_MATCH_FORMAT
)

const (
	AudioCategory_Other = iota
	AudioCategory_ForegroundOnlyMedia
	AudioCategory_BackgroundCapableMedia
	AudioCategory_Communications
	AudioCategory_Alerts
	AudioCategory_SoundEffects
	AudioCategory_GameEffects
	AudioCategory_GameMedia
	AudioCategory_GameChat
	AudioCategory_Speech
	AudioCategory_Movie
	AudioCategory_Media
)

const (
	WAVE_FORMAT_PCM = 0x1
)

const (
	INFINITE = 0xFFFFFFFF
)

const (
	EConsole = iota
	EMultimedia
	ECommunications
	ERole_enum_count
)

const (
	DELETE       = 0x00010000
	READ_CONTROL = 0x00020000
	SYNCHRONIZE  = 0x00100000
	WRITE_DAC    = 0x00040000
	WRITE_OWNER  = 0x00080000
)

const (
	EVENT_ALL_ACCESS   = 0x1F0003
	EVENT_MODIFY_STATE = 0x0002
)

const (
	CREATE_EVENT_INITIAL_SET  = 0x00000002
	CREATE_EVENT_MANUAL_RESET = 0x00000001
)

const (
	AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY = 0x1
	AUDCLNT_BUFFERFLAGS_SILENT             = 0x2
	AUDCLNT_BUFFERFLAGS_TIMESTAMP_ERROR    = 0x4
)

const (
	AUDCLNT_STREAMFLAGS_CROSSPROCESS        = 0x00010000
	AUDCLNT_STREAMFLAGS_LOOPBACK            = 0x00020000
	AUDCLNT_STREAMFLAGS_EVENTCALLBACK       = 0x00040000
	AUDCLNT_STREAMFLAGS_NOPERSIST           = 0x00080000
	AUDCLNT_STREAMFLAGS_RATEADJUST          = 0x00100000
	AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM      = 0x80000000
	AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY = 0x08000000
)

const (
	AUDCLNT_SHAREMODE_SHARED = iota
	AUDCLNT_SHAREMODE_EXCLUSIVE
)

const (
	ENDPOINT_SYSFX_ENABLED = iota
	ENDPOINT_SYSFX_DISABLED
)

const (
	DEVICE_STATE_ACTIVE     = 0x00000001
	DEVICE_STATE_DISABLED   = 0x00000002
	DEVICE_STATE_NOTPRESENT = 0x00000004
	DEVICE_STATE_UNPLUGGED  = 0x00000008
	DEVICE_STATEMASK_ALL    = 0x0000000F
)

const (
	ERender = iota
	ECapture
	EAll
	EDataFlow_enum_count
)

const (
	STGM_READ       = 0x0
	STGM_WRITE      = 0x1
	STGM_READ_WRITE = 0x2
)

const (
	CLSCTX_INPROC_SERVER          = 0x1
	CLSCTX_INPROC_HANDLER         = 0x2
	CLSCTX_LOCAL_SERVER           = 0x4
	CLSCTX_INPROC_SERVER16        = 0x8
	CLSCTX_REMOTE_SERVER          = 0x10
	CLSCTX_INPROC_HANDLER16       = 0x20
	CLSCTX_RESERVED1              = 0x40
	CLSCTX_RESERVED2              = 0x80
	CLSCTX_RESERVED3              = 0x100
	CLSCTX_RESERVED4              = 0x200
	CLSCTX_NO_CODE_DOWNLOAD       = 0x400
	CLSCTX_RESERVED5              = 0x800
	CLSCTX_NO_CUSTOM_MARSHAL      = 0x1000
	CLSCTX_ENABLE_CODE_DOWNLOAD   = 0x2000
	CLSCTX_NO_FAILURE_LOG         = 0x4000
	CLSCTX_DISABLE_AAA            = 0x8000
	CLSCTX_ENABLE_AAA             = 0x10000
	CLSCTX_FROM_DEFAULT_CONTEXT   = 0x20000
	CLSCTX_ACTIVATE_32_BIT_SERVER = 0x40000
	CLSCTX_ACTIVATE_64_BIT_SERVER = 0x80000
	CLSCTX_ENABLE_CLOAKING        = 0x100000
	CLSCTX_APPCONTAINER           = 0x400000
	CLSCTX_ACTIVATE_AAA_AS_IU     = 0x800000
	CLSCTX_PS_DLL                 = 0x80000000
	CLSCTX_ALL                    = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER
)
<commit_msg>Add constants<commit_after>package wca

const (
	AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED       = 0x10000000
	AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE            = 0x20000000
	AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED = 0x40000000
)

const (
	AUDCLNT_STREAMOPTIONS_NONE = iota
	AUDCLNT_STREAMOPTIONS_RAW
	AUDCLNT_STREAMOPTIONS_MATCH_FORMAT
)

const (
	AudioCategory_Other = iota
	AudioCategory_ForegroundOnlyMedia
	AudioCategory_BackgroundCapableMedia
	AudioCategory_Communications
	AudioCategory_Alerts
	AudioCategory_SoundEffects
	AudioCategory_GameEffects
	AudioCategory_GameMedia
	AudioCategory_GameChat
	AudioCategory_Speech
	AudioCategory_Movie
	AudioCategory_Media
)

const (
	WAVE_FORMAT_PCM = 0x1
)

const (
	INFINITE = 0xFFFFFFFF
)

const (
	EConsole = iota
	EMultimedia
	ECommunications
	ERole_enum_count
)

const (
	DELETE       = 0x00010000
	READ_CONTROL = 0x00020000
	SYNCHRONIZE  = 0x00100000
	WRITE_DAC    = 0x00040000
	WRITE_OWNER  = 0x00080000
)

const (
	EVENT_ALL_ACCESS   = 0x1F0003
	EVENT_MODIFY_STATE = 0x0002
)

const (
	CREATE_EVENT_INITIAL_SET  = 0x00000002
	CREATE_EVENT_MANUAL_RESET = 0x00000001
)

const (
	AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY = 0x1
	AUDCLNT_BUFFERFLAGS_SILENT             = 0x2
	AUDCLNT_BUFFERFLAGS_TIMESTAMP_ERROR    = 0x4
)

const (
	AUDCLNT_STREAMFLAGS_CROSSPROCESS        = 0x00010000
	AUDCLNT_STREAMFLAGS_LOOPBACK            = 0x00020000
	AUDCLNT_STREAMFLAGS_EVENTCALLBACK       = 0x00040000
	AUDCLNT_STREAMFLAGS_NOPERSIST           = 0x00080000
	AUDCLNT_STREAMFLAGS_RATEADJUST          = 0x00100000
	AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM      = 0x80000000
	AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY = 0x08000000
)

const (
	AUDCLNT_SHAREMODE_SHARED = iota
	AUDCLNT_SHAREMODE_EXCLUSIVE
)

const (
	ENDPOINT_SYSFX_ENABLED = iota
	ENDPOINT_SYSFX_DISABLED
)

const (
	DEVICE_STATE_ACTIVE     = 0x00000001
	DEVICE_STATE_DISABLED   = 0x00000002
	DEVICE_STATE_NOTPRESENT = 0x00000004
	DEVICE_STATE_UNPLUGGED  = 0x00000008
	DEVICE_STATEMASK_ALL    = 0x0000000F
)

const (
	ERender = iota
	ECapture
	EAll
	EDataFlow_enum_count
)

const (
	STGM_READ       = 0x0
	STGM_WRITE      = 0x1
	STGM_READ_WRITE = 0x2
)

const (
	CLSCTX_INPROC_SERVER          = 0x1
	CLSCTX_INPROC_HANDLER         = 0x2
	CLSCTX_LOCAL_SERVER           = 0x4
	CLSCTX_INPROC_SERVER16        = 0x8
	CLSCTX_REMOTE_SERVER          = 0x10
	CLSCTX_INPROC_HANDLER16       = 0x20
	CLSCTX_RESERVED1              = 0x40
	CLSCTX_RESERVED2              = 0x80
	CLSCTX_RESERVED3              = 0x100
	CLSCTX_RESERVED4              = 0x200
	CLSCTX_NO_CODE_DOWNLOAD       = 0x400
	CLSCTX_RESERVED5              = 0x800
	CLSCTX_NO_CUSTOM_MARSHAL      = 0x1000
	CLSCTX_ENABLE_CODE_DOWNLOAD   = 0x2000
	CLSCTX_NO_FAILURE_LOG         = 0x4000
	CLSCTX_DISABLE_AAA            = 0x8000
	CLSCTX_ENABLE_AAA             = 0x10000
	CLSCTX_FROM_DEFAULT_CONTEXT   = 0x20000
	CLSCTX_ACTIVATE_32_BIT_SERVER = 0x40000
	CLSCTX_ACTIVATE_64_BIT_SERVER = 0x80000
	CLSCTX_ENABLE_CLOAKING        = 0x100000
	CLSCTX_APPCONTAINER           = 0x400000
	CLSCTX_ACTIVATE_AAA_AS_IU     = 0x800000
	CLSCTX_PS_DLL                 = 0x80000000
	CLSCTX_ALL                    = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER
)

const (
	AUDCLNT_E_NOT_INITIALIZED              = 0x001
	AUDCLNT_E_ALREADY_INITIALIZED          = 0x002
	AUDCLNT_E_WRONG_ENDPOINT_TYPE          = 0x003
	AUDCLNT_E_DEVICE_INVALIDATED           = 0x004
	AUDCLNT_E_NOT_STOPPED                  = 0x005
	AUDCLNT_E_BUFFER_TOO_LARGE             = 0x006
	AUDCLNT_E_OUT_OF_ORDER                 = 0x007
	AUDCLNT_E_UNSUPPORTED_FORMAT           = 0x008
	AUDCLNT_E_INVALID_SIZE                 = 0x009
	AUDCLNT_E_DEVICE_IN_USE                = 0x00a
	AUDCLNT_E_BUFFER_OPERATION_PENDING     = 0x00b
	AUDCLNT_E_THREAD_NOT_REGISTERED        = 0x00c
	AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED   = 0x00e
	AUDCLNT_E_ENDPOINT_CREATE_FAILED       = 0x00f
	AUDCLNT_E_SERVICE_NOT_RUNNING          = 0x010
	AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED     = 0x011
	AUDCLNT_E_EXCLUSIVE_MODE_ONLY          = 0x012
	AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL = 0x013
	AUDCLNT_E_EVENTHANDLE_NOT_SET          = 0x014
	AUDCLNT_E_INCORRECT_BUFFER_SIZE        = 0x015
	AUDCLNT_E_BUFFER_SIZE_ERROR            = 0x016
	AUDCLNT_E_CPUUSAGE_EXCEEDED            = 0x017
	AUDCLNT_E_BUFFER_ERROR                 = 0x018
	AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED      = 0x019
	AUDCLNT_E_INVALID_DEVICE_PERIOD        = 0x020
)
<|endoftext|>


<commit_before>/// Copyright (c) 2017 Intel Corporation
//
// 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 tests

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"
)

// Container represents a clear container
type Container struct {
	// Bundle contains the container information
	// if nil then try to run the container without --bundle option
	Bundle *Bundle

	// Console pty slave path
	// if nil then try to run the container without --console option
	Console *string

	// PidFile where process id is written
	// if nil then try to run the container without --pid-file option
	PidFile *string

	// Debug enables debug output
	Debug bool

	// LogFile where debug information is written
	// if nil then try to run the container without --log option
	LogFile *string

	// Detach allows to run the process detached from the shell
	Detach bool

	// ID of the container
	// if nil then try to run the container without container ID
	ID *string
}

// Process describes a process to be executed on a running container.
type Process struct {
	ContainerID *string
	Console     *string
	Tty         *string
	Detach      bool
	Workload    []string
}

// NewContainer returns a new Container
func NewContainer(workload []string, detach bool) (*Container, error) {
	b, err := NewBundle(workload)
	if err != nil {
		return nil, err
	}

	console := ""

	pidFile := filepath.Join(b.Path, "pid")
	logFile := filepath.Join(b.Path, "log")
	id := RandID(20)

	return &Container{
		Bundle:  b,
		Console: &console,
		PidFile: &pidFile,
		Debug:   true,
		LogFile: &logFile,
		Detach:  detach,
		ID:      &id,
	}, nil
}

// Run the container
// calls to run command returning its stdout, stderr and exit code
func (c *Container) Run() (bytes.Buffer, bytes.Buffer, int) {
	args := []string{}

	if c.Debug {
		args = append(args, "--debug")
	}

	if c.LogFile != nil {
		args = append(args, "--log", *c.LogFile)
	}

	args = append(args, "run")

	if c.Bundle != nil {
		args = append(args, "--bundle", c.Bundle.Path)
	}

	if c.Console != nil {
		args = append(args, "--console", *c.Console)
	}

	if c.PidFile != nil {
		args = append(args, "--pid-file", *c.PidFile)
	}

	if c.Detach {
		args = append(args, "--detach")
	}

	if c.ID != nil {
		args = append(args, *c.ID)
	}

	cmd := NewCommand(Runtime, args...)
	ret := cmd.Run()

	return cmd.Stdout, cmd.Stderr, ret
}

// Delete the container
// calls to delete command returning its stdout, stderr and exit code
func (c *Container) Delete(force bool) (bytes.Buffer, bytes.Buffer, int) {
	args := []string{"delete"}

	if force {
		args = append(args, "--force")
	}

	if c.ID != nil {
		args = append(args, *c.ID)
	}

	cmd := NewCommand(Runtime, args...)
	ret := cmd.Run()

	return cmd.Stdout, cmd.Stderr, ret
}

// Kill the container
// calls to kill command returning its stdout, stderr and exit code
func (c *Container) Kill(all bool, signal interface{}) (bytes.Buffer, bytes.Buffer, int) {
	args := []string{"kill"}

	if all {
		args = append(args, "--all")
	}

	if c.ID != nil {
		args = append(args, *c.ID)
	}

	switch t := signal.(type) {
	case syscall.Signal:
		args = append(args, strconv.Itoa(int(t)))
	case string:
		args = append(args, t)
	}

	cmd := NewCommand(Runtime, args...)
	ret := cmd.Run()

	return cmd.Stdout, cmd.Stderr, ret
}

// Exec the container
// calls into exec command returning its stdout, stderr and exit code
func (c *Container) Exec(process Process) (bytes.Buffer, bytes.Buffer, int) {
	args := []string{}

	if c.Debug {
		args = append(args, "--debug")
	}

	if c.LogFile != nil {
		args = append(args, "--log", *c.LogFile)
	}

	args = append(args, "exec")

	if process.Console != nil {
		args = append(args, "--console", *process.Console)
	}

	if process.Tty != nil {
		args = append(args, "--tty", *process.Tty)
	}

	if process.Detach {
		args = append(args, "--detach")
	}

	if process.ContainerID != nil {
		args = append(args, *process.ContainerID)
	}

	args = append(args, process.Workload...)

	cmd := NewCommand(Runtime, args...)
	ret := cmd.Run()

	return cmd.Stdout, cmd.Stderr, ret
}

// List the containers
// calls to list command returning its stdout, stderr and exit code
func (c *Container) List(format string, quiet bool, all bool) (bytes.Buffer, bytes.Buffer, int) {
	args := []string{"list"}

	if format != "" {
		args = append(args, "--format", format)
	}

	if quiet {
		args = append(args, "--quiet")
	}

	if all {
		args = append(args, "--all")
	}

	cmd := NewCommand(Runtime, args...)
	ret := cmd.Run()

	return cmd.Stdout, cmd.Stderr, ret
}

// SetWorkload sets a workload for the container
func (c *Container) SetWorkload(workload []string) error {
	c.Bundle.Config.Process.Args = workload
	return c.Bundle.Save()
}

// RemoveOption removes a specific option
// container will run without the specific option
func (c *Container) RemoveOption(option string) error {
	switch option {
	case "--bundle", "-b":
		defer c.Bundle.Remove()
		c.Bundle = nil
	case "--console":
		c.Console = nil
	case "--pid-file":
		c.PidFile = nil
	default:
		return fmt.Errorf("undefined option '%s'", option)
	}

	return nil
}

// Cleanup removes files and directories created by the container
// returns an error if a file or directory can not be removed
func (c *Container) Cleanup() error {
	if c.Bundle != nil {
		return c.Bundle.Remove()
	}

	return nil
}

// Exist returns true if any of next cases is true:
// - list command shows the container
// - the process id specified in the pid file is running (cc-shim)
// - the VM is running (qemu)
// else false is returned
func (c *Container) Exist() bool {
	return c.isListed() || c.isWorkloadRunning() || c.isVMRunning()
}

func (c *Container) isListed() bool {
	if c.ID == nil {
		return false
	}

	stdout, _, ret := c.List("", true, false)
	if ret != 0 {
		return false
	}

	return strings.Contains(stdout.String(), *c.ID)
}

func (c *Container) isWorkloadRunning() bool {
	if c.PidFile == nil {
		return false
	}

	content, err := ioutil.ReadFile(*c.PidFile)
	if err != nil {
		return false
	}

	if _, err := os.Stat(fmt.Sprintf("/proc/%s/stat", string(content))); os.IsNotExist(err) {
		return false
	}

	return true
}

func (c *Container) isVMRunning() bool {
	// FIXME: find a way to check if the VM is still running
	return false
}
<commit_msg>tests: fix container.go<commit_after>/// Copyright (c) 2017 Intel Corporation
//
// 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 tests

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"
)

// Container represents a clear container
type Container struct {
	// Bundle contains the container information
	// if nil then try to run the container without --bundle option
	Bundle *Bundle

	// Console pty slave path
	// if nil then try to run the container without --console option
	Console *string

	// PidFile where process id is written
	// if nil then try to run the container without --pid-file option
	PidFile *string

	// Debug enables debug output
	Debug bool

	// LogFile where debug information is written
	// if nil then try to run the container without --log option
	LogFile *string

	// Detach allows to run the process detached from the shell
	Detach bool

	// ID of the container
	// if nil then try to run the container without container ID
	ID *string
}

// Process describes a process to be executed on a running container.
type Process struct {
	ContainerID *string
	Console     *string
	Tty         *string
	Detach      bool
	Workload    []string
}

// NewContainer returns a new Container
func NewContainer(workload []string, detach bool) (*Container, error) {
	b, err := NewBundle(workload)
	if err != nil {
		return nil, err
	}

	console := ""

	pidFile := filepath.Join(b.Path, "pid")
	logFile := filepath.Join(b.Path, "log")
	id := RandID(20)

	return &Container{
		Bundle:  b,
		Console: &console,
		PidFile: &pidFile,
		Debug:   true,
		LogFile: &logFile,
		Detach:  detach,
		ID:      &id,
	}, nil
}

// Run the container
// calls to run command returning its stdout, stderr and exit code
func (c *Container) Run() (string, string, int) {
	args := []string{}

	if c.Debug {
		args = append(args, "--debug")
	}

	if c.LogFile != nil {
		args = append(args, "--log", *c.LogFile)
	}

	args = append(args, "run")

	if c.Bundle != nil {
		args = append(args, "--bundle", c.Bundle.Path)
	}

	if c.Console != nil {
		args = append(args, "--console", *c.Console)
	}

	if c.PidFile != nil {
		args = append(args, "--pid-file", *c.PidFile)
	}

	if c.Detach {
		args = append(args, "--detach")
	}

	if c.ID != nil {
		args = append(args, *c.ID)
	}

	cmd := NewCommand(Runtime, args...)

	return cmd.Run()
}

// Delete the container
// calls to delete command returning its stdout, stderr and exit code
func (c *Container) Delete(force bool) (string, string, int) {
	args := []string{"delete"}

	if force {
		args = append(args, "--force")
	}

	if c.ID != nil {
		args = append(args, *c.ID)
	}

	cmd := NewCommand(Runtime, args...)

	return cmd.Run()
}

// Kill the container
// calls to kill command returning its stdout, stderr and exit code
func (c *Container) Kill(all bool, signal interface{}) (string, string, int) {
	args := []string{"kill"}

	if all {
		args = append(args, "--all")
	}

	if c.ID != nil {
		args = append(args, *c.ID)
	}

	switch t := signal.(type) {
	case syscall.Signal:
		args = append(args, strconv.Itoa(int(t)))
	case string:
		args = append(args, t)
	}

	cmd := NewCommand(Runtime, args...)

	return cmd.Run()
}

// Exec the container
// calls into exec command returning its stdout, stderr and exit code
func (c *Container) Exec(process Process) (string, string, int) {
	args := []string{}

	if c.Debug {
		args = append(args, "--debug")
	}

	if c.LogFile != nil {
		args = append(args, "--log", *c.LogFile)
	}

	args = append(args, "exec")

	if process.Console != nil {
		args = append(args, "--console", *process.Console)
	}

	if process.Tty != nil {
		args = append(args, "--tty", *process.Tty)
	}

	if process.Detach {
		args = append(args, "--detach")
	}

	if process.ContainerID != nil {
		args = append(args, *process.ContainerID)
	}

	args = append(args, process.Workload...)

	cmd := NewCommand(Runtime, args...)

	return cmd.Run()
}

// List the containers
// calls to list command returning its stdout, stderr and exit code
func (c *Container) List(format string, quiet bool, all bool) (string, string, int) {
	args := []string{"list"}

	if format != "" {
		args = append(args, "--format", format)
	}

	if quiet {
		args = append(args, "--quiet")
	}

	if all {
		args = append(args, "--all")
	}

	cmd := NewCommand(Runtime, args...)

	return cmd.Run()
}

// SetWorkload sets a workload for the container
func (c *Container) SetWorkload(workload []string) error {
	c.Bundle.Config.Process.Args = workload
	return c.Bundle.Save()
}

// RemoveOption removes a specific option
// container will run without the specific option
func (c *Container) RemoveOption(option string) error {
	switch option {
	case "--bundle", "-b":
		defer c.Bundle.Remove()
		c.Bundle = nil
	case "--console":
		c.Console = nil
	case "--pid-file":
		c.PidFile = nil
	default:
		return fmt.Errorf("undefined option '%s'", option)
	}

	return nil
}

// Cleanup removes files and directories created by the container
// returns an error if a file or directory can not be removed
func (c *Container) Cleanup() error {
	if c.Bundle != nil {
		return c.Bundle.Remove()
	}

	return nil
}

// Exist returns true if any of next cases is true:
// - list command shows the container
// - the process id specified in the pid file is running (cc-shim)
// - the VM is running (qemu)
// else false is returned
func (c *Container) Exist() bool {
	return c.isListed() || c.isWorkloadRunning() || c.isVMRunning()
}

func (c *Container) isListed() bool {
	if c.ID == nil {
		return false
	}

	stdout, _, ret := c.List("", true, false)
	if ret != 0 {
		return false
	}

	return strings.Contains(stdout, *c.ID)
}

func (c *Container) isWorkloadRunning() bool {
	if c.PidFile == nil {
		return false
	}

	content, err := ioutil.ReadFile(*c.PidFile)
	if err != nil {
		return false
	}

	if _, err := os.Stat(fmt.Sprintf("/proc/%s/stat", string(content))); os.IsNotExist(err) {
		return false
	}

	return true
}

func (c *Container) isVMRunning() bool {
	// FIXME: find a way to check if the VM is still running
	return false
}
<|endoftext|>


<commit_before>package garden

import (
	"io"
)

//go:generate counterfeiter . Container

type Container interface {
	Handle() string

	// Stop stops a container.
	//
	// If kill is false, garden stops a container by sending the processes running inside it the SIGTERM signal.
	// It then waits for the processes to terminate before returning a response.
	// If one or more processes do not terminate within 10 seconds,
	// garden sends these processes the SIGKILL signal, killing them ungracefully.
	//
	// If kill is true, garden stops a container by sending the processing running inside it a SIGKILL signal.
	//
	// Once a container is stopped, garden does not allow spawning new processes inside the container.
	// It is possible to copy files in to and out of a stopped container.
	// It is only when a container is destroyed that its filesystem is cleaned up.
	//
	// Errors:
	// * None.
	Stop(kill bool) error

	// Returns information about a container.
	Info() (ContainerInfo, error)

	// StreamIn streams data into a file in a container.
	//
	// Errors:
	// *  TODO.
	StreamIn(dstPath string, tarStream io.Reader) error

	// StreamOut streams a file out of a container.
	//
	// Errors:
	// * TODO.
	StreamOut(srcPath string) (io.ReadCloser, error)

	// Limits the network bandwidth for a container.
	LimitBandwidth(limits BandwidthLimits) error

	CurrentBandwidthLimits() (BandwidthLimits, error)

	// Limits the CPU shares for a container.
	LimitCPU(limits CPULimits) error

	CurrentCPULimits() (CPULimits, error)

	// Limits the disk usage for a container.
	//
	// The disk limits that are set by this command only have effect for the container's unprivileged user.
	// Files/directories created by its privileged user are not subject to these limits.
	//
	// TODO: explain how disk management works.
	LimitDisk(limits DiskLimits) error
	CurrentDiskLimits() (DiskLimits, error)

	// Limits the memory usage for a container.
	//
	// The limit applies to all process in the container. When the limit is
	// exceeded, the container will be automatically stopped.
	//
	// Errors:
	// * The kernel does not support setting memory.memsw.limit_in_bytes.
	LimitMemory(limits MemoryLimits) error

	CurrentMemoryLimits() (MemoryLimits, error)

	// Map a port on the host to a port in the container so that traffic to the
	// host port is forwarded to the container port.
	//
	// If a host port is not given, a port will be acquired from the server's port
	// pool.
	//
	// If a container port is not given, the port will be the same as the
	// container port.
	//
	// The two resulting ports are returned in the response.
	//
	// Errors:
	// * When no port can be acquired from the server's port pool.
	NetIn(hostPort, containerPort uint32) (uint32, uint32, error)

	// Whitelist outbound network traffic.
	//
	// If the configuration directive deny_networks is not used,
	// all networks are already whitelisted and this command is effectively a no-op.
	//
	// Later NetOut calls take precedence over earlier calls, which is
	// significant only in relation to logging.
	//
	// Errors:
	// * An error is returned if the NetOut call fails.
	NetOut(netOutRule NetOutRule) error

	// Run a script inside a container.
	//
	// The root user will be mapped to a non-root UID in the host unless the container (not this process) was created with 'privileged' true.
	//
	// Errors:
	// * TODO.
	Run(ProcessSpec, ProcessIO) (Process, error)

	// Attach starts streaming the output back to the client from a specified process.
	//
	// Errors:
	// * processID does not refer to a running process.
	Attach(processID uint32, io ProcessIO) (Process, error)

	// Metrics returns the current set of metrics for a container
	Metrics() (Metrics, error)

	// Properties returns the current set of properties
	Properties() (Properties, error)

	// Property returns the value of the property with the specified name.
	//
	// Errors:
	// * When the property does not exist on the container.
	Property(name string) (string, error)

	// Set a named property on a container to a specified value.
	//
	// Errors:
	// * None.
	SetProperty(name string, value string) error

	// Remove a property with the specified name from a container.
	//
	// Errors:
	// * None.
	RemoveProperty(name string) error
}

// ProcessSpec contains parameters for running a script inside a container.
type ProcessSpec struct {
	// Path to command to execute.
	Path string `json:"path,omitempty"`

	// Arguments to pass to command.
	Args []string `json:"args,omitempty"`

	// Environment variables.
	Env []string `json:"env,omitempty"`

	// Working directory (default: home directory).
	Dir string `json:"dir,omitempty"`

	// The name of a user in the container to run the process as.
	User string `json:"user,omitempty"`

	// Resource limits
	Limits ResourceLimits `json:"rlimits,omitempty"`

	// Execute with a TTY for stdio.
	TTY *TTYSpec `json:"tty,omitempty"`
}

type TTYSpec struct {
	WindowSize *WindowSize `json:"window_size,omitempty"`
}

type WindowSize struct {
	Columns int `json:"columns,omitempty"`
	Rows    int `json:"rows,omitempty"`
}

type ProcessIO struct {
	Stdin  io.Reader
	Stdout io.Writer
	Stderr io.Writer
}

//go:generate counterfeiter . Process

type Process interface {
	ID() uint32
	Wait() (int, error)
	SetTTY(TTYSpec) error
	Signal(Signal) error
}

type Signal int

const (
	SignalTerminate Signal = iota
	SignalKill
)

type PortMapping struct {
	HostPort      uint32
	ContainerPort uint32
}

// ContainerInfo holds information about a container.
type ContainerInfo struct {
	State         string        // Either "active" or "stopped".
	Events        []string      // List of events that occurred for the container. It currently includes only "oom" (Out Of Memory) event if it occurred.
	HostIP        string        // The IP address of the gateway which controls the host side of the container's virtual ethernet pair.
	ContainerIP   string        // The IP address of the container side of the container's virtual ethernet pair.
	ExternalIP    string        //
	ContainerPath string        // The path to the directory holding the container's files (both its control scripts and filesystem).
	ProcessIDs    []uint32      // List of running processes.
	Properties    Properties    // List of properties defined for the container.
	MappedPorts   []PortMapping //
}

func NewError(msg string) *Error {
	return &Error{msg}
}

type Error struct {
	ErrorMsg string `json:"error_msg"`
}

func (e *Error) Error() string {
	return e.ErrorMsg
}

type ContainerInfoEntry struct {
	Info ContainerInfo
	Err  *Error
}

type Metrics struct {
	MemoryStat ContainerMemoryStat
	CPUStat    ContainerCPUStat
	DiskStat   ContainerDiskStat
}

type ContainerMetricsEntry struct {
	Metrics Metrics
	Err     *Error
}

type ContainerMemoryStat struct {
	Cache                   uint64
	Rss                     uint64
	MappedFile              uint64
	Pgpgin                  uint64
	Pgpgout                 uint64
	Swap                    uint64
	Pgfault                 uint64
	Pgmajfault              uint64
	InactiveAnon            uint64
	ActiveAnon              uint64
	InactiveFile            uint64
	ActiveFile              uint64
	Unevictable             uint64
	HierarchicalMemoryLimit uint64
	HierarchicalMemswLimit  uint64
	TotalCache              uint64
	TotalRss                uint64
	TotalMappedFile         uint64
	TotalPgpgin             uint64
	TotalPgpgout            uint64
	TotalSwap               uint64
	TotalPgfault            uint64
	TotalPgmajfault         uint64
	TotalInactiveAnon       uint64
	TotalActiveAnon         uint64
	TotalInactiveFile       uint64
	TotalActiveFile         uint64
	TotalUnevictable        uint64
	// A memory usage total which reports memory usage in the same way that limits are enforced.
	// This value includes memory consumed by nested containers.
	TotalUsageTowardLimit uint64
}

type ContainerCPUStat struct {
	Usage  uint64
	User   uint64
	System uint64
}

type ContainerDiskStat struct {
	BytesUsed  uint64
	InodesUsed uint64
}

type ContainerBandwidthStat struct {
	InRate   uint64
	InBurst  uint64
	OutRate  uint64
	OutBurst uint64
}

type BandwidthLimits struct {
	RateInBytesPerSecond      uint64 `json:"rate,omitempty"`
	BurstRateInBytesPerSecond uint64 `json:"burst,omitempty"`
}

type DiskLimits struct {
	BlockSoft uint64 `json:"block_soft,omitempty"`
	BlockHard uint64 `json:"block_hard,omitempty"`

	InodeSoft uint64 `json:"inode_soft,omitempty"`
	InodeHard uint64 `json:"inode_hard,omitempty"`

	// New soft block limit specified in bytes. Only has effect when BlockSoft is not specified.
	ByteSoft uint64 `json:"byte_soft,omitempty"`

	// New hard block limit specified in bytes. Only has effect when BlockHard is not specified.
	ByteHard uint64 `json:"byte_hard,omitempty"`
}

type MemoryLimits struct {
	//	Memory usage limit in bytes.
	LimitInBytes uint64 `json:"limit_in_bytes,omitempty"`
}

type CPULimits struct {
	LimitInShares uint64 `json:"limit_in_shares,omitempty"`
}

// Resource limits.
//
// Please refer to the manual page of getrlimit for a description of the individual fields:
// http://www.kernel.org/doc/man-pages/online/pages/man2/getrlimit.2.html
type ResourceLimits struct {
	As         *uint64 `json:"as,omitempty"`
	Core       *uint64 `json:"core,omitempty"`
	Cpu        *uint64 `json:"cpu,omitempty"`
	Data       *uint64 `json:"data,omitempty"`
	Fsize      *uint64 `json:"fsize,omitempty"`
	Locks      *uint64 `json:"locks,omitempty"`
	Memlock    *uint64 `json:"memlock,omitempty"`
	Msgqueue   *uint64 `json:"msgqueue,omitempty"`
	Nice       *uint64 `json:"nice,omitempty"`
	Nofile     *uint64 `json:"nofile,omitempty"`
	Nproc      *uint64 `json:"nproc,omitempty"`
	Rss        *uint64 `json:"rss,omitempty"`
	Rtprio     *uint64 `json:"rtprio,omitempty"`
	Sigpending *uint64 `json:"sigpending,omitempty"`
	Stack      *uint64 `json:"stack,omitempty"`
}
<commit_msg>whitespace<commit_after>package garden

import (
	"io"
)

//go:generate counterfeiter . Container

type Container interface {
	Handle() string

	// Stop stops a container.
	//
	// If kill is false, garden stops a container by sending the processes running inside it the SIGTERM signal.
	// It then waits for the processes to terminate before returning a response.
	// If one or more processes do not terminate within 10 seconds,
	// garden sends these processes the SIGKILL signal, killing them ungracefully.
	//
	// If kill is true, garden stops a container by sending the processing running inside it a SIGKILL signal.
	//
	// Once a container is stopped, garden does not allow spawning new processes inside the container.
	// It is possible to copy files in to and out of a stopped container.
	// It is only when a container is destroyed that its filesystem is cleaned up.
	//
	// Errors:
	// * None.
	Stop(kill bool) error

	// Returns information about a container.
	Info() (ContainerInfo, error)

	// StreamIn streams data into a file in a container.
	//
	// Errors:
	// *  TODO.
	StreamIn(dstPath string, tarStream io.Reader) error

	// StreamOut streams a file out of a container.
	//
	// Errors:
	// * TODO.
	StreamOut(srcPath string) (io.ReadCloser, error)

	// Limits the network bandwidth for a container.
	LimitBandwidth(limits BandwidthLimits) error

	CurrentBandwidthLimits() (BandwidthLimits, error)

	// Limits the CPU shares for a container.
	LimitCPU(limits CPULimits) error

	CurrentCPULimits() (CPULimits, error)

	// Limits the disk usage for a container.
	//
	// The disk limits that are set by this command only have effect for the container's unprivileged user.
	// Files/directories created by its privileged user are not subject to these limits.
	//
	// TODO: explain how disk management works.
	LimitDisk(limits DiskLimits) error

	CurrentDiskLimits() (DiskLimits, error)

	// Limits the memory usage for a container.
	//
	// The limit applies to all process in the container. When the limit is
	// exceeded, the container will be automatically stopped.
	//
	// Errors:
	// * The kernel does not support setting memory.memsw.limit_in_bytes.
	LimitMemory(limits MemoryLimits) error

	CurrentMemoryLimits() (MemoryLimits, error)

	// Map a port on the host to a port in the container so that traffic to the
	// host port is forwarded to the container port.
	//
	// If a host port is not given, a port will be acquired from the server's port
	// pool.
	//
	// If a container port is not given, the port will be the same as the
	// container port.
	//
	// The two resulting ports are returned in the response.
	//
	// Errors:
	// * When no port can be acquired from the server's port pool.
	NetIn(hostPort, containerPort uint32) (uint32, uint32, error)

	// Whitelist outbound network traffic.
	//
	// If the configuration directive deny_networks is not used,
	// all networks are already whitelisted and this command is effectively a no-op.
	//
	// Later NetOut calls take precedence over earlier calls, which is
	// significant only in relation to logging.
	//
	// Errors:
	// * An error is returned if the NetOut call fails.
	NetOut(netOutRule NetOutRule) error

	// Run a script inside a container.
	//
	// The root user will be mapped to a non-root UID in the host unless the container (not this process) was created with 'privileged' true.
	//
	// Errors:
	// * TODO.
	Run(ProcessSpec, ProcessIO) (Process, error)

	// Attach starts streaming the output back to the client from a specified process.
	//
	// Errors:
	// * processID does not refer to a running process.
	Attach(processID uint32, io ProcessIO) (Process, error)

	// Metrics returns the current set of metrics for a container
	Metrics() (Metrics, error)

	// Properties returns the current set of properties
	Properties() (Properties, error)

	// Property returns the value of the property with the specified name.
	//
	// Errors:
	// * When the property does not exist on the container.
	Property(name string) (string, error)

	// Set a named property on a container to a specified value.
	//
	// Errors:
	// * None.
	SetProperty(name string, value string) error

	// Remove a property with the specified name from a container.
	//
	// Errors:
	// * None.
	RemoveProperty(name string) error
}

// ProcessSpec contains parameters for running a script inside a container.
type ProcessSpec struct {
	// Path to command to execute.
	Path string `json:"path,omitempty"`

	// Arguments to pass to command.
	Args []string `json:"args,omitempty"`

	// Environment variables.
	Env []string `json:"env,omitempty"`

	// Working directory (default: home directory).
	Dir string `json:"dir,omitempty"`

	// The name of a user in the container to run the process as.
	User string `json:"user,omitempty"`

	// Resource limits
	Limits ResourceLimits `json:"rlimits,omitempty"`

	// Execute with a TTY for stdio.
	TTY *TTYSpec `json:"tty,omitempty"`
}

type TTYSpec struct {
	WindowSize *WindowSize `json:"window_size,omitempty"`
}

type WindowSize struct {
	Columns int `json:"columns,omitempty"`
	Rows    int `json:"rows,omitempty"`
}

type ProcessIO struct {
	Stdin  io.Reader
	Stdout io.Writer
	Stderr io.Writer
}

//go:generate counterfeiter . Process

type Process interface {
	ID() uint32
	Wait() (int, error)
	SetTTY(TTYSpec) error
	Signal(Signal) error
}

type Signal int

const (
	SignalTerminate Signal = iota
	SignalKill
)

type PortMapping struct {
	HostPort      uint32
	ContainerPort uint32
}

// ContainerInfo holds information about a container.
type ContainerInfo struct {
	State         string        // Either "active" or "stopped".
	Events        []string      // List of events that occurred for the container. It currently includes only "oom" (Out Of Memory) event if it occurred.
	HostIP        string        // The IP address of the gateway which controls the host side of the container's virtual ethernet pair.
	ContainerIP   string        // The IP address of the container side of the container's virtual ethernet pair.
	ExternalIP    string        //
	ContainerPath string        // The path to the directory holding the container's files (both its control scripts and filesystem).
	ProcessIDs    []uint32      // List of running processes.
	Properties    Properties    // List of properties defined for the container.
	MappedPorts   []PortMapping //
}

func NewError(msg string) *Error {
	return &Error{msg}
}

type Error struct {
	ErrorMsg string `json:"error_msg"`
}

func (e *Error) Error() string {
	return e.ErrorMsg
}

type ContainerInfoEntry struct {
	Info ContainerInfo
	Err  *Error
}

type Metrics struct {
	MemoryStat ContainerMemoryStat
	CPUStat    ContainerCPUStat
	DiskStat   ContainerDiskStat
}

type ContainerMetricsEntry struct {
	Metrics Metrics
	Err     *Error
}

type ContainerMemoryStat struct {
	Cache                   uint64
	Rss                     uint64
	MappedFile              uint64
	Pgpgin                  uint64
	Pgpgout                 uint64
	Swap                    uint64
	Pgfault                 uint64
	Pgmajfault              uint64
	InactiveAnon            uint64
	ActiveAnon              uint64
	InactiveFile            uint64
	ActiveFile              uint64
	Unevictable             uint64
	HierarchicalMemoryLimit uint64
	HierarchicalMemswLimit  uint64
	TotalCache              uint64
	TotalRss                uint64
	TotalMappedFile         uint64
	TotalPgpgin             uint64
	TotalPgpgout            uint64
	TotalSwap               uint64
	TotalPgfault            uint64
	TotalPgmajfault         uint64
	TotalInactiveAnon       uint64
	TotalActiveAnon         uint64
	TotalInactiveFile       uint64
	TotalActiveFile         uint64
	TotalUnevictable        uint64
	// A memory usage total which reports memory usage in the same way that limits are enforced.
	// This value includes memory consumed by nested containers.
	TotalUsageTowardLimit uint64
}

type ContainerCPUStat struct {
	Usage  uint64
	User   uint64
	System uint64
}

type ContainerDiskStat struct {
	BytesUsed  uint64
	InodesUsed uint64
}

type ContainerBandwidthStat struct {
	InRate   uint64
	InBurst  uint64
	OutRate  uint64
	OutBurst uint64
}

type BandwidthLimits struct {
	RateInBytesPerSecond      uint64 `json:"rate,omitempty"`
	BurstRateInBytesPerSecond uint64 `json:"burst,omitempty"`
}

type DiskLimits struct {
	BlockSoft uint64 `json:"block_soft,omitempty"`
	BlockHard uint64 `json:"block_hard,omitempty"`

	InodeSoft uint64 `json:"inode_soft,omitempty"`
	InodeHard uint64 `json:"inode_hard,omitempty"`

	// New soft block limit specified in bytes. Only has effect when BlockSoft is not specified.
	ByteSoft uint64 `json:"byte_soft,omitempty"`

	// New hard block limit specified in bytes. Only has effect when BlockHard is not specified.
	ByteHard uint64 `json:"byte_hard,omitempty"`
}

type MemoryLimits struct {
	//	Memory usage limit in bytes.
	LimitInBytes uint64 `json:"limit_in_bytes,omitempty"`
}

type CPULimits struct {
	LimitInShares uint64 `json:"limit_in_shares,omitempty"`
}

// Resource limits.
//
// Please refer to the manual page of getrlimit for a description of the individual fields:
// http://www.kernel.org/doc/man-pages/online/pages/man2/getrlimit.2.html
type ResourceLimits struct {
	As         *uint64 `json:"as,omitempty"`
	Core       *uint64 `json:"core,omitempty"`
	Cpu        *uint64 `json:"cpu,omitempty"`
	Data       *uint64 `json:"data,omitempty"`
	Fsize      *uint64 `json:"fsize,omitempty"`
	Locks      *uint64 `json:"locks,omitempty"`
	Memlock    *uint64 `json:"memlock,omitempty"`
	Msgqueue   *uint64 `json:"msgqueue,omitempty"`
	Nice       *uint64 `json:"nice,omitempty"`
	Nofile     *uint64 `json:"nofile,omitempty"`
	Nproc      *uint64 `json:"nproc,omitempty"`
	Rss        *uint64 `json:"rss,omitempty"`
	Rtprio     *uint64 `json:"rtprio,omitempty"`
	Sigpending *uint64 `json:"sigpending,omitempty"`
	Stack      *uint64 `json:"stack,omitempty"`
}
<|endoftext|>


<commit_before>// Copyright (C) 2019-2022, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package throttling

import (
	"fmt"
	"time"

	"github.com/prometheus/client_golang/prometheus"

	"golang.org/x/net/context"

	"github.com/ava-labs/avalanchego/ids"
	"github.com/ava-labs/avalanchego/snow/networking/tracker"
	"github.com/ava-labs/avalanchego/snow/validators"
	"github.com/ava-labs/avalanchego/utils/timer/mockable"
	"github.com/ava-labs/avalanchego/utils/wrappers"
)

const epsilon = time.Millisecond

var (
	_ CPUThrottler = &cpuThrottler{}
	_ CPUThrottler = &noCPUThrottler{}
)

// CPUThrottler rate-limits based on the CPU usage caused by each peer.
// We will not read messages from peers whose messages cause excessive
// CPU usage until the CPU usage caused by the peer drops to an acceptable level.
type CPUThrottler interface {
	// Blocks until we can read a message from the given peer.
	// If [ctx] is canceled, returns immediately.
	Acquire(ctx context.Context, nodeID ids.NodeID)
}

// A CPU throttler that always immediately returns on [Acquire].
type noCPUThrottler struct{}

func (t *noCPUThrottler) Acquire(context.Context, ids.NodeID) {}

type CPUThrottlerConfig struct {
	Clock mockable.Clock `json:"-"`
	// The maximum amount of time we'll wait before
	// re-checking whether a call to [Acquire] can return.
	MaxRecheckDelay time.Duration `json:"maxRecheckDelay"`
}

type cpuThrottler struct {
	CPUThrottlerConfig
	metrics *cpuThrottlerMetrics
	// Tells us the target CPU utilization of each node.
	cpuTargeter tracker.CPUTargeter
	// Tells us CPU utilization of each node.
	cpuTracker tracker.TimeTracker
}

type cpuThrottlerMetrics struct {
	totalWaits      prometheus.Counter
	totalNoWaits    prometheus.Counter
	awaitingAcquire prometheus.Gauge
}

func newCPUThrottlerMetrics(namespace string, reg prometheus.Registerer) (*cpuThrottlerMetrics, error) {
	m := &cpuThrottlerMetrics{
		totalWaits: prometheus.NewCounter(prometheus.CounterOpts{
			Namespace: namespace,
			Name:      "cpu_throttler_total_waits",
			Help:      "Number of times we've waited to read a message from a node because their CPU usage was too high",
		}),
		totalNoWaits: prometheus.NewCounter(prometheus.CounterOpts{
			Namespace: namespace,
			Name:      "cpu_throttler_total_no_waits",
			Help:      "Number of times we didn't wait to read a message due to their CPU usage being too high",
		}),
		awaitingAcquire: prometheus.NewGauge(prometheus.GaugeOpts{
			Namespace: namespace,
			Name:      "cpu_throttler_awaiting_acquire",
			Help:      "Number of nodes we're waiting to read a message from because their CPU usage is too high",
		}),
	}
	errs := wrappers.Errs{}
	errs.Add(
		reg.Register(m.totalWaits),
		reg.Register(m.totalNoWaits),
		reg.Register(m.awaitingAcquire),
	)
	return m, errs.Err
}

func NewCPUThrottler(
	namespace string,
	reg prometheus.Registerer,
	config CPUThrottlerConfig,
	vdrs validators.Set,
	cpuTracker tracker.TimeTracker,
	cpuTargeter tracker.CPUTargeter,
) (CPUThrottler, error) {
	metrics, err := newCPUThrottlerMetrics(namespace, reg)
	if err != nil {
		return nil, fmt.Errorf("couldn't initialize CPU throttler metrics: %w", err)
	}
	return &cpuThrottler{
		metrics:            metrics,
		CPUThrottlerConfig: config,
		cpuTargeter:        cpuTargeter,
		cpuTracker:         cpuTracker,
	}, nil
}

func (t *cpuThrottler) Acquire(ctx context.Context, nodeID ids.NodeID) {
	// Fires when we should re-check whether this node's CPU usage
	// has fallen to an acceptable level.
	timer := time.NewTimer(0)
	if !timer.Stop() {
		<-timer.C
	}
	defer timer.Stop()

	// [waited] is true if we waited for this node's CPU usage
	// to fall to an acceptable level before returning
	waited := false
	// Note that we increment [numWaiting] here even though
	// we might not actually wait. In this case, [numWaiting]
	// will be decremented pretty much immediately.
	// Technically this causes this metric to be incorrect for
	// a small duration, but doing it like this makes the code cleaner.
	t.metrics.awaitingAcquire.Inc()
	defer func() {
		t.metrics.awaitingAcquire.Dec()
		if waited {
			t.metrics.totalWaits.Inc()
		} else {
			t.metrics.totalNoWaits.Inc()
		}
	}()

	for {
		now := t.Clock.Time()
		// Get target CPU usage for this node.
		targetVdrCPU, targetAtLargeCPU, _ := t.cpuTargeter.TargetCPUUsage(nodeID)
		targetCPU := targetVdrCPU + targetAtLargeCPU
		// Get actual CPU usage for this node.
		actualCPU := t.cpuTracker.Utilization(nodeID, now)
		if actualCPU <= targetCPU {
			return
		}
		// See how long it will take for actual CPU usage to drop to target,
		// assuming this node uses no more CPU.
		waitDuration := t.cpuTracker.TimeUntilUtilization(nodeID, now, targetCPU)
		if waitDuration < epsilon {
			// If the amount of time until we reach the CPU target is very small,
			// just return to avoid a situation where we excessively re-check.
			return
		}
		if waitDuration > t.MaxRecheckDelay {
			// Re-check at least every [t.MaxRecheckDelay] in case it will be a
			// very long time until CPU usage reaches the target level.
			//
			// Note that not only can a node's CPU usage decrease over time, but
			// also its target CPU usage may increase.
			// In this case, the node's CPU usage can drop to the target level
			// sooner than [waitDuration] because the target has increased.
			// The minimum re-check frequency accounts for that case by
			// optimistically re-checking whether the node's CPU usage is now at
			// an acceptable level.
			waitDuration = t.MaxRecheckDelay
		}
		waited = true
		timer.Reset(waitDuration)
		select {
		case <-ctx.Done():
			return
		case <-timer.C:
		}
	}
}
<commit_msg>Improve cpu throttler awaiting acquire metric accuracy (#1479)<commit_after>// Copyright (C) 2019-2022, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package throttling

import (
	"fmt"
	"time"

	"github.com/prometheus/client_golang/prometheus"

	"golang.org/x/net/context"

	"github.com/ava-labs/avalanchego/ids"
	"github.com/ava-labs/avalanchego/snow/networking/tracker"
	"github.com/ava-labs/avalanchego/snow/validators"
	"github.com/ava-labs/avalanchego/utils/timer/mockable"
	"github.com/ava-labs/avalanchego/utils/wrappers"
)

const epsilon = time.Millisecond

var (
	_ CPUThrottler = &cpuThrottler{}
	_ CPUThrottler = &noCPUThrottler{}
)

// CPUThrottler rate-limits based on the CPU usage caused by each peer.
// We will not read messages from peers whose messages cause excessive
// CPU usage until the CPU usage caused by the peer drops to an acceptable level.
type CPUThrottler interface {
	// Blocks until we can read a message from the given peer.
	// If [ctx] is canceled, returns immediately.
	Acquire(ctx context.Context, nodeID ids.NodeID)
}

// A CPU throttler that always immediately returns on [Acquire].
type noCPUThrottler struct{}

func (t *noCPUThrottler) Acquire(context.Context, ids.NodeID) {}

type CPUThrottlerConfig struct {
	Clock mockable.Clock `json:"-"`
	// The maximum amount of time we'll wait before
	// re-checking whether a call to [Acquire] can return.
	MaxRecheckDelay time.Duration `json:"maxRecheckDelay"`
}

type cpuThrottler struct {
	CPUThrottlerConfig
	metrics *cpuThrottlerMetrics
	// Tells us the target CPU utilization of each node.
	cpuTargeter tracker.CPUTargeter
	// Tells us CPU utilization of each node.
	cpuTracker tracker.TimeTracker
}

type cpuThrottlerMetrics struct {
	totalWaits      prometheus.Counter
	totalNoWaits    prometheus.Counter
	awaitingAcquire prometheus.Gauge
}

func newCPUThrottlerMetrics(namespace string, reg prometheus.Registerer) (*cpuThrottlerMetrics, error) {
	m := &cpuThrottlerMetrics{
		totalWaits: prometheus.NewCounter(prometheus.CounterOpts{
			Namespace: namespace,
			Name:      "cpu_throttler_total_waits",
			Help:      "Number of times we've waited to read a message from a node because their CPU usage was too high",
		}),
		totalNoWaits: prometheus.NewCounter(prometheus.CounterOpts{
			Namespace: namespace,
			Name:      "cpu_throttler_total_no_waits",
			Help:      "Number of times we didn't wait to read a message due to their CPU usage being too high",
		}),
		awaitingAcquire: prometheus.NewGauge(prometheus.GaugeOpts{
			Namespace: namespace,
			Name:      "cpu_throttler_awaiting_acquire",
			Help:      "Number of nodes we're waiting to read a message from because their CPU usage is too high",
		}),
	}
	errs := wrappers.Errs{}
	errs.Add(
		reg.Register(m.totalWaits),
		reg.Register(m.totalNoWaits),
		reg.Register(m.awaitingAcquire),
	)
	return m, errs.Err
}

func NewCPUThrottler(
	namespace string,
	reg prometheus.Registerer,
	config CPUThrottlerConfig,
	vdrs validators.Set,
	cpuTracker tracker.TimeTracker,
	cpuTargeter tracker.CPUTargeter,
) (CPUThrottler, error) {
	metrics, err := newCPUThrottlerMetrics(namespace, reg)
	if err != nil {
		return nil, fmt.Errorf("couldn't initialize CPU throttler metrics: %w", err)
	}
	return &cpuThrottler{
		metrics:            metrics,
		CPUThrottlerConfig: config,
		cpuTargeter:        cpuTargeter,
		cpuTracker:         cpuTracker,
	}, nil
}

func (t *cpuThrottler) Acquire(ctx context.Context, nodeID ids.NodeID) {
	// Fires when we should re-check whether this node's CPU usage
	// has fallen to an acceptable level.
	timer := time.NewTimer(0)
	if !timer.Stop() {
		<-timer.C
	}
	defer timer.Stop()

	// [waited] is true if we waited for this node's CPU usage
	// to fall to an acceptable level before returning
	waited := false
	defer func() {
		if waited {
			t.metrics.totalWaits.Inc()
			// Note that [t.metrics.awaitingAcquire.Inc()]
			// was called once if and only if [waited] is true.
			t.metrics.awaitingAcquire.Dec()
		} else {
			t.metrics.totalNoWaits.Inc()
		}
	}()

	for {
		now := t.Clock.Time()
		// Get target CPU usage for this node.
		targetVdrCPU, targetAtLargeCPU, _ := t.cpuTargeter.TargetCPUUsage(nodeID)
		targetCPU := targetVdrCPU + targetAtLargeCPU
		// Get actual CPU usage for this node.
		actualCPU := t.cpuTracker.Utilization(nodeID, now)
		if actualCPU <= targetCPU {
			return
		}
		// See how long it will take for actual CPU usage to drop to target,
		// assuming this node uses no more CPU.
		waitDuration := t.cpuTracker.TimeUntilUtilization(nodeID, now, targetCPU)
		if waitDuration < epsilon {
			// If the amount of time until we reach the CPU target is very small,
			// just return to avoid a situation where we excessively re-check.
			return
		}
		if waitDuration > t.MaxRecheckDelay {
			// Re-check at least every [t.MaxRecheckDelay] in case it will be a
			// very long time until CPU usage reaches the target level.
			//
			// Note that not only can a node's CPU usage decrease over time, but
			// also its target CPU usage may increase.
			// In this case, the node's CPU usage can drop to the target level
			// sooner than [waitDuration] because the target has increased.
			// The minimum re-check frequency accounts for that case by
			// optimistically re-checking whether the node's CPU usage is now at
			// an acceptable level.
			waitDuration = t.MaxRecheckDelay
		}
		if !waited {
			// Note this is called at most once.
			t.metrics.awaitingAcquire.Inc()
		}
		waited = true
		timer.Reset(waitDuration)
		select {
		case <-ctx.Done():
			return
		case <-timer.C:
		}
	}
}
<|endoftext|>


<commit_before>// +build coprocess

package main

/*
#include <stdio.h>

#include "coprocess/sds/sds.h"

#include "coprocess/api.h"

#include "coprocess/python/dispatcher.h"
#include "coprocess/python/binding.h"

*/
import "C"

import (
	"github.com/Sirupsen/logrus"
	"github.com/mitchellh/mapstructure"
	"github.com/gorilla/context"

	"encoding/json"

	"bytes"
	"io/ioutil"
	"net/http"
)

var EnableCoProcess bool = true

var GlobalDispatcher CoProcessDispatcher

func CoProcessDispatchHook(o CoProcessObject) CoProcessObject {
	objectAsJson, _ := json.Marshal(o)
	return GlobalDispatcher.DispatchHook(objectAsJson)
}

func CreateCoProcessMiddleware(IsPre bool, tykMwSuper *TykMiddleware) func(http.Handler) http.Handler {
	dMiddleware := &CoProcessMiddleware{
		TykMiddleware:       tykMwSuper,
		Pre: IsPre,
		/*
		MiddlewareClassName: MiddlewareName,
		UseSession:          UseSession,
		*/
	}

	return CreateMiddleware(dMiddleware, tykMwSuper)
}

type CoProcessDispatcher interface {
	DispatchHook([]byte) CoProcessObject
}

type CoProcessObject struct {
	HookType string	`json:"hook_type"`
	Request CoProcessMiniRequestObject	`json:"request,omitempty"`
	Session SessionState	`json:"session,omitempty"`
	Spec map[string]string `json:"spec,omitempty"`
}

type CoProcessMiniRequestObject struct {
	Headers         map[string][]string
	SetHeaders      map[string]string
	DeleteHeaders   []string
	Body            string
	URL             string
	Params          map[string][]string
	AddParams       map[string]string
	ExtendedParams  map[string][]string
	DeleteParams    []string
	ReturnOverrides ReturnOverrides
}

type CoProcessMiddleware struct {
	*TykMiddleware
	MiddlewareClassName string
	Pre                 bool
	UseSession          bool
}

type CoProcessMiddlewareConfig struct {
	ConfigData map[string]string `mapstructure:"config_data" bson:"config_data" json:"config_data"`
}

// New lets you do any initialisations for the object can be done here
func (m *CoProcessMiddleware) New() {}

// GetConfig retrieves the configuration from the API config - we user mapstructure for this for simplicity
func (m *CoProcessMiddleware) GetConfig() (interface{}, error) {
	var thisModuleConfig CoProcessMiddlewareConfig

	err := mapstructure.Decode(m.TykMiddleware.Spec.APIDefinition.RawData, &thisModuleConfig)
	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "jsvm",
		}).Error(err)
		return nil, err
	}

	return thisModuleConfig, nil
}

// ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail
func (m *CoProcessMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, configuration interface{}) (error, int) {
	  log.WithFields(logrus.Fields{
	    "prefix": "coprocess",
	  }).Info( "ProcessRequest: ", m.MiddlewareClassName, " Pre: ", m.Pre )

	defer r.Body.Close()
	originalBody, _ := ioutil.ReadAll(r.Body)

	var object, newObject CoProcessObject

	object.Request = CoProcessMiniRequestObject{
		Headers:        r.Header,
		SetHeaders:     make(map[string]string),
		DeleteHeaders:  make([]string, 0),
		Body:           string(originalBody),
		URL:            r.URL.Path,
		Params:         r.URL.Query(),
		AddParams:      make(map[string]string),
		ExtendedParams: make(map[string][]string),
		DeleteParams:   make([]string, 0),
	}

	object.HookType = "pre"

	// Encode the session object (if not a pre-process)
	if !m.Pre {
		object.Session = context.Get(r, SessionData).(SessionState)
		object.HookType = "post"
	}

	// Append spec data
	object.Spec = map[string]string{
		"OrgID": m.TykMiddleware.Spec.OrgID,
		"APIID": m.TykMiddleware.Spec.APIID,
	}

	newObject = CoProcessDispatchHook(object)

	r.ContentLength = int64(len(newObject.Request.Body))
	r.Body = ioutil.NopCloser(bytes.NewBufferString(newObject.Request.Body))

	return nil, 200
}

//export CoProcess_Log
func CoProcess_Log(CMessage *C.char, CLogLevel *C.char) {
	var message, logLevel string
	message = C.GoString(CMessage)
	logLevel = C.GoString(CLogLevel)

	switch logLevel {
	case "error":
		log.WithFields(logrus.Fields{
			"prefix": CoProcessName,
		}).Error(message)
	default:
		log.WithFields(logrus.Fields{
			"prefix": CoProcessName,
		}).Info(message)
	}
}
<commit_msg>Restore header manipulation<commit_after>// +build coprocess

package main

/*
#include <stdio.h>

#include "coprocess/sds/sds.h"

#include "coprocess/api.h"

#include "coprocess/python/dispatcher.h"
#include "coprocess/python/binding.h"

*/
import "C"

import (
	"github.com/Sirupsen/logrus"
	"github.com/mitchellh/mapstructure"
	"github.com/gorilla/context"

	"encoding/json"

	"bytes"
	"io/ioutil"
	"net/http"
)

var EnableCoProcess bool = true

var GlobalDispatcher CoProcessDispatcher

func CoProcessDispatchHook(o CoProcessObject) CoProcessObject {
	objectAsJson, _ := json.Marshal(o)
	return GlobalDispatcher.DispatchHook(objectAsJson)
}

func CreateCoProcessMiddleware(IsPre bool, tykMwSuper *TykMiddleware) func(http.Handler) http.Handler {
	dMiddleware := &CoProcessMiddleware{
		TykMiddleware:       tykMwSuper,
		Pre: IsPre,
		/*
		MiddlewareClassName: MiddlewareName,
		UseSession:          UseSession,
		*/
	}

	return CreateMiddleware(dMiddleware, tykMwSuper)
}

type CoProcessDispatcher interface {
	DispatchHook([]byte) CoProcessObject
}

type CoProcessObject struct {
	HookType string	`json:"hook_type"`
	Request CoProcessMiniRequestObject	`json:"request,omitempty"`
	Session SessionState	`json:"session,omitempty"`
	Spec map[string]string `json:"spec,omitempty"`
}

type CoProcessMiniRequestObject struct {
	Headers         map[string][]string
	SetHeaders      map[string]string
	DeleteHeaders   []string
	Body            string
	URL             string
	Params          map[string][]string
	AddParams       map[string]string
	ExtendedParams  map[string][]string
	DeleteParams    []string
	ReturnOverrides ReturnOverrides
}

type CoProcessMiddleware struct {
	*TykMiddleware
	MiddlewareClassName string
	Pre                 bool
	UseSession          bool
}

type CoProcessMiddlewareConfig struct {
	ConfigData map[string]string `mapstructure:"config_data" bson:"config_data" json:"config_data"`
}

// New lets you do any initialisations for the object can be done here
func (m *CoProcessMiddleware) New() {}

// GetConfig retrieves the configuration from the API config - we user mapstructure for this for simplicity
func (m *CoProcessMiddleware) GetConfig() (interface{}, error) {
	var thisModuleConfig CoProcessMiddlewareConfig

	err := mapstructure.Decode(m.TykMiddleware.Spec.APIDefinition.RawData, &thisModuleConfig)
	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "jsvm",
		}).Error(err)
		return nil, err
	}

	return thisModuleConfig, nil
}

// ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail
func (m *CoProcessMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, configuration interface{}) (error, int) {
	  log.WithFields(logrus.Fields{
	    "prefix": "coprocess",
	  }).Info( "ProcessRequest: ", m.MiddlewareClassName, " Pre: ", m.Pre )

	defer r.Body.Close()
	originalBody, _ := ioutil.ReadAll(r.Body)

	var object, newObject CoProcessObject

	object.Request = CoProcessMiniRequestObject{
		Headers:        r.Header,
		SetHeaders:     make(map[string]string),
		DeleteHeaders:  make([]string, 0),
		Body:           string(originalBody),
		URL:            r.URL.Path,
		Params:         r.URL.Query(),
		AddParams:      make(map[string]string),
		ExtendedParams: make(map[string][]string),
		DeleteParams:   make([]string, 0),
	}

	object.HookType = "pre"

	// Encode the session object (if not a pre-process)
	if !m.Pre {
		object.Session = context.Get(r, SessionData).(SessionState)
		object.HookType = "post"
	}

	// Append spec data
	object.Spec = map[string]string{
		"OrgID": m.TykMiddleware.Spec.OrgID,
		"APIID": m.TykMiddleware.Spec.APIID,
	}

	newObject = CoProcessDispatchHook(object)

	r.ContentLength = int64(len(newObject.Request.Body))
	r.Body = ioutil.NopCloser(bytes.NewBufferString(newObject.Request.Body))

	for _, dh := range newObject.Request.DeleteHeaders {
		r.Header.Del(dh)
	}

	for h, v := range newObject.Request.SetHeaders {
		r.Header.Set(h, v)
	}

	return nil, 200
}

//export CoProcess_Log
func CoProcess_Log(CMessage *C.char, CLogLevel *C.char) {
	var message, logLevel string
	message = C.GoString(CMessage)
	logLevel = C.GoString(CLogLevel)

	switch logLevel {
	case "error":
		log.WithFields(logrus.Fields{
			"prefix": CoProcessName,
		}).Error(message)
	default:
		log.WithFields(logrus.Fields{
			"prefix": CoProcessName,
		}).Info(message)
	}
}
<|endoftext|>


<commit_before>package heartbleed

import (
	"net"
	"testing"
)

func TestBleed(t *testing.T) {
	// IIS (?)
	tgt := Target{"twitch.tv", "https"}
	_, err := Heartbleed(&tgt, []byte("FiloSottile/Heartbleed"), false)
	if err != Closed {
		t.Errorf("twitch.tv: %v", err)
	}

	// ELB
	tgt = Target{"www.theneeds.com", "https"}
	_, err = Heartbleed(&tgt, []byte("FiloSottile/Heartbleed"), false)
	if err != Safe {
		t.Errorf("www.theneeds.com: %v", err)
	}

	// SAFE
	tgt = Target{"gmail.com", "https"}
	_, err = Heartbleed(&tgt, []byte("FiloSottile/Heartbleed"), false)
	if err != Safe {
		t.Errorf("gmail.com: %v", err)
	}

	// VULNERABLE
	tgt = Target{"www.cloudflarechallenge.com", "https"}
	_, err = Heartbleed(&tgt, []byte("FiloSottile/Heartbleed"), false)
	if err != nil {
		t.Errorf("www.cloudflarechallenge.com: %v", err)
	}

	// TIMEOUT
	tgt = Target{"www.cloudflarechallenge.com:4242", "https"}
	_, err = Heartbleed(&tgt, []byte("FiloSottile/Heartbleed"), false)
	nerr, ok := err.(*net.OpError)
	if !ok || nerr.Err.Error() != "i/o timeout" {
		t.Errorf("www.cloudflarechallenge.com:4242: %v", err)
	}
}
<commit_msg>Update so each test has it's own for verbosity. Also check for go test -short and skip the longer tests.<commit_after>package heartbleed

import (
	"net"
	"testing"
)

func TestBleedIIS(t *testing.T) {
	// IIS (?)
	tgt := Target{"twitch.tv", "https"}
	_, err := Heartbleed(&tgt, []byte("FiloSottile/Heartbleed"), false)
	if err != Closed {
		t.Errorf("twitch.tv: %v", err)
	}
}

func TestBleedELB(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping ELB test to save time.")
	}

	// ELB
	tgt := Target{"www.theneeds.com", "https"}
	_, err := Heartbleed(&tgt, []byte("FiloSottile/Heartbleed"), false)
	if err != Safe {
		t.Errorf("www.theneeds.com: %v", err)
	}
}

func TestBleedSafe(t *testing.T) {
	// SAFE
	tgt := Target{"gmail.com", "https"}
	_, err := Heartbleed(&tgt, []byte("FiloSottile/Heartbleed"), false)
	if err != Safe {
		t.Errorf("gmail.com: %v", err)
	}
}

func TestBleedVulnerable(t *testing.T) {
	// VULNERABLE
	tgt := Target{"www.cloudflarechallenge.com", "https"}
	_, err := Heartbleed(&tgt, []byte("FiloSottile/Heartbleed"), false)
	if err != nil {
		t.Errorf("www.cloudflarechallenge.com: %v", err)
	}
}

func TestBleedTimeout(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping timeout test to save time.")
	}

	// TIMEOUT
	tgt := Target{"www.cloudflarechallenge.com:4242", "https"}
	_, err := Heartbleed(&tgt, []byte("FiloSottile/Heartbleed"), false)
	nerr, ok := err.(*net.OpError)
	if !ok || nerr.Err.Error() != "i/o timeout" {
		t.Errorf("www.cloudflarechallenge.com:4242: %v", err)
	}
}
<|endoftext|>


<commit_before>package core

import (
	"context"
	"encoding/json"
	"expvar"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strings"
	"syscall"
	"time"

	"chain/core/fetch"
	"chain/core/leader"
	"chain/core/mockhsm"
	"chain/core/txdb"
	"chain/crypto/ed25519"
	"chain/crypto/ed25519/hd25519"
	"chain/database/pg"
	"chain/database/sql"
	"chain/errors"
	"chain/net/http/httpjson"
	"chain/net/rpc"
	"chain/protocol"
	"chain/protocol/state"
)

var (
	errAlreadyConfigured = errors.New("core is already configured; must reset first")
	errUnconfigured      = errors.New("core is not configured")
	errBadGenerator      = errors.New("generator returned an unsuccessful response")
	errBadBlockXPub      = errors.New("supplied block xpub is invalid")
)

// reserved mockhsm key alias
const autoBlockKeyAlias = "_CHAIN_CORE_AUTO_BLOCK_KEY"

func isProduction() bool {
	return expvar.Get("buildtag").String() != `"dev"`
}

// errProdReset is returned when reset is called on a
// production system.
var errProdReset = errors.New("reset called on production system")

// Reset deletes all data, resulting in an unconfigured core.
// It must be called before any other functions in this package.
func Reset(ctx context.Context, db pg.DB) error {
	if isProduction() {
		return errors.Wrap(errProdReset)
	}

	const q = `
		TRUNCATE
			account_control_programs,
			account_utxos,
			accounts,
			annotated_accounts,
			annotated_assets,
			annotated_outputs,
			annotated_txs,
			asset_tags,
			assets,
			blocks,
			config,
			generator_pending_block,
			leader,
			mockhsm,
			pool_txs,
			query_blocks,
			query_indexes,
			reservations,
			signed_blocks,
			signers,
			snapshots
			RESTART IDENTITY;
	`

	_, err := db.Exec(ctx, q)
	return errors.Wrap(err)
}

func (a *api) reset(ctx context.Context) error {
	if isProduction() {
		return errors.Wrap(errProdReset)
	}

	w := httpjson.ResponseWriter(ctx)
	closeConnOK(w)
	execSelf("RESET=true")
	panic("unreached")
}

func (a *api) info(ctx context.Context) (map[string]interface{}, error) {
	if a.config == nil {
		// never configured
		return map[string]interface{}{
			"is_configured": false,
		}, nil
	}
	if leader.IsLeading() {
		return a.leaderInfo(ctx)
	} else {
		return a.fetchInfoFromLeader(ctx)
	}
}

func (a *api) leaderInfo(ctx context.Context) (map[string]interface{}, error) {
	localHeight := a.c.Height()
	var (
		generatorHeight  interface{}
		generatorFetched time.Time
	)
	if a.config.IsGenerator {
		generatorHeight = localHeight
		generatorFetched = time.Now()
	} else {
		generatorHeight, generatorFetched = fetch.GeneratorHeight()
	}

	buildCommit := json.RawMessage(expvar.Get("buildcommit").String())
	buildDate := json.RawMessage(expvar.Get("builddate").String())

	return map[string]interface{}{
		"is_configured":                     true,
		"configured_at":                     a.config.ConfiguredAt,
		"is_signer":                         a.config.IsSigner,
		"is_generator":                      a.config.IsGenerator,
		"generator_url":                     a.config.GeneratorURL,
		"initial_block_hash":                a.config.InitialBlockHash,
		"block_height":                      localHeight,
		"generator_block_height":            generatorHeight,
		"generator_block_height_fetched_at": generatorFetched,
		"is_production":                     isProduction(),
		"build_commit":                      &buildCommit,
		"build_date":                        &buildDate,
	}, nil
}

func (a *api) fetchInfoFromLeader(ctx context.Context) (map[string]interface{}, error) {
	addr, err := leader.Address(ctx)
	if err != nil {
		return nil, err
	}

	l := &rpc.Client{
		BaseURL: "https://" + addr,
		// TODO(tessr): Auth.
	}

	var resp map[string]interface{}
	err = l.Call(ctx, "/info", nil, &resp)
	return resp, err
}

// Configure configures the core by writing to the database.
// If running in a cored process,
// the caller must ensure that the new configuration is properly reloaded,
// for example by restarting the process.
//
// If c.IsSigner is true, Configure generates a new mockhsm keypair
// for signing blocks, and assigns it to c.BlockXPub.
//
// If c.IsGenerator is true, Configure creates an initial block,
// saves it, and assigns its hash to c.InitialBlockHash.
// Otherwise, c.IsGenerator is false, and Configure makes a test request
// to GeneratorURL to detect simple configuration mistakes.
func Configure(ctx context.Context, db pg.DB, c *Config) error {
	var err error
	if !c.IsGenerator {
		err = tryGenerator(ctx, c.GeneratorURL)
		if err != nil {
			return err
		}
	}

	var signingKeys []ed25519.PublicKey
	if c.IsSigner {
		var blockXPub *hd25519.XPub
		if c.BlockXPub == "" {
			hsm := mockhsm.New(db)
			coreXPub, created, err := hsm.GetOrCreateKey(ctx, autoBlockKeyAlias)
			if err != nil {
				return err
			}
			blockXPub = coreXPub.XPub
			if created {
				log.Printf("Generated new block-signing key %s\n", blockXPub.String())
			} else {
				log.Printf("Using block-signing key %s\n", blockXPub.String())
			}
			c.BlockXPub = blockXPub.String()
		} else {
			blockXPub, err = hd25519.XPubFromString(c.BlockXPub)
			if err != nil {
				return errors.Wrap(errBadBlockXPub, err.Error())
			}
		}
		signingKeys = append(signingKeys, blockXPub.Key)
	}

	if c.IsGenerator {
		block, err := protocol.NewInitialBlock(signingKeys, 1, time.Now())
		if err != nil {
			return err
		}
		store, pool := txdb.New(db.(*sql.DB))
		chain, err := protocol.NewChain(ctx, store, pool, nil)
		if err != nil {
			return err
		}

		err = chain.CommitBlock(ctx, block, state.Empty())
		if err != nil {
			return err
		}

		c.InitialBlockHash = block.Hash()
	}

	const q = `
		INSERT INTO config (is_signer, block_xpub, is_generator, initial_block_hash, generator_url, configured_at)
		VALUES ($1, $2, $3, $4, $5, NOW())
	`
	_, err = db.Exec(ctx, q, c.IsSigner, c.BlockXPub, c.IsGenerator, c.InitialBlockHash, c.GeneratorURL)
	return err
}

func configure(ctx context.Context, x *Config) error {
	err := Configure(ctx, pg.FromContext(ctx), x)
	if err != nil {
		return err
	}

	w := httpjson.ResponseWriter(ctx)
	closeConnOK(w)
	execSelf()
	panic("unreached")
}

func tryGenerator(ctx context.Context, url string) error {
	client := &rpc.Client{
		BaseURL: url,
	}
	var x struct {
		BlockHeight uint64 `json:"block_height"`
	}
	err := client.Call(ctx, "/rpc/block-height", nil, &x)
	if err != nil {
		return errors.Wrap(errBadGenerator, err.Error())
	}

	if x.BlockHeight < 1 {
		return errBadGenerator
	}

	return nil
}

func closeConnOK(w http.ResponseWriter) {
	w.Header().Add("Connection", "close")
	w.WriteHeader(http.StatusNoContent)

	hijacker, ok := w.(http.Hijacker)
	if !ok {
		log.Printf("no hijacker")
		return
	}
	conn, buf, err := hijacker.Hijack()
	if err != nil {
		log.Printf("could not hijack connection: %s\n", err)
		return
	}
	err = buf.Flush()
	if err != nil {
		log.Printf("could not flush connection buffer: %s\n", err)
	}
	err = conn.Close()
	if err != nil {
		log.Printf("could not close connection: %s\n", err)
	}
}

// execSelf execs Args with environment values replaced
// by the ones in env.
func execSelf(env ...string) {
	binpath, err := exec.LookPath(os.Args[0])
	if err != nil {
		panic(err)
	}

	env = mergeEnvLists(env, os.Environ())
	err = syscall.Exec(binpath, os.Args, env)
	if err != nil {
		panic(err)
	}
}

// mergeEnvLists merges the two environment lists such that
// variables with the same name in "in" replace those in "out".
// This always returns a newly allocated slice.
func mergeEnvLists(in, out []string) []string {
	out = append([]string(nil), out...)
NextVar:
	for _, inkv := range in {
		k := strings.SplitAfterN(inkv, "=", 2)[0]
		for i, outkv := range out {
			if strings.HasPrefix(outkv, k) {
				out[i] = inkv
				continue NextVar
			}
		}
		out = append(out, inkv)
	}
	return out
}
<commit_msg>core: set generator_height minimum bound of local<commit_after>package core

import (
	"context"
	"encoding/json"
	"expvar"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strings"
	"syscall"
	"time"

	"chain/core/fetch"
	"chain/core/leader"
	"chain/core/mockhsm"
	"chain/core/txdb"
	"chain/crypto/ed25519"
	"chain/crypto/ed25519/hd25519"
	"chain/database/pg"
	"chain/database/sql"
	"chain/errors"
	"chain/net/http/httpjson"
	"chain/net/rpc"
	"chain/protocol"
	"chain/protocol/state"
)

var (
	errAlreadyConfigured = errors.New("core is already configured; must reset first")
	errUnconfigured      = errors.New("core is not configured")
	errBadGenerator      = errors.New("generator returned an unsuccessful response")
	errBadBlockXPub      = errors.New("supplied block xpub is invalid")
)

// reserved mockhsm key alias
const autoBlockKeyAlias = "_CHAIN_CORE_AUTO_BLOCK_KEY"

func isProduction() bool {
	return expvar.Get("buildtag").String() != `"dev"`
}

// errProdReset is returned when reset is called on a
// production system.
var errProdReset = errors.New("reset called on production system")

// Reset deletes all data, resulting in an unconfigured core.
// It must be called before any other functions in this package.
func Reset(ctx context.Context, db pg.DB) error {
	if isProduction() {
		return errors.Wrap(errProdReset)
	}

	const q = `
		TRUNCATE
			account_control_programs,
			account_utxos,
			accounts,
			annotated_accounts,
			annotated_assets,
			annotated_outputs,
			annotated_txs,
			asset_tags,
			assets,
			blocks,
			config,
			generator_pending_block,
			leader,
			mockhsm,
			pool_txs,
			query_blocks,
			query_indexes,
			reservations,
			signed_blocks,
			signers,
			snapshots
			RESTART IDENTITY;
	`

	_, err := db.Exec(ctx, q)
	return errors.Wrap(err)
}

func (a *api) reset(ctx context.Context) error {
	if isProduction() {
		return errors.Wrap(errProdReset)
	}

	w := httpjson.ResponseWriter(ctx)
	closeConnOK(w)
	execSelf("RESET=true")
	panic("unreached")
}

func (a *api) info(ctx context.Context) (map[string]interface{}, error) {
	if a.config == nil {
		// never configured
		return map[string]interface{}{
			"is_configured": false,
		}, nil
	}
	if leader.IsLeading() {
		return a.leaderInfo(ctx)
	} else {
		return a.fetchInfoFromLeader(ctx)
	}
}

func (a *api) leaderInfo(ctx context.Context) (map[string]interface{}, error) {
	localHeight := a.c.Height()
	var (
		generatorHeight  uint64
		generatorFetched time.Time
	)
	if a.config.IsGenerator {
		generatorHeight = localHeight
		generatorFetched = time.Now()
	} else {
		generatorHeight, generatorFetched = fetch.GeneratorHeight()
	}

	buildCommit := json.RawMessage(expvar.Get("buildcommit").String())
	buildDate := json.RawMessage(expvar.Get("builddate").String())

	// Because everything is asynchronous, it's possible for the localHeight to
	// be higher than our cached generator height. In that case, display the
	// generatorHeight as our height.
	if localHeight > generatorHeight {
		generatorHeight = localHeight
	}

	return map[string]interface{}{
		"is_configured":                     true,
		"configured_at":                     a.config.ConfiguredAt,
		"is_signer":                         a.config.IsSigner,
		"is_generator":                      a.config.IsGenerator,
		"generator_url":                     a.config.GeneratorURL,
		"initial_block_hash":                a.config.InitialBlockHash,
		"block_height":                      localHeight,
		"generator_block_height":            generatorHeight,
		"generator_block_height_fetched_at": generatorFetched,
		"is_production":                     isProduction(),
		"build_commit":                      &buildCommit,
		"build_date":                        &buildDate,
	}, nil
}

func (a *api) fetchInfoFromLeader(ctx context.Context) (map[string]interface{}, error) {
	addr, err := leader.Address(ctx)
	if err != nil {
		return nil, err
	}

	l := &rpc.Client{
		BaseURL: "https://" + addr,
		// TODO(tessr): Auth.
	}

	var resp map[string]interface{}
	err = l.Call(ctx, "/info", nil, &resp)
	return resp, err
}

// Configure configures the core by writing to the database.
// If running in a cored process,
// the caller must ensure that the new configuration is properly reloaded,
// for example by restarting the process.
//
// If c.IsSigner is true, Configure generates a new mockhsm keypair
// for signing blocks, and assigns it to c.BlockXPub.
//
// If c.IsGenerator is true, Configure creates an initial block,
// saves it, and assigns its hash to c.InitialBlockHash.
// Otherwise, c.IsGenerator is false, and Configure makes a test request
// to GeneratorURL to detect simple configuration mistakes.
func Configure(ctx context.Context, db pg.DB, c *Config) error {
	var err error
	if !c.IsGenerator {
		err = tryGenerator(ctx, c.GeneratorURL)
		if err != nil {
			return err
		}
	}

	var signingKeys []ed25519.PublicKey
	if c.IsSigner {
		var blockXPub *hd25519.XPub
		if c.BlockXPub == "" {
			hsm := mockhsm.New(db)
			coreXPub, created, err := hsm.GetOrCreateKey(ctx, autoBlockKeyAlias)
			if err != nil {
				return err
			}
			blockXPub = coreXPub.XPub
			if created {
				log.Printf("Generated new block-signing key %s\n", blockXPub.String())
			} else {
				log.Printf("Using block-signing key %s\n", blockXPub.String())
			}
			c.BlockXPub = blockXPub.String()
		} else {
			blockXPub, err = hd25519.XPubFromString(c.BlockXPub)
			if err != nil {
				return errors.Wrap(errBadBlockXPub, err.Error())
			}
		}
		signingKeys = append(signingKeys, blockXPub.Key)
	}

	if c.IsGenerator {
		block, err := protocol.NewInitialBlock(signingKeys, 1, time.Now())
		if err != nil {
			return err
		}
		store, pool := txdb.New(db.(*sql.DB))
		chain, err := protocol.NewChain(ctx, store, pool, nil)
		if err != nil {
			return err
		}

		err = chain.CommitBlock(ctx, block, state.Empty())
		if err != nil {
			return err
		}

		c.InitialBlockHash = block.Hash()
	}

	const q = `
		INSERT INTO config (is_signer, block_xpub, is_generator, initial_block_hash, generator_url, configured_at)
		VALUES ($1, $2, $3, $4, $5, NOW())
	`
	_, err = db.Exec(ctx, q, c.IsSigner, c.BlockXPub, c.IsGenerator, c.InitialBlockHash, c.GeneratorURL)
	return err
}

func configure(ctx context.Context, x *Config) error {
	err := Configure(ctx, pg.FromContext(ctx), x)
	if err != nil {
		return err
	}

	w := httpjson.ResponseWriter(ctx)
	closeConnOK(w)
	execSelf()
	panic("unreached")
}

func tryGenerator(ctx context.Context, url string) error {
	client := &rpc.Client{
		BaseURL: url,
	}
	var x struct {
		BlockHeight uint64 `json:"block_height"`
	}
	err := client.Call(ctx, "/rpc/block-height", nil, &x)
	if err != nil {
		return errors.Wrap(errBadGenerator, err.Error())
	}

	if x.BlockHeight < 1 {
		return errBadGenerator
	}

	return nil
}

func closeConnOK(w http.ResponseWriter) {
	w.Header().Add("Connection", "close")
	w.WriteHeader(http.StatusNoContent)

	hijacker, ok := w.(http.Hijacker)
	if !ok {
		log.Printf("no hijacker")
		return
	}
	conn, buf, err := hijacker.Hijack()
	if err != nil {
		log.Printf("could not hijack connection: %s\n", err)
		return
	}
	err = buf.Flush()
	if err != nil {
		log.Printf("could not flush connection buffer: %s\n", err)
	}
	err = conn.Close()
	if err != nil {
		log.Printf("could not close connection: %s\n", err)
	}
}

// execSelf execs Args with environment values replaced
// by the ones in env.
func execSelf(env ...string) {
	binpath, err := exec.LookPath(os.Args[0])
	if err != nil {
		panic(err)
	}

	env = mergeEnvLists(env, os.Environ())
	err = syscall.Exec(binpath, os.Args, env)
	if err != nil {
		panic(err)
	}
}

// mergeEnvLists merges the two environment lists such that
// variables with the same name in "in" replace those in "out".
// This always returns a newly allocated slice.
func mergeEnvLists(in, out []string) []string {
	out = append([]string(nil), out...)
NextVar:
	for _, inkv := range in {
		k := strings.SplitAfterN(inkv, "=", 2)[0]
		for i, outkv := range out {
			if strings.HasPrefix(outkv, k) {
				out[i] = inkv
				continue NextVar
			}
		}
		out = append(out, inkv)
	}
	return out
}
<|endoftext|>


<commit_before>package core

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"sort"
	"strconv"
	"strings"
	"time"
)

const ms_date_layout = "Mon, 02 Jan 2006 15:04:05 GMT"
const version = "2009-09-19"

type Credentials struct {
	Account   string
	AccessKey string
}

type AzureRequest struct {
	Method      string
	Container   string
	Resource    string
	RequestTime time.Time
	Request     *http.Request
	Header      map[string]string
	Body        io.Reader
}

type Core struct {
	Credentials  Credentials
	AzureRequest AzureRequest
}

func New(credentials Credentials, azureRequest AzureRequest) *Core {
	return &Core{
		Credentials:  credentials,
		AzureRequest: azureRequest}
}

func (core Core) addCustomInformationsToHeader() {
	for key, value := range core.AzureRequest.Header {
		core.AzureRequest.Request.Header.Add(key, value)
	}
}

func (core Core) PrepareRequest() *http.Request {
	body := &bytes.Buffer{}

	if core.AzureRequest.Body != nil {
		io.Copy(body, core.AzureRequest.Body)
	}

	req, err := http.NewRequest(strings.ToUpper(core.AzureRequest.Method), core.RequestUrl(), body)

	if err != nil {
		log.Fatal(err)
	}

	core.AzureRequest.Request = req
	core.addCustomInformationsToHeader()
	core.complementHeaderInformations()

	return req
}

func (core Core) RequestUrl() string {
	return fmt.Sprintf("%s%s%s", core.webService(), core.AzureRequest.Container, core.AzureRequest.Resource)
}

func (core Core) complementHeaderInformations() {
	core.AzureRequest.Request.Header.Add("x-ms-date", core.formattedRequestTime())
	core.AzureRequest.Request.Header.Add("x-ms-version", version)
	core.AzureRequest.Request.Header.Add("Authorization", core.authorizationHeader())
}

func (core Core) authorizationHeader() string {
	return fmt.Sprintf("SharedKey %s:%s", core.Credentials.Account, core.signature())
}

/*
Based on Azure docs:
  Link: http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx#Constructing_Element

  1) Retrieve all headers for the resource that begin with x-ms-, including the x-ms-date header.
  2) Convert each HTTP header name to lowercase.
  3) Sort the headers lexicographically by header name, in ascending order. Note that each header may appear only once in the string.
  4) Unfold the string by replacing any breaking white space with a single space.
  5) Trim any white space around the colon in the header.
  6) Finally, append a new line character to each canonicalized header in the resulting list. Construct the CanonicalizedHeaders string by concatenating all headers in this list into a single string.
*/
func (core Core) canonicalizedHeaders() string {
	var buffer bytes.Buffer

	for key, value := range core.AzureRequest.Request.Header {
		lowerKey := strings.ToLower(key)

		if strings.HasPrefix(lowerKey, "x-ms-") {
			if buffer.Len() == 0 {
				buffer.WriteString(fmt.Sprintf("%s:%s", lowerKey, value[0]))
			} else {
				buffer.WriteString(fmt.Sprintf("\n%s:%s", lowerKey, value[0]))
			}
		}
	}

	splitted := strings.Split(buffer.String(), "\n")
	sort.Strings(splitted)

	return strings.Join(splitted, "\n")
}

/*
Based on Azure docs
  Link: http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx#Constructing_Element

1) Beginning with an empty string (""), append a forward slash (/), followed by the name of the account that owns the resource being accessed.
2) Append the resource's encoded URI path, without any query parameters.
3) Retrieve all query parameters on the resource URI, including the comp parameter if it exists.
4) Convert all parameter names to lowercase.
5) Sort the query parameters lexicographically by parameter name, in ascending order.
6) URL-decode each query parameter name and value.
7) Append each query parameter name and value to the string in the following format, making sure to include the colon (:) between the name and the value:
    parameter-name:parameter-value

8) If a query parameter has more than one value, sort all values lexicographically, then include them in a comma-separated list:
    parameter-name:parameter-value-1,parameter-value-2,parameter-value-n

9) Append a new line character (\n) after each name-value pair.

Rules:
  1) Avoid using the new line character (\n) in values for query parameters. If it must be used, ensure that it does not affect the format of the canonicalized resource string.
  2) Avoid using commas in query parameter values.
*/
func (core Core) canonicalizedResource() string {
	var buffer bytes.Buffer

	u, err := url.Parse(core.RequestUrl())

	if err != nil {
		log.Fatal(err)
	}

	buffer.WriteString(fmt.Sprintf("/%s/%s", core.Credentials.Account, core.AzureRequest.Container))
	queries := u.Query()

	for key, values := range queries {
		sort.Strings(values)
		buffer.WriteString(fmt.Sprintf("\n%s:%s", key, strings.Join(values, ",")))
	}

	splitted := strings.Split(buffer.String(), "\n")
	sort.Strings(splitted)

	return strings.Join(splitted, "\n")
}

func (core Core) contentLength() (contentLength string) {
	if core.AzureRequest.Request.Method == "PUT" {
		contentLength = strconv.FormatInt(core.AzureRequest.Request.ContentLength, 10)
	}

	return
}

func (core Core) formattedRequestTime() string {
	return core.AzureRequest.RequestTime.Format(ms_date_layout)
}

/*
params:
 HTTP Verb
 Content-Encoding
 Content-Language
 Content-Length
 Content-MD5
 Content-Type
 Date
 If-Modified-Since
 If-Match
 If-None-Match
 If-Unmodified-Since
 Range
*/
func (core Core) signature() string {
	signature := fmt.Sprintf("%s\n\n\n%s\n\n%s\n\n\n\n\n\n\n%s\n%s",
		strings.ToUpper(core.AzureRequest.Method),
		core.contentLength(),
		core.AzureRequest.Request.Header.Get("Content-Type"),
		core.canonicalizedHeaders(),
		core.canonicalizedResource())

	decodedKey, _ := base64.StdEncoding.DecodeString(core.Credentials.AccessKey)

	sha256 := hmac.New(sha256.New, []byte(decodedKey))
	sha256.Write([]byte(signature))

	return base64.StdEncoding.EncodeToString(sha256.Sum(nil))
}

func (core Core) webService() string {
	return fmt.Sprintf("https://%s.blob.core.windows.net/", core.Credentials.Account)
}
<commit_msg>bug fix when the filename have any whitespace<commit_after>package core

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"sort"
	"strconv"
	"strings"
	"time"
)

const ms_date_layout = "Mon, 02 Jan 2006 15:04:05 GMT"
const version = "2009-09-19"

type Credentials struct {
	Account   string
	AccessKey string
}

type AzureRequest struct {
	Method      string
	Container   string
	Resource    string
	RequestTime time.Time
	Request     *http.Request
	Header      map[string]string
	Body        io.Reader
}

type Core struct {
	Credentials  Credentials
	AzureRequest AzureRequest
}

func New(credentials Credentials, azureRequest AzureRequest) *Core {
	return &Core{
		Credentials:  credentials,
		AzureRequest: azureRequest}
}

func (core Core) addCustomInformationsToHeader() {
	for key, value := range core.AzureRequest.Header {
		core.AzureRequest.Request.Header.Add(key, value)
	}
}

func (core Core) PrepareRequest() *http.Request {
	body := &bytes.Buffer{}

	if core.AzureRequest.Body != nil {
		io.Copy(body, core.AzureRequest.Body)
	}

	core.sanitizeContainer()

	req, err := http.NewRequest(strings.ToUpper(core.AzureRequest.Method), core.RequestUrl(), body)

	if err != nil {
		log.Fatal(err)
	}

	core.AzureRequest.Request = req
	core.addCustomInformationsToHeader()
	core.complementHeaderInformations()

	return req
}

func (core Core) RequestUrl() string {
	return fmt.Sprintf("%s%s%s", core.webService(), core.AzureRequest.Container, core.AzureRequest.Resource)
}

// Replace any whitespace character by %20 (default of URI)
func (core *Core) sanitizeContainer() {
	core.AzureRequest.Container = strings.Replace(core.AzureRequest.Container, " ", "%20", -1)
}

func (core Core) complementHeaderInformations() {
	core.AzureRequest.Request.Header.Add("x-ms-date", core.formattedRequestTime())
	core.AzureRequest.Request.Header.Add("x-ms-version", version)
	core.AzureRequest.Request.Header.Add("Authorization", core.authorizationHeader())
}

func (core Core) authorizationHeader() string {
	return fmt.Sprintf("SharedKey %s:%s", core.Credentials.Account, core.signature())
}

/*
Based on Azure docs:
  Link: http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx#Constructing_Element

  1) Retrieve all headers for the resource that begin with x-ms-, including the x-ms-date header.
  2) Convert each HTTP header name to lowercase.
  3) Sort the headers lexicographically by header name, in ascending order. Note that each header may appear only once in the string.
  4) Unfold the string by replacing any breaking white space with a single space.
  5) Trim any white space around the colon in the header.
  6) Finally, append a new line character to each canonicalized header in the resulting list. Construct the CanonicalizedHeaders string by concatenating all headers in this list into a single string.
*/
func (core Core) canonicalizedHeaders() string {
	var buffer bytes.Buffer

	for key, value := range core.AzureRequest.Request.Header {
		lowerKey := strings.ToLower(key)

		if strings.HasPrefix(lowerKey, "x-ms-") {
			if buffer.Len() == 0 {
				buffer.WriteString(fmt.Sprintf("%s:%s", lowerKey, value[0]))
			} else {
				buffer.WriteString(fmt.Sprintf("\n%s:%s", lowerKey, value[0]))
			}
		}
	}

	splitted := strings.Split(buffer.String(), "\n")
	sort.Strings(splitted)

	return strings.Join(splitted, "\n")
}

/*
Based on Azure docs
  Link: http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx#Constructing_Element

1) Beginning with an empty string (""), append a forward slash (/), followed by the name of the account that owns the resource being accessed.
2) Append the resource's encoded URI path, without any query parameters.
3) Retrieve all query parameters on the resource URI, including the comp parameter if it exists.
4) Convert all parameter names to lowercase.
5) Sort the query parameters lexicographically by parameter name, in ascending order.
6) URL-decode each query parameter name and value.
7) Append each query parameter name and value to the string in the following format, making sure to include the colon (:) between the name and the value:
    parameter-name:parameter-value

8) If a query parameter has more than one value, sort all values lexicographically, then include them in a comma-separated list:
    parameter-name:parameter-value-1,parameter-value-2,parameter-value-n

9) Append a new line character (\n) after each name-value pair.

Rules:
  1) Avoid using the new line character (\n) in values for query parameters. If it must be used, ensure that it does not affect the format of the canonicalized resource string.
  2) Avoid using commas in query parameter values.
*/
func (core Core) canonicalizedResource() string {
	var buffer bytes.Buffer

	u, err := url.Parse(core.RequestUrl())

	if err != nil {
		log.Fatal(err)
	}

	buffer.WriteString(fmt.Sprintf("/%s/%s", core.Credentials.Account, core.AzureRequest.Container))
	queries := u.Query()

	for key, values := range queries {
		sort.Strings(values)
		buffer.WriteString(fmt.Sprintf("\n%s:%s", key, strings.Join(values, ",")))
	}

	splitted := strings.Split(buffer.String(), "\n")
	sort.Strings(splitted)

	return strings.Join(splitted, "\n")
}

func (core Core) contentLength() (contentLength string) {
	if core.AzureRequest.Request.Method == "PUT" {
		contentLength = strconv.FormatInt(core.AzureRequest.Request.ContentLength, 10)
	}

	return
}

func (core Core) formattedRequestTime() string {
	return core.AzureRequest.RequestTime.Format(ms_date_layout)
}

/*
params:
 HTTP Verb
 Content-Encoding
 Content-Language
 Content-Length
 Content-MD5
 Content-Type
 Date
 If-Modified-Since
 If-Match
 If-None-Match
 If-Unmodified-Since
 Range
*/
func (core Core) signature() string {
	signature := fmt.Sprintf("%s\n\n\n%s\n\n%s\n\n\n\n\n\n\n%s\n%s",
		strings.ToUpper(core.AzureRequest.Method),
		core.contentLength(),
		core.AzureRequest.Request.Header.Get("Content-Type"),
		core.canonicalizedHeaders(),
		core.canonicalizedResource())

	decodedKey, _ := base64.StdEncoding.DecodeString(core.Credentials.AccessKey)

	sha256 := hmac.New(sha256.New, []byte(decodedKey))
	sha256.Write([]byte(signature))

	return base64.StdEncoding.EncodeToString(sha256.Sum(nil))
}

func (core Core) webService() string {
	return fmt.Sprintf("https://%s.blob.core.windows.net/", core.Credentials.Account)
}
<|endoftext|>