<commit_before>package ts

import "io"
import "log"
import "errors"
import "github.com/32bitkid/bitreader"

func NewReader(reader io.Reader) TransportStreamReader {
	br := bitreader.NewReader32(reader)
	return &tsReader{br}
}

type TransportStreamReader interface {
	Next() (*TsPacket, error)
}

type tsReader struct {
	bitreader.Reader32
}

const SyncByte = 0x47

type TsPacket struct {
	TransportErrorIndicator    bool
	PayloadUnitStartIndicator  bool
	TransportPriority          bool
	PID                        uint32
	TransportScramblingControl uint32
	AdaptationFieldControl     uint32
	ContinuityCounter          uint32
	Payload                    []byte
}

func (tsr *tsReader) Next() (*TsPacket, error) {

	if !tsr.isAligned() && !tsr.realign() {
		return nil, errors.New("No sync_byte found")
	}

	tsr.Trash(8)

	packet := TsPacket{
		TransportErrorIndicator:   tsr.ReadBit(),
		PayloadUnitStartIndicator: tsr.ReadBit(),
		TransportPriority:         tsr.ReadBit(),
		PID:                       tsr.Read32(13),
		TransportScramblingControl: tsr.Read32(2),
		AdaptationFieldControl:     tsr.Read32(2),
		ContinuityCounter:          tsr.Read32(4),
		Payload:                    make([]byte, 184),
	}

	for i := 0; i < 184; i++ {
		packet.Payload[i] = byte(tsr.Read32(8))
	}

	return &packet, nil
}

func (tsr *tsReader) isAligned() bool {
	return tsr.Peek32(8) == SyncByte
}

func (tsr *tsReader) realign() bool {
	log.Printf("Attempting to realign")
	for i := 0; i < 188; i++ {
		if tsr.isAligned() {
			log.Printf("Realigned after %d bytes.\n", i)
			return true
		}
		tsr.Trash(8)
	}
	return false
}
<commit_msg>Adding error handling from bitreader interface<commit_after>package ts

import "io"
import "log"
import "errors"
import "github.com/32bitkid/bitreader"

func NewReader(reader io.Reader) TransportStreamReader {
	br := bitreader.NewReader32(reader)
	return &tsReader{br}
}

type TransportStreamReader interface {
	Next() (*TsPacket, error)
}

type tsReader struct {
	bitreader.Reader32
}

const SyncByte = 0x47

type TsPacket struct {
	TransportErrorIndicator    bool
	PayloadUnitStartIndicator  bool
	TransportPrriority         bool
	PID                        uint32
	TransportScramblingControl uint32
	AdaptationFieldControl     uint32
	ContinuityCounter          uint32
	Payload                    []byte
}

func isFatalErr(err error) bool {
	return err != nil && err != io.EOF
}

func (tsr *tsReader) Next() (*TsPacket, error) {

	var err error

	aligned, err := tsr.isAligned()
	if isFatalErr(err) {
		return nil, err
	}

	if !aligned {
		err = tsr.realign()
		if isFatalErr(err) {
			return nil, err
		}
	}

	if err = tsr.Trash(8); isFatalErr(err) {
		return nil, err
	}

	packet := TsPacket{}

	packet.TransportErrorIndicator, err = tsr.ReadBit()
	if isFatalErr(err) {
		return nil, err
	}

	packet.PayloadUnitStartIndicator, err = tsr.ReadBit()
	if isFatalErr(err) {
		return nil, err
	}

	packet.TransportPrriority, err = tsr.ReadBit()
	if isFatalErr(err) {
		return nil, err
	}

	packet.PID, err = tsr.Read32(13)
	if isFatalErr(err) {
		return nil, err
	}

	packet.TransportScramblingControl, err = tsr.Read32(2)
	if isFatalErr(err) {
		return nil, err
	}

	packet.AdaptationFieldControl, err = tsr.Read32(2)
	if isFatalErr(err) {
		return nil, err
	}

	packet.ContinuityCounter, err = tsr.Read32(4)
	if isFatalErr(err) {
		return nil, err
	}

	// TODO handle adaptation field

	packet.Payload = make([]byte, 184)

	var val uint32
	for i := 0; i < 184; i++ {
		val, err = tsr.Read32(8)
		if isFatalErr(err) {
			return nil, err
		}
		packet.Payload[i] = byte(val)
	}

	return &packet, nil
}

func (tsr *tsReader) isAligned() (bool, error) {
	val, err := tsr.Peek32(8)
	return val == SyncByte, err
}

func (tsr *tsReader) realign() error {
	log.Printf("Attempting to realign")
	for i := 0; i < 188; i++ {
		tsr.Trash(8)
		isAligned, err := tsr.isAligned()
		if err != nil {
			return err
		}
		if isAligned {
			log.Printf("Realigned after %d bytes.\n", i)
			return nil
		}
	}
	return errors.New("Unable to find SyncByte")
}
<|endoftext|>


<commit_before>// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package maas

import (
	"github.com/juju/errors"
	"github.com/juju/gomaasapi"
	jc "github.com/juju/testing/checkers"
	"github.com/juju/utils/set"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/feature"
	coretesting "github.com/juju/juju/testing"
	"github.com/juju/juju/version"
)

type maas2Suite struct {
	baseProviderSuite
}

func (suite *maas2Suite) SetUpTest(c *gc.C) {
	suite.baseProviderSuite.SetUpTest(c)
	suite.SetFeatureFlags(feature.MAAS2)
}

func (suite *maas2Suite) injectController(controller gomaasapi.Controller) {
	mockGetController := func(maasServer, apiKey string) (gomaasapi.Controller, error) {
		return controller, nil
	}
	suite.PatchValue(&GetMAAS2Controller, mockGetController)
}

func (suite *maas2Suite) makeEnviron(c *gc.C, controller gomaasapi.Controller) *maasEnviron {
	if controller != nil {
		suite.injectController(controller)
	}
	testAttrs := coretesting.Attrs{}
	for k, v := range maasEnvAttrs {
		testAttrs[k] = v
	}
	testAttrs["maas-server"] = "http://any-old-junk.invalid/"
	testAttrs["agent-version"] = version.Current.String()
	testAttrs["maas-agent-name"] = "agent-prefix"

	attrs := coretesting.FakeConfig().Merge(testAttrs)
	cfg, err := config.New(config.NoDefaults, attrs)
	c.Assert(err, jc.ErrorIsNil)
	env, err := NewEnviron(cfg)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(env, gc.NotNil)
	return env
}

type fakeController struct {
	gomaasapi.Controller
	bootResources      []gomaasapi.BootResource
	bootResourcesError error
	machines           []gomaasapi.Machine
	machinesError      error
	machinesArgsCheck  func(gomaasapi.MachinesArgs)
	zones              []gomaasapi.Zone
	zonesError         error
	spaces             []gomaasapi.Space
	spacesError        error

	allocateMachine          gomaasapi.Machine
	allocateMachineMatches   gomaasapi.ConstraintMatches
	allocateMachineError     error
	allocateMachineArgsCheck func(gomaasapi.AllocateMachineArgs)

	files           []gomaasapi.File
	filesPrefix     string
	filesError      error
	getFileFilename string
	addFileArgs     gomaasapi.AddFileArgs

	releaseMachinesErrors []error
	releaseMachinesArgs   []gomaasapi.ReleaseMachinesArgs
}

func (c *fakeController) Machines(args gomaasapi.MachinesArgs) ([]gomaasapi.Machine, error) {
	if c.machinesArgsCheck != nil {
		c.machinesArgsCheck(args)
	}
	if c.machinesError != nil {
		return nil, c.machinesError
	}
	if len(args.SystemIDs) > 0 {
		result := []gomaasapi.Machine{}
		systemIds := set.NewStrings(args.SystemIDs...)
		for _, machine := range c.machines {
			if systemIds.Contains(machine.SystemID()) {
				result = append(result, machine)
			}
		}
		return result, nil
	}
	return c.machines, nil
}

func (c *fakeController) AllocateMachine(args gomaasapi.AllocateMachineArgs) (gomaasapi.Machine, gomaasapi.ConstraintMatches, error) {
	if c.allocateMachineArgsCheck != nil {
		c.allocateMachineArgsCheck(args)
	}
	if c.allocateMachineError != nil {
		return nil, c.allocateMachineMatches, c.allocateMachineError
	}
	return c.allocateMachine, c.allocateMachineMatches, nil
}

func (c *fakeController) BootResources() ([]gomaasapi.BootResource, error) {
	if c.bootResourcesError != nil {
		return nil, c.bootResourcesError
	}
	return c.bootResources, nil
}

func (c *fakeController) Zones() ([]gomaasapi.Zone, error) {
	if c.zonesError != nil {
		return nil, c.zonesError
	}
	return c.zones, nil
}

func (c *fakeController) Spaces() ([]gomaasapi.Space, error) {
	if c.spacesError != nil {
		return nil, c.spacesError
	}
	return c.spaces, nil
}

func (c *fakeController) Files(prefix string) ([]gomaasapi.File, error) {
	c.filesPrefix = prefix
	if c.filesError != nil {
		return nil, c.filesError
	}
	return c.files, nil
}

func (c *fakeController) GetFile(filename string) (gomaasapi.File, error) {
	c.getFileFilename = filename
	if c.filesError != nil {
		return nil, c.filesError
	}
	// Try to find the file by name (needed for testing RemoveAll)
	for _, file := range c.files {
		if file.Filename() == filename {
			return file, nil
		}
	}
	// The test forgot to set up matching files!
	return nil, errors.Errorf("no file named %v found - did you set up your test correctly?", filename)
}

func (c *fakeController) AddFile(args gomaasapi.AddFileArgs) error {
	c.addFileArgs = args
	return c.filesError
}

func (c *fakeController) ReleaseMachines(args gomaasapi.ReleaseMachinesArgs) error {
	c.releaseMachinesArgs = append(c.releaseMachinesArgs, args)
	if len(c.releaseMachinesErrors) == 0 {
		return nil
	}
	err := c.releaseMachinesErrors[0]
	c.releaseMachinesErrors = c.releaseMachinesErrors[1:]
	return err
}

type fakeBootResource struct {
	gomaasapi.BootResource
	name         string
	architecture string
}

func (r *fakeBootResource) Name() string {
	return r.name
}

func (r *fakeBootResource) Architecture() string {
	return r.architecture
}

type fakeMachine struct {
	gomaasapi.Machine
	zoneName      string
	hostname      string
	systemID      string
	ipAddresses   []string
	statusName    string
	statusMessage string
	cpuCount      int
	memory        int
	architecture  string
	interfaceSet  []gomaasapi.Interface
}

func (m *fakeMachine) CPUCount() int {
	return m.cpuCount
}

func (m *fakeMachine) Memory() int {
	return m.memory
}

func (m *fakeMachine) Architecture() string {
	return m.architecture
}

func (m *fakeMachine) SystemID() string {
	return m.systemID
}

func (m *fakeMachine) Hostname() string {
	return m.hostname
}

func (m *fakeMachine) IPAddresses() []string {
	return m.ipAddresses
}

func (m *fakeMachine) StatusName() string {
	return m.statusName
}

func (m *fakeMachine) StatusMessage() string {
	return m.statusMessage
}

func (m *fakeMachine) Zone() gomaasapi.Zone {
	return fakeZone{name: m.zoneName}
}

func (m *fakeMachine) InterfaceSet() []gomaasapi.Interface {
	return m.interfaceSet
}

func (m *fakeMachine) Start(args gomaasapi.StartArgs) error {
	return nil
}

type fakeZone struct {
	gomaasapi.Zone
	name string
}

func (z fakeZone) Name() string {
	return z.name
}

type fakeSpace struct {
	gomaasapi.Space
	name    string
	id      int
	subnets []gomaasapi.Subnet
}

func (s fakeSpace) Name() string {
	return s.name
}

func (s fakeSpace) ID() int {
	return s.id
}

func (s fakeSpace) Subnets() []gomaasapi.Subnet {
	return s.subnets
}

type fakeSubnet struct {
	gomaasapi.Subnet
	id         int
	space      string
	vlan       gomaasapi.VLAN
	gateway    string
	cidr       string
	dnsServers []string
}

func (s fakeSubnet) ID() int {
	return s.id
}

func (s fakeSubnet) Space() string {
	return s.space
}

func (s fakeSubnet) VLAN() gomaasapi.VLAN {
	return s.vlan
}

func (s fakeSubnet) Gateway() string {
	return s.gateway
}

func (s fakeSubnet) CIDR() string {
	return s.cidr
}

func (s fakeSubnet) DNSServers() []string {
	return s.dnsServers
}

type fakeVLAN struct {
	gomaasapi.VLAN
	id  int
	vid int
	mtu int
}

func (v fakeVLAN) ID() int {
	return v.id
}

func (v fakeVLAN) VID() int {
	return v.vid
}

func (v fakeVLAN) MTU() int {
	return v.mtu
}

type fakeInterface struct {
	gomaasapi.Interface
	id         int
	name       string
	parents    []string
	children   []string
	type_      string
	enabled    bool
	vlan       gomaasapi.VLAN
	links      []gomaasapi.Link
	macAddress string
}

func (v *fakeInterface) ID() int {
	return v.id
}

func (v *fakeInterface) Name() string {
	return v.name
}

func (v *fakeInterface) Parents() []string {
	return v.parents
}

func (v *fakeInterface) Children() []string {
	return v.children
}

func (v *fakeInterface) Type() string {
	return v.type_
}

func (v *fakeInterface) Enabled() bool {
	return v.enabled
}

func (v *fakeInterface) VLAN() gomaasapi.VLAN {
	return v.vlan
}

func (v *fakeInterface) Links() []gomaasapi.Link {
	return v.links
}

func (v *fakeInterface) MACAddress() string {
	return v.macAddress
}

type fakeLink struct {
	gomaasapi.Link
	id        int
	mode      string
	subnet    gomaasapi.Subnet
	ipAddress string
}

func (l *fakeLink) ID() int {
	return l.id
}

func (l *fakeLink) Mode() string {
	return l.mode
}

func (l *fakeLink) Subnet() gomaasapi.Subnet {
	return l.subnet
}

func (l *fakeLink) IPAddress() string {
	return l.ipAddress
}

type fakeFile struct {
	gomaasapi.File
	name     string
	url      string
	contents []byte
	deleted  bool
	error    error
}

func (f *fakeFile) Filename() string {
	return f.name
}

func (f *fakeFile) AnonymousURL() string {
	return f.url
}

func (f *fakeFile) Delete() error {
	f.deleted = true
	return f.error
}

func (f *fakeFile) ReadAll() ([]byte, error) {
	if f.error != nil {
		return nil, f.error
	}
	return f.contents, nil
}
<commit_msg>Add fakeBlockDevice for testing<commit_after>// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package maas

import (
	"github.com/juju/errors"
	"github.com/juju/gomaasapi"
	jc "github.com/juju/testing/checkers"
	"github.com/juju/utils/set"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/feature"
	coretesting "github.com/juju/juju/testing"
	"github.com/juju/juju/version"
)

type maas2Suite struct {
	baseProviderSuite
}

func (suite *maas2Suite) SetUpTest(c *gc.C) {
	suite.baseProviderSuite.SetUpTest(c)
	suite.SetFeatureFlags(feature.MAAS2)
}

func (suite *maas2Suite) injectController(controller gomaasapi.Controller) {
	mockGetController := func(maasServer, apiKey string) (gomaasapi.Controller, error) {
		return controller, nil
	}
	suite.PatchValue(&GetMAAS2Controller, mockGetController)
}

func (suite *maas2Suite) makeEnviron(c *gc.C, controller gomaasapi.Controller) *maasEnviron {
	if controller != nil {
		suite.injectController(controller)
	}
	testAttrs := coretesting.Attrs{}
	for k, v := range maasEnvAttrs {
		testAttrs[k] = v
	}
	testAttrs["maas-server"] = "http://any-old-junk.invalid/"
	testAttrs["agent-version"] = version.Current.String()
	testAttrs["maas-agent-name"] = "agent-prefix"

	attrs := coretesting.FakeConfig().Merge(testAttrs)
	cfg, err := config.New(config.NoDefaults, attrs)
	c.Assert(err, jc.ErrorIsNil)
	env, err := NewEnviron(cfg)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(env, gc.NotNil)
	return env
}

type fakeController struct {
	gomaasapi.Controller
	bootResources      []gomaasapi.BootResource
	bootResourcesError error
	machines           []gomaasapi.Machine
	machinesError      error
	machinesArgsCheck  func(gomaasapi.MachinesArgs)
	zones              []gomaasapi.Zone
	zonesError         error
	spaces             []gomaasapi.Space
	spacesError        error

	allocateMachine          gomaasapi.Machine
	allocateMachineMatches   gomaasapi.ConstraintMatches
	allocateMachineError     error
	allocateMachineArgsCheck func(gomaasapi.AllocateMachineArgs)

	files           []gomaasapi.File
	filesPrefix     string
	filesError      error
	getFileFilename string
	addFileArgs     gomaasapi.AddFileArgs

	releaseMachinesErrors []error
	releaseMachinesArgs   []gomaasapi.ReleaseMachinesArgs
}

func (c *fakeController) Machines(args gomaasapi.MachinesArgs) ([]gomaasapi.Machine, error) {
	if c.machinesArgsCheck != nil {
		c.machinesArgsCheck(args)
	}
	if c.machinesError != nil {
		return nil, c.machinesError
	}
	if len(args.SystemIDs) > 0 {
		result := []gomaasapi.Machine{}
		systemIds := set.NewStrings(args.SystemIDs...)
		for _, machine := range c.machines {
			if systemIds.Contains(machine.SystemID()) {
				result = append(result, machine)
			}
		}
		return result, nil
	}
	return c.machines, nil
}

func (c *fakeController) AllocateMachine(args gomaasapi.AllocateMachineArgs) (gomaasapi.Machine, gomaasapi.ConstraintMatches, error) {
	if c.allocateMachineArgsCheck != nil {
		c.allocateMachineArgsCheck(args)
	}
	if c.allocateMachineError != nil {
		return nil, c.allocateMachineMatches, c.allocateMachineError
	}
	return c.allocateMachine, c.allocateMachineMatches, nil
}

func (c *fakeController) BootResources() ([]gomaasapi.BootResource, error) {
	if c.bootResourcesError != nil {
		return nil, c.bootResourcesError
	}
	return c.bootResources, nil
}

func (c *fakeController) Zones() ([]gomaasapi.Zone, error) {
	if c.zonesError != nil {
		return nil, c.zonesError
	}
	return c.zones, nil
}

func (c *fakeController) Spaces() ([]gomaasapi.Space, error) {
	if c.spacesError != nil {
		return nil, c.spacesError
	}
	return c.spaces, nil
}

func (c *fakeController) Files(prefix string) ([]gomaasapi.File, error) {
	c.filesPrefix = prefix
	if c.filesError != nil {
		return nil, c.filesError
	}
	return c.files, nil
}

func (c *fakeController) GetFile(filename string) (gomaasapi.File, error) {
	c.getFileFilename = filename
	if c.filesError != nil {
		return nil, c.filesError
	}
	// Try to find the file by name (needed for testing RemoveAll)
	for _, file := range c.files {
		if file.Filename() == filename {
			return file, nil
		}
	}
	// The test forgot to set up matching files!
	return nil, errors.Errorf("no file named %v found - did you set up your test correctly?", filename)
}

func (c *fakeController) AddFile(args gomaasapi.AddFileArgs) error {
	c.addFileArgs = args
	return c.filesError
}

func (c *fakeController) ReleaseMachines(args gomaasapi.ReleaseMachinesArgs) error {
	c.releaseMachinesArgs = append(c.releaseMachinesArgs, args)
	if len(c.releaseMachinesErrors) == 0 {
		return nil
	}
	err := c.releaseMachinesErrors[0]
	c.releaseMachinesErrors = c.releaseMachinesErrors[1:]
	return err
}

type fakeBootResource struct {
	gomaasapi.BootResource
	name         string
	architecture string
}

func (r *fakeBootResource) Name() string {
	return r.name
}

func (r *fakeBootResource) Architecture() string {
	return r.architecture
}

type fakeMachine struct {
	gomaasapi.Machine
	zoneName      string
	hostname      string
	systemID      string
	ipAddresses   []string
	statusName    string
	statusMessage string
	cpuCount      int
	memory        int
	architecture  string
	interfaceSet  []gomaasapi.Interface
}

func (m *fakeMachine) CPUCount() int {
	return m.cpuCount
}

func (m *fakeMachine) Memory() int {
	return m.memory
}

func (m *fakeMachine) Architecture() string {
	return m.architecture
}

func (m *fakeMachine) SystemID() string {
	return m.systemID
}

func (m *fakeMachine) Hostname() string {
	return m.hostname
}

func (m *fakeMachine) IPAddresses() []string {
	return m.ipAddresses
}

func (m *fakeMachine) StatusName() string {
	return m.statusName
}

func (m *fakeMachine) StatusMessage() string {
	return m.statusMessage
}

func (m *fakeMachine) Zone() gomaasapi.Zone {
	return fakeZone{name: m.zoneName}
}

func (m *fakeMachine) InterfaceSet() []gomaasapi.Interface {
	return m.interfaceSet
}

func (m *fakeMachine) Start(args gomaasapi.StartArgs) error {
	return nil
}

type fakeZone struct {
	gomaasapi.Zone
	name string
}

func (z fakeZone) Name() string {
	return z.name
}

type fakeSpace struct {
	gomaasapi.Space
	name    string
	id      int
	subnets []gomaasapi.Subnet
}

func (s fakeSpace) Name() string {
	return s.name
}

func (s fakeSpace) ID() int {
	return s.id
}

func (s fakeSpace) Subnets() []gomaasapi.Subnet {
	return s.subnets
}

type fakeSubnet struct {
	gomaasapi.Subnet
	id         int
	space      string
	vlan       gomaasapi.VLAN
	gateway    string
	cidr       string
	dnsServers []string
}

func (s fakeSubnet) ID() int {
	return s.id
}

func (s fakeSubnet) Space() string {
	return s.space
}

func (s fakeSubnet) VLAN() gomaasapi.VLAN {
	return s.vlan
}

func (s fakeSubnet) Gateway() string {
	return s.gateway
}

func (s fakeSubnet) CIDR() string {
	return s.cidr
}

func (s fakeSubnet) DNSServers() []string {
	return s.dnsServers
}

type fakeVLAN struct {
	gomaasapi.VLAN
	id  int
	vid int
	mtu int
}

func (v fakeVLAN) ID() int {
	return v.id
}

func (v fakeVLAN) VID() int {
	return v.vid
}

func (v fakeVLAN) MTU() int {
	return v.mtu
}

type fakeInterface struct {
	gomaasapi.Interface
	id         int
	name       string
	parents    []string
	children   []string
	type_      string
	enabled    bool
	vlan       gomaasapi.VLAN
	links      []gomaasapi.Link
	macAddress string
}

func (v *fakeInterface) ID() int {
	return v.id
}

func (v *fakeInterface) Name() string {
	return v.name
}

func (v *fakeInterface) Parents() []string {
	return v.parents
}

func (v *fakeInterface) Children() []string {
	return v.children
}

func (v *fakeInterface) Type() string {
	return v.type_
}

func (v *fakeInterface) Enabled() bool {
	return v.enabled
}

func (v *fakeInterface) VLAN() gomaasapi.VLAN {
	return v.vlan
}

func (v *fakeInterface) Links() []gomaasapi.Link {
	return v.links
}

func (v *fakeInterface) MACAddress() string {
	return v.macAddress
}

type fakeLink struct {
	gomaasapi.Link
	id        int
	mode      string
	subnet    gomaasapi.Subnet
	ipAddress string
}

func (l *fakeLink) ID() int {
	return l.id
}

func (l *fakeLink) Mode() string {
	return l.mode
}

func (l *fakeLink) Subnet() gomaasapi.Subnet {
	return l.subnet
}

func (l *fakeLink) IPAddress() string {
	return l.ipAddress
}

type fakeFile struct {
	gomaasapi.File
	name     string
	url      string
	contents []byte
	deleted  bool
	error    error
}

func (f *fakeFile) Filename() string {
	return f.name
}

func (f *fakeFile) AnonymousURL() string {
	return f.url
}

func (f *fakeFile) Delete() error {
	f.deleted = true
	return f.error
}

func (f *fakeFile) ReadAll() ([]byte, error) {
	if f.error != nil {
		return nil, f.error
	}
	return f.contents, nil
}

type fakeBlockDevice struct {
	gomaasapi.BlockDevice
	name string
	size int
}

func (bd fakeBlockDevice) Name() string {
	return bd.name
}

func (bd fakeBlockDevice) Size() int {
	return bd.size
}
<|endoftext|>


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

package docker

import (
	"errors"
	"github.com/fsouza/go-dockerclient"
	"github.com/globocom/tsuru/action"
	"github.com/globocom/tsuru/app"
	"github.com/globocom/tsuru/db"
	"github.com/globocom/tsuru/log"
	"github.com/globocom/tsuru/provision"
	"github.com/globocom/tsuru/queue"
	"labix.org/v2/mgo/bson"
	"net"
	"strings"
)

var createContainer = action.Action{
	Name: "create-container",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		app := ctx.Params[0].(provision.App)
		imageId := ctx.Params[1].(string)
		cmds := ctx.Params[2].([]string)
		log.Debugf("create container for app %s, based on image %s, with cmds %s", app.GetName(), imageId, cmds)
		cont, err := newContainer(app, imageId, cmds)
		if err != nil {
			log.Errorf("error on create container for app %s - %s", app.GetName(), err)
			return nil, err
		}
		return cont, nil
	},
	Backward: func(ctx action.BWContext) {
		c := ctx.FWResult.(container)
		dockerCluster().RemoveContainer(docker.RemoveContainerOptions{ID: c.ID})
		coll := collection()
		defer coll.Close()
		coll.Remove(bson.M{"id": c.ID})
	},
}

var setNetworkInfo = action.Action{
	Name: "set-network-info",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		c := ctx.Previous.(container)
		ip, hostPort, err := c.networkInfo()
		if err != nil {
			return nil, err
		}
		c.IP = ip
		c.HostPort = hostPort
		return c, nil
	},
}

var addRoute = action.Action{
	Name: "add-route",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		c := ctx.Previous.(container)
		r, err := getRouter()
		if err != nil {
			return nil, err
		}
		err = r.AddRoute(c.AppName, c.getAddress())
		return c, err
	},
	Backward: func(ctx action.BWContext) {
	},
}

var startContainer = action.Action{
	Name: "start-container",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		c := ctx.Previous.(container)
		log.Debugf("starting container %s", c.ID)
		err := c.start()
		if err != nil {
			log.Errorf("error on start container %s - %s", c.ID, err)
			return nil, err
		}
		return c, nil
	},
	Backward: func(ctx action.BWContext) {
		c := ctx.FWResult.(container)
		err := dockerCluster().StopContainer(c.ID, 10)
		if err != nil {
			log.Errorf("Failed to stop the container %q: %s", c.ID, err)
		}
	},
}

var injectEnvirons = action.Action{
	Name: "inject-environs",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		app, ok := ctx.Params[0].(provision.App)
		if !ok {
			return nil, errors.New("First parameter must be a provision.App.")
		}
		go injectEnvsAndRestart(app)
		return nil, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var saveUnits = action.Action{
	Name: "save-units",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		a, ok := ctx.Params[0].(*app.App)
		if !ok {
			return nil, errors.New("First parameter must be a *app.App.")
		}
		a, err := app.GetByName(a.Name)
		if err != nil {
			return nil, err
		}
		containers, err := listAppContainers(a.GetName())
		if err != nil {
			return nil, err
		}
		for _, c := range containers {
			var status string
			addr := strings.Replace(c.getAddress(), "http://", "", 1)
			conn, err := net.Dial("tcp", addr)
			if err != nil {
				status = provision.StatusUnreachable.String()
			} else {
				conn.Close()
				status = provision.StatusStarted.String()
			}
			u := app.Unit{
				Name:  c.ID,
				Type:  c.Type,
				Ip:    c.HostAddr,
				State: status,
			}
			a.AddUnit(&u)
		}
		conn, err := db.Conn()
		if err != nil {
			return nil, err
		}
		defer conn.Close()
		conn.Apps().Update(bson.M{"name": a.Name}, a)
		return nil, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var bindService = action.Action{
	Name: "bind-service",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		a, ok := ctx.Params[0].(provision.App)
		if !ok {
			return nil, errors.New("First parameter must be a provision.App.")
		}
		for _, u := range a.ProvisionedUnits() {
			msg := queue.Message{
				Action: app.BindService,
				Args:   []string{a.GetName(), u.GetName()},
			}
			go app.Enqueue(msg)
		}
		return nil, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}
<commit_msg>docker: removing container from name in createContainer backward.<commit_after>// Copyright 2014 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package docker

import (
	"errors"
	"github.com/fsouza/go-dockerclient"
	"github.com/globocom/tsuru/action"
	"github.com/globocom/tsuru/app"
	"github.com/globocom/tsuru/db"
	"github.com/globocom/tsuru/log"
	"github.com/globocom/tsuru/provision"
	"github.com/globocom/tsuru/queue"
	"labix.org/v2/mgo/bson"
	"net"
	"strings"
)

var createContainer = action.Action{
	Name: "create-container",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		app := ctx.Params[0].(provision.App)
		imageId := ctx.Params[1].(string)
		cmds := ctx.Params[2].([]string)
		log.Debugf("create container for app %s, based on image %s, with cmds %s", app.GetName(), imageId, cmds)
		cont, err := newContainer(app, imageId, cmds)
		if err != nil {
			log.Errorf("error on create container for app %s - %s", app.GetName(), err)
			return nil, err
		}
		return cont, nil
	},
	Backward: func(ctx action.BWContext) {
		c := ctx.FWResult.(container)
		dockerCluster().RemoveContainer(docker.RemoveContainerOptions{ID: c.ID})
		coll := collection()
		defer coll.Close()
		coll.Remove(bson.M{"name": c.Name})
	},
}

var setNetworkInfo = action.Action{
	Name: "set-network-info",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		c := ctx.Previous.(container)
		ip, hostPort, err := c.networkInfo()
		if err != nil {
			return nil, err
		}
		c.IP = ip
		c.HostPort = hostPort
		return c, nil
	},
}

var addRoute = action.Action{
	Name: "add-route",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		c := ctx.Previous.(container)
		r, err := getRouter()
		if err != nil {
			return nil, err
		}
		err = r.AddRoute(c.AppName, c.getAddress())
		return c, err
	},
	Backward: func(ctx action.BWContext) {
	},
}

var startContainer = action.Action{
	Name: "start-container",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		c := ctx.Previous.(container)
		log.Debugf("starting container %s", c.ID)
		err := c.start()
		if err != nil {
			log.Errorf("error on start container %s - %s", c.ID, err)
			return nil, err
		}
		return c, nil
	},
	Backward: func(ctx action.BWContext) {
		c := ctx.FWResult.(container)
		err := dockerCluster().StopContainer(c.ID, 10)
		if err != nil {
			log.Errorf("Failed to stop the container %q: %s", c.ID, err)
		}
	},
}

var injectEnvirons = action.Action{
	Name: "inject-environs",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		app, ok := ctx.Params[0].(provision.App)
		if !ok {
			return nil, errors.New("First parameter must be a provision.App.")
		}
		go injectEnvsAndRestart(app)
		return nil, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var saveUnits = action.Action{
	Name: "save-units",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		a, ok := ctx.Params[0].(*app.App)
		if !ok {
			return nil, errors.New("First parameter must be a *app.App.")
		}
		a, err := app.GetByName(a.Name)
		if err != nil {
			return nil, err
		}
		containers, err := listAppContainers(a.GetName())
		if err != nil {
			return nil, err
		}
		for _, c := range containers {
			var status string
			addr := strings.Replace(c.getAddress(), "http://", "", 1)
			conn, err := net.Dial("tcp", addr)
			if err != nil {
				status = provision.StatusUnreachable.String()
			} else {
				conn.Close()
				status = provision.StatusStarted.String()
			}
			u := app.Unit{
				Name:  c.ID,
				Type:  c.Type,
				Ip:    c.HostAddr,
				State: status,
			}
			a.AddUnit(&u)
		}
		conn, err := db.Conn()
		if err != nil {
			return nil, err
		}
		defer conn.Close()
		conn.Apps().Update(bson.M{"name": a.Name}, a)
		return nil, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}

var bindService = action.Action{
	Name: "bind-service",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		a, ok := ctx.Params[0].(provision.App)
		if !ok {
			return nil, errors.New("First parameter must be a provision.App.")
		}
		for _, u := range a.ProvisionedUnits() {
			msg := queue.Message{
				Action: app.BindService,
				Args:   []string{a.GetName(), u.GetName()},
			}
			go app.Enqueue(msg)
		}
		return nil, nil
	},
	Backward: func(ctx action.BWContext) {
	},
}
<|endoftext|>


<commit_before>package shadowsocks

import (
	"context"

	"v2ray.com/core"
	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/protocol"
	"v2ray.com/core/common/retry"
	"v2ray.com/core/common/signal"
	"v2ray.com/core/proxy"
	"v2ray.com/core/transport/internet"
	"v2ray.com/core/transport/ray"
)

// Client is a inbound handler for Shadowsocks protocol
type Client struct {
	serverPicker protocol.ServerPicker
	v            *core.Instance
}

// NewClient create a new Shadowsocks client.
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
	serverList := protocol.NewServerList()
	for _, rec := range config.Server {
		serverList.AddServer(protocol.NewServerSpecFromPB(*rec))
	}
	if serverList.Size() == 0 {
		return nil, newError("0 server")
	}
	client := &Client{
		serverPicker: protocol.NewRoundRobinServerPicker(serverList),
		v:            core.MustFromContext(ctx),
	}
	return client, nil
}

// Process implements OutboundHandler.Process().
func (v *Client) Process(ctx context.Context, outboundRay ray.OutboundRay, dialer proxy.Dialer) error {
	destination, ok := proxy.TargetFromContext(ctx)
	if !ok {
		return newError("target not specified")
	}
	network := destination.Network

	var server *protocol.ServerSpec
	var conn internet.Connection

	err := retry.ExponentialBackoff(5, 100).On(func() error {
		server = v.serverPicker.PickServer()
		dest := server.Destination()
		dest.Network = network
		rawConn, err := dialer.Dial(ctx, dest)
		if err != nil {
			return err
		}
		conn = rawConn

		return nil
	})
	if err != nil {
		return newError("failed to find an available destination").AtWarning().Base(err)
	}
	newError("tunneling request to ", destination, " via ", server.Destination()).WriteToLog()

	defer conn.Close()

	request := &protocol.RequestHeader{
		Version: Version,
		Address: destination.Address,
		Port:    destination.Port,
	}
	if destination.Network == net.Network_TCP {
		request.Command = protocol.RequestCommandTCP
	} else {
		request.Command = protocol.RequestCommandUDP
	}

	user := server.PickUser()
	rawAccount, err := user.GetTypedAccount()
	if err != nil {
		return newError("failed to get a valid user account").AtWarning().Base(err)
	}
	account := rawAccount.(*MemoryAccount)
	request.User = user

	if account.OneTimeAuth == Account_Auto || account.OneTimeAuth == Account_Enabled {
		request.Option |= RequestOptionOneTimeAuth
	}

	sessionPolicy := v.v.PolicyManager().ForLevel(user.Level)
	ctx, cancel := context.WithCancel(ctx)
	timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)

	if request.Command == protocol.RequestCommandTCP {
		bufferedWriter := buf.NewBufferedWriter(buf.NewWriter(conn))
		bodyWriter, err := WriteTCPRequest(request, bufferedWriter)
		if err != nil {
			return newError("failed to write request").Base(err)
		}

		if err := bufferedWriter.SetBuffered(false); err != nil {
			return err
		}

		requestDone := signal.ExecuteAsync(func() error {
			defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
			return buf.Copy(outboundRay.OutboundInput(), bodyWriter, buf.UpdateActivity(timer))
		})

		responseDone := signal.ExecuteAsync(func() error {
			defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)

			responseReader, err := ReadTCPResponse(user, conn)
			if err != nil {
				return err
			}

			return buf.Copy(responseReader, outboundRay.OutboundOutput(), buf.UpdateActivity(timer))
		})

		if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
			return newError("connection ends").Base(err)
		}

		return nil
	}

	if request.Command == protocol.RequestCommandUDP {

		writer := buf.NewSequentialWriter(&UDPWriter{
			Writer:  conn,
			Request: request,
		})

		requestDone := signal.ExecuteAsync(func() error {
			defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)

			if err := buf.Copy(outboundRay.OutboundInput(), writer, buf.UpdateActivity(timer)); err != nil {
				return newError("failed to transport all UDP request").Base(err)
			}
			return nil
		})

		responseDone := signal.ExecuteAsync(func() error {
			defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)

			reader := &UDPReader{
				Reader: conn,
				User:   user,
			}

			if err := buf.Copy(reader, outboundRay.OutboundOutput(), buf.UpdateActivity(timer)); err != nil {
				return newError("failed to transport all UDP response").Base(err)
			}
			return nil
		})

		if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
			return newError("connection ends").Base(err)
		}

		return nil
	}

	return nil
}

func init() {
	common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
		return NewClient(ctx, config.(*ClientConfig))
	}))
}
<commit_msg>trace context<commit_after>package shadowsocks

import (
	"context"

	"v2ray.com/core"
	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/protocol"
	"v2ray.com/core/common/retry"
	"v2ray.com/core/common/signal"
	"v2ray.com/core/proxy"
	"v2ray.com/core/transport/internet"
	"v2ray.com/core/transport/ray"
)

// Client is a inbound handler for Shadowsocks protocol
type Client struct {
	serverPicker protocol.ServerPicker
	v            *core.Instance
}

// NewClient create a new Shadowsocks client.
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
	serverList := protocol.NewServerList()
	for _, rec := range config.Server {
		serverList.AddServer(protocol.NewServerSpecFromPB(*rec))
	}
	if serverList.Size() == 0 {
		return nil, newError("0 server")
	}
	client := &Client{
		serverPicker: protocol.NewRoundRobinServerPicker(serverList),
		v:            core.MustFromContext(ctx),
	}
	return client, nil
}

// Process implements OutboundHandler.Process().
func (v *Client) Process(ctx context.Context, outboundRay ray.OutboundRay, dialer proxy.Dialer) error {
	destination, ok := proxy.TargetFromContext(ctx)
	if !ok {
		return newError("target not specified")
	}
	network := destination.Network

	var server *protocol.ServerSpec
	var conn internet.Connection

	err := retry.ExponentialBackoff(5, 100).On(func() error {
		server = v.serverPicker.PickServer()
		dest := server.Destination()
		dest.Network = network
		rawConn, err := dialer.Dial(ctx, dest)
		if err != nil {
			return err
		}
		conn = rawConn

		return nil
	})
	if err != nil {
		return newError("failed to find an available destination").AtWarning().Base(err)
	}
	newError("tunneling request to ", destination, " via ", server.Destination()).WithContext(ctx).WriteToLog()

	defer conn.Close()

	request := &protocol.RequestHeader{
		Version: Version,
		Address: destination.Address,
		Port:    destination.Port,
	}
	if destination.Network == net.Network_TCP {
		request.Command = protocol.RequestCommandTCP
	} else {
		request.Command = protocol.RequestCommandUDP
	}

	user := server.PickUser()
	rawAccount, err := user.GetTypedAccount()
	if err != nil {
		return newError("failed to get a valid user account").AtWarning().Base(err)
	}
	account := rawAccount.(*MemoryAccount)
	request.User = user

	if account.OneTimeAuth == Account_Auto || account.OneTimeAuth == Account_Enabled {
		request.Option |= RequestOptionOneTimeAuth
	}

	sessionPolicy := v.v.PolicyManager().ForLevel(user.Level)
	ctx, cancel := context.WithCancel(ctx)
	timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)

	if request.Command == protocol.RequestCommandTCP {
		bufferedWriter := buf.NewBufferedWriter(buf.NewWriter(conn))
		bodyWriter, err := WriteTCPRequest(request, bufferedWriter)
		if err != nil {
			return newError("failed to write request").Base(err)
		}

		if err := bufferedWriter.SetBuffered(false); err != nil {
			return err
		}

		requestDone := signal.ExecuteAsync(func() error {
			defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
			return buf.Copy(outboundRay.OutboundInput(), bodyWriter, buf.UpdateActivity(timer))
		})

		responseDone := signal.ExecuteAsync(func() error {
			defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)

			responseReader, err := ReadTCPResponse(user, conn)
			if err != nil {
				return err
			}

			return buf.Copy(responseReader, outboundRay.OutboundOutput(), buf.UpdateActivity(timer))
		})

		if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
			return newError("connection ends").Base(err)
		}

		return nil
	}

	if request.Command == protocol.RequestCommandUDP {

		writer := buf.NewSequentialWriter(&UDPWriter{
			Writer:  conn,
			Request: request,
		})

		requestDone := signal.ExecuteAsync(func() error {
			defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)

			if err := buf.Copy(outboundRay.OutboundInput(), writer, buf.UpdateActivity(timer)); err != nil {
				return newError("failed to transport all UDP request").Base(err)
			}
			return nil
		})

		responseDone := signal.ExecuteAsync(func() error {
			defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)

			reader := &UDPReader{
				Reader: conn,
				User:   user,
			}

			if err := buf.Copy(reader, outboundRay.OutboundOutput(), buf.UpdateActivity(timer)); err != nil {
				return newError("failed to transport all UDP response").Base(err)
			}
			return nil
		})

		if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
			return newError("connection ends").Base(err)
		}

		return nil
	}

	return nil
}

func init() {
	common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
		return NewClient(ctx, config.(*ClientConfig))
	}))
}
<|endoftext|>


<commit_before>package shell

import (
	"log"
	"os"
	"os/exec"
	"os/signal"
	"reflect"
	"strings"
	"syscall"

	"github.com/gruntwork-io/terragrunt/errors"
	"github.com/gruntwork-io/terragrunt/options"
)

// Run the specified shell command with the specified arguments. Connect the command's stdin, stdout, and stderr to
// the currently running app.
func RunShellCommand(terragruntOptions *options.TerragruntOptions, command string, args ...string) error {
	terragruntOptions.Logger.Printf("Running command: %s %s", command, strings.Join(args, " "))

	cmd := exec.Command(command, args...)

	// TODO: consider adding prefix from terragruntOptions logger to stdout and stderr
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	// Terragrunt can run some commands (such as terraform remote config) before running the actual terraform
	// command requested by the user. The output of these other commands should not end up on stdout as this
	// breaks scripts relying on terraform's output.
	if !reflect.DeepEqual(terragruntOptions.TerraformCliArgs, args) {
		cmd.Stdout = os.Stderr
	}

	cmd.Dir = terragruntOptions.WorkingDir

	cmdChannel := make(chan error)
	signalChannel := NewSignalsForwarder(forwardSignals, cmd, terragruntOptions.Logger, cmdChannel)
	defer signalChannel.Close()

	err := cmd.Run()
	cmdChannel <- err

	return errors.WithStackTrace(err)
}

// Return the exit code of a command. If the error is not an exec.ExitError type,
// the error is returned.
func GetExitCode(err error) (int, error) {
	var retCode int
	if exiterr, ok := errors.Unwrap(err).(*exec.ExitError); ok {
	status := exiterr.Sys().(syscall.WaitStatus)
	retCode = status.ExitStatus()
	return retCode, nil
		}
	return retCode, err
}

type SignalsForwarder chan os.Signal

// Fowards signals to a command, waiting for the command to finish.
func NewSignalsForwarder(signals []os.Signal, c *exec.Cmd, logger *log.Logger, cmdChannel chan error) SignalsForwarder {
	signalChannel := make(chan os.Signal, 1)
	signal.Notify(signalChannel, signals...)

	go func() {
		for {
			select {
			case s := <-signalChannel:
				logger.Printf("Forward signal %s to terraform.", s.String())
				err := c.Process.Signal(s)
				if err != nil {
					logger.Printf("Error forwarding signal: %v", err)
				}
			case <- cmdChannel:
				return
			}
		}
	}()

	return signalChannel
}

func (signalChannel *SignalsForwarder) Close() error {
	signal.Stop(*signalChannel)
	*signalChannel <- nil
	close(*signalChannel)
	return nil
}
<commit_msg>cleanup GetExitCode<commit_after>package shell

import (
	"log"
	"os"
	"os/exec"
	"os/signal"
	"reflect"
	"strings"
	"syscall"

	"github.com/gruntwork-io/terragrunt/errors"
	"github.com/gruntwork-io/terragrunt/options"
)

// Run the specified shell command with the specified arguments. Connect the command's stdin, stdout, and stderr to
// the currently running app.
func RunShellCommand(terragruntOptions *options.TerragruntOptions, command string, args ...string) error {
	terragruntOptions.Logger.Printf("Running command: %s %s", command, strings.Join(args, " "))

	cmd := exec.Command(command, args...)

	// TODO: consider adding prefix from terragruntOptions logger to stdout and stderr
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	// Terragrunt can run some commands (such as terraform remote config) before running the actual terraform
	// command requested by the user. The output of these other commands should not end up on stdout as this
	// breaks scripts relying on terraform's output.
	if !reflect.DeepEqual(terragruntOptions.TerraformCliArgs, args) {
		cmd.Stdout = os.Stderr
	}

	cmd.Dir = terragruntOptions.WorkingDir

	cmdChannel := make(chan error)
	signalChannel := NewSignalsForwarder(forwardSignals, cmd, terragruntOptions.Logger, cmdChannel)
	defer signalChannel.Close()

	err := cmd.Run()
	cmdChannel <- err

	return errors.WithStackTrace(err)
}

// Return the exit code of a command. If the error is not an exec.ExitError type,
// the error is returned.
func GetExitCode(err error) (int, error) {
	if exiterr, ok := errors.Unwrap(err).(*exec.ExitError); ok {
		status := exiterr.Sys().(syscall.WaitStatus)
		return status.ExitStatus(), nil
	}
	return 0, err
}

type SignalsForwarder chan os.Signal

// Fowards signals to a command, waiting for the command to finish.
func NewSignalsForwarder(signals []os.Signal, c *exec.Cmd, logger *log.Logger, cmdChannel chan error) SignalsForwarder {
	signalChannel := make(chan os.Signal, 1)
	signal.Notify(signalChannel, signals...)

	go func() {
		for {
			select {
			case s := <-signalChannel:
				logger.Printf("Forward signal %s to terraform.", s.String())
				err := c.Process.Signal(s)
				if err != nil {
					logger.Printf("Error forwarding signal: %v", err)
				}
			case <- cmdChannel:
				return
			}
		}
	}()

	return signalChannel
}

func (signalChannel *SignalsForwarder) Close() error {
	signal.Stop(*signalChannel)
	*signalChannel <- nil
	close(*signalChannel)
	return nil
}
<|endoftext|>


<commit_before>package toxiproxy

import (
	"errors"
	"net"
	"sync"

	"github.com/Shopify/toxiproxy/v2/stream"
	"github.com/sirupsen/logrus"
	tomb "gopkg.in/tomb.v1"
)

// Proxy represents the proxy in its entirity with all its links. The main
// responsibility of Proxy is to accept new client and create Links between the
// client and upstream.
//
// Client <-> toxiproxy <-> Upstream.
//
type Proxy struct {
	sync.Mutex

	Name     string `json:"name"`
	Listen   string `json:"listen"`
	Upstream string `json:"upstream"`
	Enabled  bool   `json:"enabled"`

	listener net.Listener
	started  chan error

	tomb        tomb.Tomb
	connections ConnectionList
	Toxics      *ToxicCollection `json:"-"`
}

type ConnectionList struct {
	list map[string]net.Conn
	lock sync.Mutex
}

func (c *ConnectionList) Lock() {
	c.lock.Lock()
}

func (c *ConnectionList) Unlock() {
	c.lock.Unlock()
}

var ErrProxyAlreadyStarted = errors.New("Proxy already started")

func NewProxy() *Proxy {
	proxy := &Proxy{
		started:     make(chan error),
		connections: ConnectionList{list: make(map[string]net.Conn)},
	}
	proxy.Toxics = NewToxicCollection(proxy)
	return proxy
}

func (proxy *Proxy) Start() error {
	proxy.Lock()
	defer proxy.Unlock()

	return start(proxy)
}

func (proxy *Proxy) Update(input *Proxy) error {
	proxy.Lock()
	defer proxy.Unlock()

	if input.Listen != proxy.Listen || input.Upstream != proxy.Upstream {
		stop(proxy)
		proxy.Listen = input.Listen
		proxy.Upstream = input.Upstream
	}

	if input.Enabled != proxy.Enabled {
		if input.Enabled {
			return start(proxy)
		}
		stop(proxy)
	}
	return nil
}

func (proxy *Proxy) Stop() {
	proxy.Lock()
	defer proxy.Unlock()

	stop(proxy)
}

func (proxy *Proxy) listen() error {
	var err error
	proxy.listener, err = net.Listen("tcp", proxy.Listen)
	if err != nil {
		proxy.started <- err
		return err
	}
	proxy.Listen = proxy.listener.Addr().String()
	proxy.started <- nil

	logrus.WithFields(logrus.Fields{
		"name":     proxy.Name,
		"proxy":    proxy.Listen,
		"upstream": proxy.Upstream,
	}).Info("Started proxy")

	return nil
}

func (proxy *Proxy) close() {
	// Unblock proxy.listener.Accept()
	err := proxy.listener.Close()
	if err != nil {
		logrus.WithFields(logrus.Fields{
			"proxy":  proxy.Name,
			"listen": proxy.Listen,
			"err":    err,
		}).Warn("Attempted to close an already closed proxy server")
	}
}

// This channel is to kill the blocking Accept() call below by closing the
// net.Listener.
func (proxy *Proxy) freeBlocker(acceptTomb *tomb.Tomb) {
	<-proxy.tomb.Dying()

	// Notify ln.Accept() that the shutdown was safe
	acceptTomb.Killf("Shutting down from stop()")

	proxy.close()

	// Wait for the accept loop to finish processing
	acceptTomb.Wait()
	proxy.tomb.Done()
}

// server runs the Proxy server, accepting new clients and creating Links to
// connect them to upstreams.
func (proxy *Proxy) server() {
	err := proxy.listen()
	if err != nil {
		return
	}

	acceptTomb := &tomb.Tomb{}
	defer acceptTomb.Done()

	// This channel is to kill the blocking Accept() call below by closing the
	// net.Listener.
	go proxy.freeBlocker(acceptTomb)

	for {
		client, err := proxy.listener.Accept()
		if err != nil {
			// This is to confirm we're being shut down in a legit way. Unfortunately,
			// Go doesn't export the error when it's closed from Close() so we have to
			// sync up with a channel here.
			//
			// See http://zhen.org/blog/graceful-shutdown-of-go-net-dot-listeners/
			select {
			case <-acceptTomb.Dying():
			default:
				logrus.WithFields(logrus.Fields{
					"proxy":  proxy.Name,
					"listen": proxy.Listen,
					"err":    err,
				}).Warn("Error while accepting client")
			}
			return
		}

		logrus.WithFields(logrus.Fields{
			"name":     proxy.Name,
			"client":   client.RemoteAddr(),
			"proxy":    proxy.Listen,
			"upstream": proxy.Upstream,
		}).Info("Accepted client")

		upstream, err := net.Dial("tcp", proxy.Upstream)
		if err != nil {
			logrus.WithFields(logrus.Fields{
				"name":     proxy.Name,
				"client":   client.RemoteAddr(),
				"proxy":    proxy.Listen,
				"upstream": proxy.Upstream,
			}).Error("Unable to open connection to upstream")
			client.Close()
			continue
		}

		name := client.RemoteAddr().String()
		proxy.connections.Lock()
		proxy.connections.list[name+"upstream"] = upstream
		proxy.connections.list[name+"downstream"] = client
		proxy.connections.Unlock()
		proxy.Toxics.StartLink(name+"upstream", client, upstream, stream.Upstream)
		proxy.Toxics.StartLink(name+"downstream", upstream, client, stream.Downstream)
	}
}

func (proxy *Proxy) RemoveConnection(name string) {
	proxy.connections.Lock()
	defer proxy.connections.Unlock()
	delete(proxy.connections.list, name)
}

// Starts a proxy, assumes the lock has already been taken.
func start(proxy *Proxy) error {
	if proxy.Enabled {
		return ErrProxyAlreadyStarted
	}

	proxy.tomb = tomb.Tomb{} // Reset tomb, from previous starts/stops
	go proxy.server()
	err := <-proxy.started
	// Only enable the proxy if it successfully started
	proxy.Enabled = err == nil
	return err
}

// Stops a proxy, assumes the lock has already been taken.
func stop(proxy *Proxy) {
	if !proxy.Enabled {
		return
	}
	proxy.Enabled = false

	proxy.tomb.Killf("Shutting down from stop()")
	proxy.tomb.Wait() // Wait until we stop accepting new connections

	proxy.connections.Lock()
	defer proxy.connections.Unlock()
	for _, conn := range proxy.connections.list {
		conn.Close()
	}

	logrus.WithFields(logrus.Fields{
		"name":     proxy.Name,
		"proxy":    proxy.Listen,
		"upstream": proxy.Upstream,
	}).Info("Terminated proxy")
}
<commit_msg>Fix the typo in comment for Proxy<commit_after>package toxiproxy

import (
	"errors"
	"net"
	"sync"

	"github.com/Shopify/toxiproxy/v2/stream"
	"github.com/sirupsen/logrus"
	tomb "gopkg.in/tomb.v1"
)

// Proxy represents the proxy in its entirety with all its links. The main
// responsibility of Proxy is to accept new client and create Links between the
// client and upstream.
//
// Client <-> toxiproxy <-> Upstream.
//
type Proxy struct {
	sync.Mutex

	Name     string `json:"name"`
	Listen   string `json:"listen"`
	Upstream string `json:"upstream"`
	Enabled  bool   `json:"enabled"`

	listener net.Listener
	started  chan error

	tomb        tomb.Tomb
	connections ConnectionList
	Toxics      *ToxicCollection `json:"-"`
}

type ConnectionList struct {
	list map[string]net.Conn
	lock sync.Mutex
}

func (c *ConnectionList) Lock() {
	c.lock.Lock()
}

func (c *ConnectionList) Unlock() {
	c.lock.Unlock()
}

var ErrProxyAlreadyStarted = errors.New("Proxy already started")

func NewProxy() *Proxy {
	proxy := &Proxy{
		started:     make(chan error),
		connections: ConnectionList{list: make(map[string]net.Conn)},
	}
	proxy.Toxics = NewToxicCollection(proxy)
	return proxy
}

func (proxy *Proxy) Start() error {
	proxy.Lock()
	defer proxy.Unlock()

	return start(proxy)
}

func (proxy *Proxy) Update(input *Proxy) error {
	proxy.Lock()
	defer proxy.Unlock()

	if input.Listen != proxy.Listen || input.Upstream != proxy.Upstream {
		stop(proxy)
		proxy.Listen = input.Listen
		proxy.Upstream = input.Upstream
	}

	if input.Enabled != proxy.Enabled {
		if input.Enabled {
			return start(proxy)
		}
		stop(proxy)
	}
	return nil
}

func (proxy *Proxy) Stop() {
	proxy.Lock()
	defer proxy.Unlock()

	stop(proxy)
}

func (proxy *Proxy) listen() error {
	var err error
	proxy.listener, err = net.Listen("tcp", proxy.Listen)
	if err != nil {
		proxy.started <- err
		return err
	}
	proxy.Listen = proxy.listener.Addr().String()
	proxy.started <- nil

	logrus.WithFields(logrus.Fields{
		"name":     proxy.Name,
		"proxy":    proxy.Listen,
		"upstream": proxy.Upstream,
	}).Info("Started proxy")

	return nil
}

func (proxy *Proxy) close() {
	// Unblock proxy.listener.Accept()
	err := proxy.listener.Close()
	if err != nil {
		logrus.WithFields(logrus.Fields{
			"proxy":  proxy.Name,
			"listen": proxy.Listen,
			"err":    err,
		}).Warn("Attempted to close an already closed proxy server")
	}
}

// This channel is to kill the blocking Accept() call below by closing the
// net.Listener.
func (proxy *Proxy) freeBlocker(acceptTomb *tomb.Tomb) {
	<-proxy.tomb.Dying()

	// Notify ln.Accept() that the shutdown was safe
	acceptTomb.Killf("Shutting down from stop()")

	proxy.close()

	// Wait for the accept loop to finish processing
	acceptTomb.Wait()
	proxy.tomb.Done()
}

// server runs the Proxy server, accepting new clients and creating Links to
// connect them to upstreams.
func (proxy *Proxy) server() {
	err := proxy.listen()
	if err != nil {
		return
	}

	acceptTomb := &tomb.Tomb{}
	defer acceptTomb.Done()

	// This channel is to kill the blocking Accept() call below by closing the
	// net.Listener.
	go proxy.freeBlocker(acceptTomb)

	for {
		client, err := proxy.listener.Accept()
		if err != nil {
			// This is to confirm we're being shut down in a legit way. Unfortunately,
			// Go doesn't export the error when it's closed from Close() so we have to
			// sync up with a channel here.
			//
			// See http://zhen.org/blog/graceful-shutdown-of-go-net-dot-listeners/
			select {
			case <-acceptTomb.Dying():
			default:
				logrus.WithFields(logrus.Fields{
					"proxy":  proxy.Name,
					"listen": proxy.Listen,
					"err":    err,
				}).Warn("Error while accepting client")
			}
			return
		}

		logrus.WithFields(logrus.Fields{
			"name":     proxy.Name,
			"client":   client.RemoteAddr(),
			"proxy":    proxy.Listen,
			"upstream": proxy.Upstream,
		}).Info("Accepted client")

		upstream, err := net.Dial("tcp", proxy.Upstream)
		if err != nil {
			logrus.WithFields(logrus.Fields{
				"name":     proxy.Name,
				"client":   client.RemoteAddr(),
				"proxy":    proxy.Listen,
				"upstream": proxy.Upstream,
			}).Error("Unable to open connection to upstream")
			client.Close()
			continue
		}

		name := client.RemoteAddr().String()
		proxy.connections.Lock()
		proxy.connections.list[name+"upstream"] = upstream
		proxy.connections.list[name+"downstream"] = client
		proxy.connections.Unlock()
		proxy.Toxics.StartLink(name+"upstream", client, upstream, stream.Upstream)
		proxy.Toxics.StartLink(name+"downstream", upstream, client, stream.Downstream)
	}
}

func (proxy *Proxy) RemoveConnection(name string) {
	proxy.connections.Lock()
	defer proxy.connections.Unlock()
	delete(proxy.connections.list, name)
}

// Starts a proxy, assumes the lock has already been taken.
func start(proxy *Proxy) error {
	if proxy.Enabled {
		return ErrProxyAlreadyStarted
	}

	proxy.tomb = tomb.Tomb{} // Reset tomb, from previous starts/stops
	go proxy.server()
	err := <-proxy.started
	// Only enable the proxy if it successfully started
	proxy.Enabled = err == nil
	return err
}

// Stops a proxy, assumes the lock has already been taken.
func stop(proxy *Proxy) {
	if !proxy.Enabled {
		return
	}
	proxy.Enabled = false

	proxy.tomb.Killf("Shutting down from stop()")
	proxy.tomb.Wait() // Wait until we stop accepting new connections

	proxy.connections.Lock()
	defer proxy.connections.Unlock()
	for _, conn := range proxy.connections.list {
		conn.Close()
	}

	logrus.WithFields(logrus.Fields{
		"name":     proxy.Name,
		"proxy":    proxy.Listen,
		"upstream": proxy.Upstream,
	}).Info("Terminated proxy")
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package indexers

import (
	"fmt"

	"github.com/btcsuite/btcd/blockchain"
	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcd/database"
	"github.com/btcsuite/btcutil"
	"github.com/btcsuite/btcutil/gcs/builder"

	"os"
)

const (
	// cfIndexName is the human-readable name for the index.
	cfIndexName = "committed bloom filter index"
)

var (
	// cfIndexKey is the name of the db bucket used to house the
	// block hash -> CF index.
	cfIndexKey = []byte("cfbyhashidx")
)

func dbFetchCFIndexEntry(dbTx database.Tx, blockHash *chainhash.Hash) ([]byte,
    error) {
	// Load the record from the database and return now if it doesn't exist.
	index := dbTx.Metadata().Bucket(cfIndexKey)
	serializedFilter := index.Get(blockHash[:])
	if len(serializedFilter) == 0 {
		return nil, nil
	}

	return serializedFilter, nil
}

// The serialized format for keys and values in the block hash to CF bucket is:
//   <hash> = <CF>
//
//   Field           Type              Size
//   hash            chainhash.Hash    32 bytes
//   CF              []byte            variable
//   -----
//   Total: > 32 bytes

// CFIndex implements a CF by hash index.
type CFIndex struct {
	db database.DB
}

// Ensure the CFIndex type implements the Indexer interface.
var _ Indexer = (*CFIndex)(nil)

// Init initializes the hash-based CF index.
//
// This is part of the Indexer interface.
func (idx *CFIndex) Init() error {
	return nil
}

// Key returns the database key to use for the index as a byte slice.
//
// This is part of the Indexer interface.
func (idx *CFIndex) Key() []byte {
	return cfIndexKey
}

// Name returns the human-readable name of the index.
//
// This is part of the Indexer interface.
func (idx *CFIndex) Name() string {
	return cfIndexName
}

// Create is invoked when the indexer manager determines the index needs
// to be created for the first time.  It creates the buckets for the hash-based
// CF index.
//
// This is part of the Indexer interface.
func (idx *CFIndex) Create(dbTx database.Tx) error {
	meta := dbTx.Metadata()
	_, err := meta.CreateBucket(cfIndexKey)
	return err
}

func generateFilterForBlock(block *btcutil.Block) ([]byte, error) {
	b := builder.WithKeyHash(block.Hash())
	_, err := b.Key()
	if err != nil {
		return nil, err
	}
	for _, tx := range block.Transactions() {
		for _, txIn := range tx.MsgTx().TxIn {
			b.AddOutPoint(txIn.PreviousOutPoint)
		}
	}
	f, err := b.Build()
	if err != nil {
		return nil, err
	}
	return f.Bytes(), nil
}

// ConnectBlock is invoked by the index manager when a new block has been
// connected to the main chain.  This indexer adds a hash-to-CF mapping for
// every passed block.
//
// This is part of the Indexer interface.
func (idx *CFIndex) ConnectBlock(dbTx database.Tx, block *btcutil.Block,
    view *blockchain.UtxoViewpoint) error {
	filterBytes, err := generateFilterForBlock(block)
	if err != nil {
		return err
	}

	meta := dbTx.Metadata()
	index := meta.Bucket(cfIndexKey)
	err = index.Put(block.Hash()[:], filterBytes)
	if err != nil {
		return err
	}

	fmt.Fprintf(os.Stderr, "Stored CF for block %v", block.Hash())

	return nil
}

// DisconnectBlock is invoked by the index manager when a block has been
// disconnected from the main chain.  This indexer removes the hash-to-CF
// mapping for every passed block.
//
// This is part of the Indexer interface.
func (idx *CFIndex) DisconnectBlock(dbTx database.Tx, block *btcutil.Block,
    view *blockchain.UtxoViewpoint) error {
	index := dbTx.Metadata().Bucket(cfIndexKey)
	filterBytes := index.Get(block.Hash()[:])
	if len(filterBytes) == 0 {
		return fmt.Errorf("can't remove non-existent filter %s from " +
		    "the cfilter index", block.Hash())
	}
	return index.Delete(block.Hash()[:])
}

func (idx *CFIndex) FilterByBlockHash(hash *chainhash.Hash) ([]byte, error) {
	var filterBytes []byte
	err := idx.db.View(func(dbTx database.Tx) error {
		var err error
		filterBytes, err = dbFetchCFIndexEntry(dbTx, hash)
		return err
	})
	return filterBytes, err
}

// NewCFIndex returns a new instance of an indexer that is used to create a
// mapping of the hashes of all blocks in the blockchain to their respective
// committed bloom filters.
//
// It implements the Indexer interface which plugs into the IndexManager that in
// turn is used by the blockchain package.  This allows the index to be
// seamlessly maintained along with the chain.
func NewCFIndex(db database.DB) *CFIndex {
	return &CFIndex{db: db}
}

// DropCFIndex drops the CF index from the provided database if exists.
func DropCFIndex(db database.DB) error {
	return dropIndex(db, cfIndexKey, cfIndexName)
}
<commit_msg>Start preparing the ground for layer {0,1} filters<commit_after>// Copyright (c) 2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package indexers

import (
	"fmt"

	"github.com/btcsuite/btcd/blockchain"
	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcd/database"
	"github.com/btcsuite/btcutil"
	"github.com/btcsuite/btcutil/gcs/builder"

	"os"
)

const (
	// cfIndexName is the human-readable name for the index.
	cfIndexName = "committed filter index"
)

var (
	// cfBasicIndexKey is the name of the db bucket used to house the
	// block hash -> Basic CF index (CF #0).
	cfBasicIndexKey = []byte("cf0byhashidx")
	// cfExtendedIndexKey is the name of the db bucket used to house the
	// block hash -> Extended CF index (CF #1).
	cfExtendedIndexKey = []byte("cf1byhashidx")
)

func dbFetchCFIndexEntry(dbTx database.Tx, blockHash *chainhash.Hash) ([]byte,
    error) {
	// Load the record from the database and return now if it doesn't exist.
	index := dbTx.Metadata().Bucket(cfBasicIndexKey)
	serializedFilter := index.Get(blockHash[:])
	if len(serializedFilter) == 0 {
		return nil, nil
	}

	return serializedFilter, nil
}

// The serialized format for keys and values in the block hash to CF bucket is:
//   <hash> = <CF>
//
//   Field           Type              Size
//   hash            chainhash.Hash    32 bytes
//   CF              []byte            variable
//   -----
//   Total: > 32 bytes

// CFIndex implements a CF by hash index.
type CFIndex struct {
	db database.DB
}

// Ensure the CFIndex type implements the Indexer interface.
var _ Indexer = (*CFIndex)(nil)

// Init initializes the hash-based CF index.
//
// This is part of the Indexer interface.
func (idx *CFIndex) Init() error {
	return nil
}

// Key returns the database key to use for the index as a byte slice.
func (idx *CFIndex) Key() []byte {
	return cfBasicIndexKey
}

// Name returns the human-readable name of the index.
//
// This is part of the Indexer interface.
func (idx *CFIndex) Name() string {
	return cfIndexName
}

// Create is invoked when the indexer manager determines the index needs to be
// created for the first time. It creates buckets for the two hash-based CF
// indexes (simple, extended).
func (idx *CFIndex) Create(dbTx database.Tx) error {
	meta := dbTx.Metadata()
	_, err := meta.CreateBucket(cfBasicIndexKey)
	if err != nil {
		return err
	}
	_, err = meta.CreateBucket(cfExtendedIndexKey)
	return err
}

func generateFilterForBlock(block *btcutil.Block) ([]byte, error) {
	b := builder.WithKeyHash(block.Hash())
	_, err := b.Key()
	if err != nil {
		return nil, err
	}
	for _, tx := range block.Transactions() {
		for _, txIn := range tx.MsgTx().TxIn {
			b.AddOutPoint(txIn.PreviousOutPoint)
		}
	}
	f, err := b.Build()
	if err != nil {
		return nil, err
	}
	return f.Bytes(), nil
}

// ConnectBlock is invoked by the index manager when a new block has been
// connected to the main chain.  This indexer adds a hash-to-CF mapping for
// every passed block.
//
// This is part of the Indexer interface.
func (idx *CFIndex) ConnectBlock(dbTx database.Tx, block *btcutil.Block,
    view *blockchain.UtxoViewpoint) error {
	filterBytes, err := generateFilterForBlock(block)
	if err != nil {
		return err
	}

	meta := dbTx.Metadata()
	index := meta.Bucket(cfBasicIndexKey)
	err = index.Put(block.Hash()[:], filterBytes)
	if err != nil {
		return err
	}

	fmt.Fprintf(os.Stderr, "Stored CF for block %v", block.Hash())

	return nil
}

// DisconnectBlock is invoked by the index manager when a block has been
// disconnected from the main chain.  This indexer removes the hash-to-CF
// mapping for every passed block.
//
// This is part of the Indexer interface.
func (idx *CFIndex) DisconnectBlock(dbTx database.Tx, block *btcutil.Block,
    view *blockchain.UtxoViewpoint) error {
	index := dbTx.Metadata().Bucket(cfBasicIndexKey)
	filterBytes := index.Get(block.Hash()[:])
	if len(filterBytes) == 0 {
		return fmt.Errorf("can't remove non-existent filter %s from " +
		    "the cfilter index", block.Hash())
	}
	return index.Delete(block.Hash()[:])
}

func (idx *CFIndex) FilterByBlockHash(hash *chainhash.Hash) ([]byte, error) {
	var filterBytes []byte
	err := idx.db.View(func(dbTx database.Tx) error {
		var err error
		filterBytes, err = dbFetchCFIndexEntry(dbTx, hash)
		return err
	})
	return filterBytes, err
}

// NewCFIndex returns a new instance of an indexer that is used to create a
// mapping of the hashes of all blocks in the blockchain to their respective
// committed bloom filters.
//
// It implements the Indexer interface which plugs into the IndexManager that in
// turn is used by the blockchain package.  This allows the index to be
// seamlessly maintained along with the chain.
func NewCFIndex(db database.DB) *CFIndex {
	return &CFIndex{db: db}
}

// DropCFIndex drops the CF index from the provided database if exists.
func DropCFIndex(db database.DB) error {
	return dropIndex(db, cfBasicIndexKey, cfIndexName)
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package oom

import (
	"fmt"
	"testing"
	"time"

	v1 "k8s.io/api/core/v1"
	"k8s.io/client-go/tools/record"

	"github.com/google/cadvisor/utils/oomparser"
	"github.com/stretchr/testify/assert"
)

type fakeStreamer struct {
	oomInstancesToStream []*oomparser.OomInstance
}

func (fs *fakeStreamer) StreamOoms(outStream chan<- *oomparser.OomInstance) {
	for _, oomInstance := range fs.oomInstancesToStream {
		outStream <- oomInstance
	}
}

// TestStartingWatcher tests that the watcher, using the actual streamer
// and not the fake, starts successfully.
func TestStartingWatcher(t *testing.T) {
	fakeRecorder := &record.FakeRecorder{}
	node := &v1.ObjectReference{}

	oomWatcher, err := NewWatcher(fakeRecorder)
	assert.NoError(t, err)
	assert.NoError(t, oomWatcher.Start(node))
}

// TestWatcherRecordsEventsForOomEvents ensures that our OomInstances coming
// from `StreamOoms` are translated into events in our recorder.
func TestWatcherRecordsEventsForOomEvents(t *testing.T) {
	oomInstancesToStream := []*oomparser.OomInstance{
		{
			Pid:                 1000,
			ProcessName:         "fakeProcess",
			TimeOfDeath:         time.Now(),
			ContainerName:       recordEventContainerName + "some-container",
			VictimContainerName: recordEventContainerName,
		},
	}
	numExpectedOomEvents := len(oomInstancesToStream)

	fakeStreamer := &fakeStreamer{
		oomInstancesToStream: oomInstancesToStream,
	}

	fakeRecorder := record.NewFakeRecorder(numExpectedOomEvents)
	node := &v1.ObjectReference{}

	oomWatcher := &realWatcher{
		recorder:    fakeRecorder,
		oomStreamer: fakeStreamer,
	}
	assert.NoError(t, oomWatcher.Start(node))

	eventsRecorded := getRecordedEvents(fakeRecorder, numExpectedOomEvents)
	assert.Equal(t, numExpectedOomEvents, len(eventsRecorded))
}

func getRecordedEvents(fakeRecorder *record.FakeRecorder, numExpectedOomEvents int) []string {
	eventsRecorded := []string{}

	select {
	case event := <-fakeRecorder.Events:
		eventsRecorded = append(eventsRecorded, event)

		if len(eventsRecorded) == numExpectedOomEvents {
			break
		}
	case <-time.After(10 * time.Second):
		break
	}

	return eventsRecorded
}

// TestWatcherRecordsEventsForOomEventsCorrectContainerName verifies that we
// only record OOM events when the container name is the one for which we want
// to record events (i.e. /).
func TestWatcherRecordsEventsForOomEventsCorrectContainerName(t *testing.T) {
	// By "incorrect" container name, we mean a container name for which we
	// don't want to record an oom event.
	numOomEventsWithIncorrectContainerName := 1
	oomInstancesToStream := []*oomparser.OomInstance{
		{
			Pid:                 1000,
			ProcessName:         "fakeProcess",
			TimeOfDeath:         time.Now(),
			ContainerName:       recordEventContainerName + "some-container",
			VictimContainerName: recordEventContainerName,
		},
		{
			Pid:                 1000,
			ProcessName:         "fakeProcess",
			TimeOfDeath:         time.Now(),
			ContainerName:       recordEventContainerName + "kubepods/some-container",
			VictimContainerName: recordEventContainerName + "kubepods",
		},
	}
	numExpectedOomEvents := len(oomInstancesToStream) - numOomEventsWithIncorrectContainerName

	fakeStreamer := &fakeStreamer{
		oomInstancesToStream: oomInstancesToStream,
	}

	fakeRecorder := record.NewFakeRecorder(numExpectedOomEvents)
	node := &v1.ObjectReference{}

	oomWatcher := &realWatcher{
		recorder:    fakeRecorder,
		oomStreamer: fakeStreamer,
	}
	assert.NoError(t, oomWatcher.Start(node))

	eventsRecorded := getRecordedEvents(fakeRecorder, numExpectedOomEvents)
	assert.Equal(t, numExpectedOomEvents, len(eventsRecorded))
}

// TestWatcherRecordsEventsForOomEventsWithAdditionalInfo verifies that our the
// emitted event has the proper pid/process data when appropriate.
func TestWatcherRecordsEventsForOomEventsWithAdditionalInfo(t *testing.T) {
	// The process and event info should appear in the event message.
	eventPid := 1000
	processName := "fakeProcess"

	oomInstancesToStream := []*oomparser.OomInstance{
		{
			Pid:                 eventPid,
			ProcessName:         processName,
			TimeOfDeath:         time.Now(),
			ContainerName:       recordEventContainerName + "some-container",
			VictimContainerName: recordEventContainerName,
		},
	}
	numExpectedOomEvents := len(oomInstancesToStream)

	fakeStreamer := &fakeStreamer{
		oomInstancesToStream: oomInstancesToStream,
	}

	fakeRecorder := record.NewFakeRecorder(numExpectedOomEvents)
	node := &v1.ObjectReference{}

	oomWatcher := &realWatcher{
		recorder:    fakeRecorder,
		oomStreamer: fakeStreamer,
	}
	assert.NoError(t, oomWatcher.Start(node))

	eventsRecorded := getRecordedEvents(fakeRecorder, numExpectedOomEvents)

	assert.Equal(t, numExpectedOomEvents, len(eventsRecorded))
	assert.Contains(t, eventsRecorded[0], systemOOMEvent)
	assert.Contains(t, eventsRecorded[0], fmt.Sprintf("pid: %d", eventPid))
	assert.Contains(t, eventsRecorded[0], fmt.Sprintf("victim process: %s", processName))
}
<commit_msg>remove oom TestStartingWatcher ""unit"" test<commit_after>/*
Copyright 2015 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package oom

import (
	"fmt"
	"testing"
	"time"

	v1 "k8s.io/api/core/v1"
	"k8s.io/client-go/tools/record"

	"github.com/google/cadvisor/utils/oomparser"
	"github.com/stretchr/testify/assert"
)

type fakeStreamer struct {
	oomInstancesToStream []*oomparser.OomInstance
}

func (fs *fakeStreamer) StreamOoms(outStream chan<- *oomparser.OomInstance) {
	for _, oomInstance := range fs.oomInstancesToStream {
		outStream <- oomInstance
	}
}

// TestWatcherRecordsEventsForOomEvents ensures that our OomInstances coming
// from `StreamOoms` are translated into events in our recorder.
func TestWatcherRecordsEventsForOomEvents(t *testing.T) {
	oomInstancesToStream := []*oomparser.OomInstance{
		{
			Pid:                 1000,
			ProcessName:         "fakeProcess",
			TimeOfDeath:         time.Now(),
			ContainerName:       recordEventContainerName + "some-container",
			VictimContainerName: recordEventContainerName,
		},
	}
	numExpectedOomEvents := len(oomInstancesToStream)

	fakeStreamer := &fakeStreamer{
		oomInstancesToStream: oomInstancesToStream,
	}

	fakeRecorder := record.NewFakeRecorder(numExpectedOomEvents)
	node := &v1.ObjectReference{}

	oomWatcher := &realWatcher{
		recorder:    fakeRecorder,
		oomStreamer: fakeStreamer,
	}
	assert.NoError(t, oomWatcher.Start(node))

	eventsRecorded := getRecordedEvents(fakeRecorder, numExpectedOomEvents)
	assert.Equal(t, numExpectedOomEvents, len(eventsRecorded))
}

func getRecordedEvents(fakeRecorder *record.FakeRecorder, numExpectedOomEvents int) []string {
	eventsRecorded := []string{}

	select {
	case event := <-fakeRecorder.Events:
		eventsRecorded = append(eventsRecorded, event)

		if len(eventsRecorded) == numExpectedOomEvents {
			break
		}
	case <-time.After(10 * time.Second):
		break
	}

	return eventsRecorded
}

// TestWatcherRecordsEventsForOomEventsCorrectContainerName verifies that we
// only record OOM events when the container name is the one for which we want
// to record events (i.e. /).
func TestWatcherRecordsEventsForOomEventsCorrectContainerName(t *testing.T) {
	// By "incorrect" container name, we mean a container name for which we
	// don't want to record an oom event.
	numOomEventsWithIncorrectContainerName := 1
	oomInstancesToStream := []*oomparser.OomInstance{
		{
			Pid:                 1000,
			ProcessName:         "fakeProcess",
			TimeOfDeath:         time.Now(),
			ContainerName:       recordEventContainerName + "some-container",
			VictimContainerName: recordEventContainerName,
		},
		{
			Pid:                 1000,
			ProcessName:         "fakeProcess",
			TimeOfDeath:         time.Now(),
			ContainerName:       recordEventContainerName + "kubepods/some-container",
			VictimContainerName: recordEventContainerName + "kubepods",
		},
	}
	numExpectedOomEvents := len(oomInstancesToStream) - numOomEventsWithIncorrectContainerName

	fakeStreamer := &fakeStreamer{
		oomInstancesToStream: oomInstancesToStream,
	}

	fakeRecorder := record.NewFakeRecorder(numExpectedOomEvents)
	node := &v1.ObjectReference{}

	oomWatcher := &realWatcher{
		recorder:    fakeRecorder,
		oomStreamer: fakeStreamer,
	}
	assert.NoError(t, oomWatcher.Start(node))

	eventsRecorded := getRecordedEvents(fakeRecorder, numExpectedOomEvents)
	assert.Equal(t, numExpectedOomEvents, len(eventsRecorded))
}

// TestWatcherRecordsEventsForOomEventsWithAdditionalInfo verifies that our the
// emitted event has the proper pid/process data when appropriate.
func TestWatcherRecordsEventsForOomEventsWithAdditionalInfo(t *testing.T) {
	// The process and event info should appear in the event message.
	eventPid := 1000
	processName := "fakeProcess"

	oomInstancesToStream := []*oomparser.OomInstance{
		{
			Pid:                 eventPid,
			ProcessName:         processName,
			TimeOfDeath:         time.Now(),
			ContainerName:       recordEventContainerName + "some-container",
			VictimContainerName: recordEventContainerName,
		},
	}
	numExpectedOomEvents := len(oomInstancesToStream)

	fakeStreamer := &fakeStreamer{
		oomInstancesToStream: oomInstancesToStream,
	}

	fakeRecorder := record.NewFakeRecorder(numExpectedOomEvents)
	node := &v1.ObjectReference{}

	oomWatcher := &realWatcher{
		recorder:    fakeRecorder,
		oomStreamer: fakeStreamer,
	}
	assert.NoError(t, oomWatcher.Start(node))

	eventsRecorded := getRecordedEvents(fakeRecorder, numExpectedOomEvents)

	assert.Equal(t, numExpectedOomEvents, len(eventsRecorded))
	assert.Contains(t, eventsRecorded[0], systemOOMEvent)
	assert.Contains(t, eventsRecorded[0], fmt.Sprintf("pid: %d", eventPid))
	assert.Contains(t, eventsRecorded[0], fmt.Sprintf("victim process: %s", processName))
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package components

import (
	"k8s.io/kops/pkg/apis/kops"
	"k8s.io/kops/pkg/apis/kops/util"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/upup/pkg/fi/loader"
)

// ClusterAutoscalerOptionsBuilder adds options for cluster autoscaler to the model
type ClusterAutoscalerOptionsBuilder struct {
	*OptionsContext
}

var _ loader.OptionsBuilder = &ClusterAutoscalerOptionsBuilder{}

func (b *ClusterAutoscalerOptionsBuilder) BuildOptions(o interface{}) error {
	clusterSpec := o.(*kops.ClusterSpec)
	cas := clusterSpec.ClusterAutoscaler
	if cas == nil || !fi.BoolValue(cas.Enabled) {
		return nil
	}

	if cas.Image == nil {

		image := "registry.k8s.io/autoscaling/cluster-autoscaler:latest"
		v, err := util.ParseKubernetesVersion(clusterSpec.KubernetesVersion)
		if err == nil {
			switch v.Minor {
			case 23:
				image = "registry.k8s.io/autoscaling/cluster-autoscaler:v1.23.0"
			case 22:
				image = "registry.k8s.io/autoscaling/cluster-autoscaler:v1.22.2"
			case 21:
				image = "registry.k8s.io/autoscaling/cluster-autoscaler:v1.21.2"
			case 20:
				image = "registry.k8s.io/autoscaling/cluster-autoscaler:v1.20.1"
			case 19:
				image = "registry.k8s.io/autoscaling/cluster-autoscaler:v1.19.2"
			}
		}
		cas.Image = fi.String(image)

	}

	if cas.Expander == nil {
		cas.Expander = fi.String("random")
	}
	if cas.ScaleDownUtilizationThreshold == nil {
		cas.ScaleDownUtilizationThreshold = fi.String("0.5")
	}
	if cas.SkipNodesWithLocalStorage == nil {
		cas.SkipNodesWithLocalStorage = fi.Bool(true)
	}
	if cas.SkipNodesWithSystemPods == nil {
		cas.SkipNodesWithSystemPods = fi.Bool(true)
	}
	if cas.BalanceSimilarNodeGroups == nil {
		cas.BalanceSimilarNodeGroups = fi.Bool(false)
	}
	if cas.AWSUseStaticInstanceList == nil {
		cas.AWSUseStaticInstanceList = fi.Bool(false)
	}
	if cas.NewPodScaleUpDelay == nil {
		cas.NewPodScaleUpDelay = fi.String("0s")
	}
	if cas.ScaleDownDelayAfterAdd == nil {
		cas.ScaleDownDelayAfterAdd = fi.String("10m0s")
	}
	if cas.MaxNodeProvisionTime == "" {
		cas.MaxNodeProvisionTime = "15m0s"
	}

	return nil
}
<commit_msg>Use Cluster Autoscaler 1.23 for k8s 1.24<commit_after>/*
Copyright 2020 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package components

import (
	"k8s.io/kops/pkg/apis/kops"
	"k8s.io/kops/pkg/apis/kops/util"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/upup/pkg/fi/loader"
)

// ClusterAutoscalerOptionsBuilder adds options for cluster autoscaler to the model
type ClusterAutoscalerOptionsBuilder struct {
	*OptionsContext
}

var _ loader.OptionsBuilder = &ClusterAutoscalerOptionsBuilder{}

func (b *ClusterAutoscalerOptionsBuilder) BuildOptions(o interface{}) error {
	clusterSpec := o.(*kops.ClusterSpec)
	cas := clusterSpec.ClusterAutoscaler
	if cas == nil || !fi.BoolValue(cas.Enabled) {
		return nil
	}

	if cas.Image == nil {

		image := "registry.k8s.io/autoscaling/cluster-autoscaler:latest"
		v, err := util.ParseKubernetesVersion(clusterSpec.KubernetesVersion)
		if err == nil {
			switch v.Minor {
			case 24:
				image = "registry.k8s.io/autoscaling/cluster-autoscaler:v1.23.0"
			case 23:
				image = "registry.k8s.io/autoscaling/cluster-autoscaler:v1.23.0"
			case 22:
				image = "registry.k8s.io/autoscaling/cluster-autoscaler:v1.22.2"
			case 21:
				image = "registry.k8s.io/autoscaling/cluster-autoscaler:v1.21.2"
			case 20:
				image = "registry.k8s.io/autoscaling/cluster-autoscaler:v1.20.1"
			case 19:
				image = "registry.k8s.io/autoscaling/cluster-autoscaler:v1.19.2"
			}
		}
		cas.Image = fi.String(image)

	}

	if cas.Expander == nil {
		cas.Expander = fi.String("random")
	}
	if cas.ScaleDownUtilizationThreshold == nil {
		cas.ScaleDownUtilizationThreshold = fi.String("0.5")
	}
	if cas.SkipNodesWithLocalStorage == nil {
		cas.SkipNodesWithLocalStorage = fi.Bool(true)
	}
	if cas.SkipNodesWithSystemPods == nil {
		cas.SkipNodesWithSystemPods = fi.Bool(true)
	}
	if cas.BalanceSimilarNodeGroups == nil {
		cas.BalanceSimilarNodeGroups = fi.Bool(false)
	}
	if cas.AWSUseStaticInstanceList == nil {
		cas.AWSUseStaticInstanceList = fi.Bool(false)
	}
	if cas.NewPodScaleUpDelay == nil {
		cas.NewPodScaleUpDelay = fi.String("0s")
	}
	if cas.ScaleDownDelayAfterAdd == nil {
		cas.ScaleDownDelayAfterAdd = fi.String("10m0s")
	}
	if cas.MaxNodeProvisionTime == "" {
		cas.MaxNodeProvisionTime = "15m0s"
	}

	return nil
}
<|endoftext|>


<commit_before>package handler

import (
	"encoding/json"
	"net/http"

	"github.com/sirupsen/logrus"
	"github.com/skygeario/skygear-server/pkg/core/auth/authz"
	"github.com/skygeario/skygear-server/pkg/core/auth/authz/policy"
	"github.com/skygeario/skygear-server/pkg/core/db"
	"github.com/skygeario/skygear-server/pkg/core/handler"
	"github.com/skygeario/skygear-server/pkg/core/inject"
	"github.com/skygeario/skygear-server/pkg/core/server"
	recordGear "github.com/skygeario/skygear-server/pkg/record"
	"github.com/skygeario/skygear-server/pkg/record/dependency/record"
)

func AttachFieldAccessUpdateHandler(
	server *server.Server,
	recordDependency recordGear.DependencyMap,
) *server.Server {
	server.Handle("/schema/field_access/update", &FieldAccessUpdateHandlerFactory{
		recordDependency,
	}).Methods("POST")
	return server
}

type FieldAccessUpdateHandlerFactory struct {
	Dependency recordGear.DependencyMap
}

func (f FieldAccessUpdateHandlerFactory) NewHandler(request *http.Request) http.Handler {
	h := &FieldAccessUpdateHandler{}
	inject.DefaultInject(h, f.Dependency, request)
	return handler.APIHandlerToHandler(h, h.TxContext)
}

func (f FieldAccessUpdateHandlerFactory) ProvideAuthzPolicy() authz.Policy {
	return policy.AllOf(
		authz.PolicyFunc(policy.RequireMasterKey),
	)
}

type FieldAccessUpdateRequestPayload struct {
}

func (s FieldAccessUpdateRequestPayload) Validate() error {
	return nil
}

/*
FieldAccessUpdateHandler fetches the entire Field ACL settings.
curl -X POST -H "Content-Type: application/json" \
  -d @- http://localhost:3000/schema/field_access/update <<EOF
{
	"access": [
		{
			"record_type":"note",
			"record_field":"content",
			"user_role":"_user_id:johndoe",
			"writable":false,
			"readable":true,
			"comparable":false,
			"discoverable":false
		}
	]
}
EOF
*/
type FieldAccessUpdateHandler struct {
	TxContext   db.TxContext  `dependency:"TxContext"`
	RecordStore record.Store  `dependency:"RecordStore"`
	Logger      *logrus.Entry `dependency:"HandlerLogger"`
}

func (h FieldAccessUpdateHandler) WithTx() bool {
	return true
}

func (h FieldAccessUpdateHandler) DecodeRequest(request *http.Request) (handler.RequestPayload, error) {
	payload := FieldAccessUpdateRequestPayload{}
	if err := json.NewDecoder(request.Body).Decode(&payload); err != nil {
		return nil, err
	}

	return payload, nil
}

func (h FieldAccessUpdateHandler) Handle(req interface{}) (resp interface{}, err error) {
	return
}
<commit_msg>Decode and validate field acl update req payload<commit_after>package handler

import (
	"encoding/json"
	"net/http"

	"github.com/sirupsen/logrus"
	"github.com/skygeario/skygear-server/pkg/core/auth/authz"
	"github.com/skygeario/skygear-server/pkg/core/auth/authz/policy"
	"github.com/skygeario/skygear-server/pkg/core/db"
	"github.com/skygeario/skygear-server/pkg/core/handler"
	"github.com/skygeario/skygear-server/pkg/core/inject"
	"github.com/skygeario/skygear-server/pkg/core/server"
	recordGear "github.com/skygeario/skygear-server/pkg/record"
	"github.com/skygeario/skygear-server/pkg/record/dependency/record"
	"github.com/skygeario/skygear-server/pkg/record/dependency/recordconv"
	"github.com/skygeario/skygear-server/pkg/server/skyerr"
)

func AttachFieldAccessUpdateHandler(
	server *server.Server,
	recordDependency recordGear.DependencyMap,
) *server.Server {
	server.Handle("/schema/field_access/update", &FieldAccessUpdateHandlerFactory{
		recordDependency,
	}).Methods("POST")
	return server
}

type FieldAccessUpdateHandlerFactory struct {
	Dependency recordGear.DependencyMap
}

func (f FieldAccessUpdateHandlerFactory) NewHandler(request *http.Request) http.Handler {
	h := &FieldAccessUpdateHandler{}
	inject.DefaultInject(h, f.Dependency, request)
	return handler.APIHandlerToHandler(h, h.TxContext)
}

func (f FieldAccessUpdateHandlerFactory) ProvideAuthzPolicy() authz.Policy {
	return policy.AllOf(
		authz.PolicyFunc(policy.RequireMasterKey),
	)
}

type FieldAccessUpdateRequestPayload struct {
	RawAccess []map[string]interface{} `json:"access"`
	FieldACL  record.FieldACL
}

func (p FieldAccessUpdateRequestPayload) Validate() error {
	return nil
}

/*
FieldAccessUpdateHandler fetches the entire Field ACL settings.
curl -X POST -H "Content-Type: application/json" \
  -d @- http://localhost:3000/schema/field_access/update <<EOF
{
	"access": [
		{
			"record_type":"note",
			"record_field":"content",
			"user_role":"_user_id:johndoe",
			"writable":false,
			"readable":true,
			"comparable":false,
			"discoverable":false
		}
	]
}
EOF
*/
type FieldAccessUpdateHandler struct {
	TxContext   db.TxContext  `dependency:"TxContext"`
	RecordStore record.Store  `dependency:"RecordStore"`
	Logger      *logrus.Entry `dependency:"HandlerLogger"`
}

func (h FieldAccessUpdateHandler) WithTx() bool {
	return true
}

func (h FieldAccessUpdateHandler) DecodeRequest(request *http.Request) (handler.RequestPayload, error) {
	payload := FieldAccessUpdateRequestPayload{}
	if err := json.NewDecoder(request.Body).Decode(&payload); err != nil {
		return nil, err
	}

	entries := record.FieldACLEntryList{}
	for _, v := range payload.RawAccess {
		ace := record.FieldACLEntry{}
		if err := (*recordconv.MapFieldACLEntry)(&ace).FromMap(v); err != nil {
			return nil, skyerr.NewInvalidArgument("invalid access entry", []string{"access"})
		}
		entries = append(entries, ace)
	}

	payload.FieldACL = record.NewFieldACL(entries)

	return payload, nil
}

func (h FieldAccessUpdateHandler) Handle(req interface{}) (resp interface{}, err error) {
	return
}
<|endoftext|>


<commit_before>// +build integration

package sqlstore

import (
	"testing"

	. "github.com/smartystreets/goconvey/convey"

	"github.com/grafana/grafana/pkg/models"
	"github.com/grafana/grafana/pkg/setting"
)

func TestPreferencesDataAccess(t *testing.T) {
	Convey("Testing preferences data access", t, func() {
		ss := InitTestDB(t)

		Convey("GetPreferencesWithDefaults with no saved preferences should return defaults", func() {
			setting.DefaultTheme = "light"
			ss.Cfg.DateFormats.DefaultTimezone = "UTC"

			query := &models.GetPreferencesWithDefaultsQuery{User: &models.SignedInUser{}}
			err := ss.GetPreferencesWithDefaults(query)
			So(err, ShouldBeNil)
			So(query.Result.Theme, ShouldEqual, "light")
			So(query.Result.Timezone, ShouldEqual, "UTC")
			So(query.Result.HomeDashboardId, ShouldEqual, 0)
		})

		Convey("GetPreferencesWithDefaults with saved org and user home dashboard should return user home dashboard", func() {
			err := SavePreferences(&models.SavePreferencesCommand{OrgId: 1, HomeDashboardId: 1})
			So(err, ShouldBeNil)
			err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, UserId: 1, HomeDashboardId: 4})
			So(err, ShouldBeNil)

			query := &models.GetPreferencesWithDefaultsQuery{User: &models.SignedInUser{OrgId: 1, UserId: 1}}
			err = ss.GetPreferencesWithDefaults(query)
			So(err, ShouldBeNil)
			So(query.Result.HomeDashboardId, ShouldEqual, 4)
		})

		Convey("GetPreferencesWithDefaults with saved org and other user home dashboard should return org home dashboard", func() {
			err := SavePreferences(&models.SavePreferencesCommand{OrgId: 1, HomeDashboardId: 1})
			So(err, ShouldBeNil)
			err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, UserId: 1, HomeDashboardId: 4})
			So(err, ShouldBeNil)

			query := &models.GetPreferencesWithDefaultsQuery{User: &models.SignedInUser{OrgId: 1, UserId: 2}}
			err = ss.GetPreferencesWithDefaults(query)
			So(err, ShouldBeNil)
			So(query.Result.HomeDashboardId, ShouldEqual, 1)
		})

		Convey("GetPreferencesWithDefaults with saved org and teams home dashboard should return last team home dashboard", func() {
			err := SavePreferences(&models.SavePreferencesCommand{OrgId: 1, HomeDashboardId: 1})
			So(err, ShouldBeNil)
			err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, TeamId: 2, HomeDashboardId: 2})
			So(err, ShouldBeNil)
			err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, TeamId: 3, HomeDashboardId: 3})
			So(err, ShouldBeNil)

			query := &models.GetPreferencesWithDefaultsQuery{
				User: &models.SignedInUser{OrgId: 1, Teams: []int64{2, 3}},
			}
			err = ss.GetPreferencesWithDefaults(query)
			So(err, ShouldBeNil)
			So(query.Result.HomeDashboardId, ShouldEqual, 3)
		})

		Convey("GetPreferencesWithDefaults with saved org and other teams home dashboard should return org home dashboard", func() {
			err := SavePreferences(&models.SavePreferencesCommand{OrgId: 1, HomeDashboardId: 1})
			So(err, ShouldBeNil)
			err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, TeamId: 2, HomeDashboardId: 2})
			So(err, ShouldBeNil)
			err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, TeamId: 3, HomeDashboardId: 3})
			So(err, ShouldBeNil)

			query := &models.GetPreferencesWithDefaultsQuery{User: &models.SignedInUser{OrgId: 1}}
			err = ss.GetPreferencesWithDefaults(query)
			So(err, ShouldBeNil)
			So(query.Result.HomeDashboardId, ShouldEqual, 1)
		})

		Convey("GetPreferencesWithDefaults with saved org, teams and user home dashboard should return user home dashboard", func() {
			err := SavePreferences(&models.SavePreferencesCommand{OrgId: 1, HomeDashboardId: 1})
			So(err, ShouldBeNil)
			err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, TeamId: 2, HomeDashboardId: 2})
			So(err, ShouldBeNil)
			err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, TeamId: 3, HomeDashboardId: 3})
			So(err, ShouldBeNil)
			err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, UserId: 1, HomeDashboardId: 4})
			So(err, ShouldBeNil)

			query := &models.GetPreferencesWithDefaultsQuery{
				User: &models.SignedInUser{OrgId: 1, UserId: 1, Teams: []int64{2, 3}},
			}
			err = ss.GetPreferencesWithDefaults(query)
			So(err, ShouldBeNil)
			So(query.Result.HomeDashboardId, ShouldEqual, 4)
		})

		Convey("GetPreferencesWithDefaults with saved org, other teams and user home dashboard should return org home dashboard", func() {
			err := SavePreferences(&models.SavePreferencesCommand{OrgId: 1, HomeDashboardId: 1})
			So(err, ShouldBeNil)
			err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, TeamId: 2, HomeDashboardId: 2})
			So(err, ShouldBeNil)
			err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, TeamId: 3, HomeDashboardId: 3})
			So(err, ShouldBeNil)
			err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, UserId: 1, HomeDashboardId: 4})
			So(err, ShouldBeNil)

			query := &models.GetPreferencesWithDefaultsQuery{
				User: &models.SignedInUser{OrgId: 1, UserId: 2},
			}
			err = ss.GetPreferencesWithDefaults(query)
			So(err, ShouldBeNil)
			So(query.Result.HomeDashboardId, ShouldEqual, 1)
		})
	})
}
<commit_msg>Chore: Rewrite preferences test from GoConvey to stdlib and testify (#29129)<commit_after>// +build integration

package sqlstore

import (
	"testing"

	"github.com/grafana/grafana/pkg/models"
	"github.com/grafana/grafana/pkg/setting"
	"github.com/stretchr/testify/require"
)

func TestPreferencesDataAccess(t *testing.T) {
	ss := InitTestDB(t)

	t.Run("GetPreferencesWithDefaults with no saved preferences should return defaults", func(t *testing.T) {
		setting.DefaultTheme = "light"
		ss.Cfg.DateFormats.DefaultTimezone = "UTC"

		query := &models.GetPreferencesWithDefaultsQuery{User: &models.SignedInUser{}}
		err := ss.GetPreferencesWithDefaults(query)
		require.NoError(t, err)
		require.Equal(t, "light", query.Result.Theme)
		require.Equal(t, "UTC", query.Result.Timezone)
		require.Equal(t, int64(0), query.Result.HomeDashboardId)
	})

	t.Run("GetPreferencesWithDefaults with saved org and user home dashboard should return user home dashboard", func(t *testing.T) {
		err := SavePreferences(&models.SavePreferencesCommand{OrgId: 1, HomeDashboardId: 1})
		require.NoError(t, err)
		err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, UserId: 1, HomeDashboardId: 4})
		require.NoError(t, err)

		query := &models.GetPreferencesWithDefaultsQuery{User: &models.SignedInUser{OrgId: 1, UserId: 1}}
		err = ss.GetPreferencesWithDefaults(query)
		require.NoError(t, err)
		require.Equal(t, int64(4), query.Result.HomeDashboardId)
	})

	t.Run("GetPreferencesWithDefaults with saved org and other user home dashboard should return org home dashboard", func(t *testing.T) {
		err := SavePreferences(&models.SavePreferencesCommand{OrgId: 1, HomeDashboardId: 1})
		require.NoError(t, err)
		err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, UserId: 1, HomeDashboardId: 4})
		require.NoError(t, err)

		query := &models.GetPreferencesWithDefaultsQuery{User: &models.SignedInUser{OrgId: 1, UserId: 2}}
		err = ss.GetPreferencesWithDefaults(query)
		require.NoError(t, err)
		require.Equal(t, int64(1), query.Result.HomeDashboardId)
	})

	t.Run("GetPreferencesWithDefaults with saved org and teams home dashboard should return last team home dashboard", func(t *testing.T) {
		err := SavePreferences(&models.SavePreferencesCommand{OrgId: 1, HomeDashboardId: 1})
		require.NoError(t, err)
		err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, TeamId: 2, HomeDashboardId: 2})
		require.NoError(t, err)
		err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, TeamId: 3, HomeDashboardId: 3})
		require.NoError(t, err)

		query := &models.GetPreferencesWithDefaultsQuery{
			User: &models.SignedInUser{OrgId: 1, Teams: []int64{2, 3}},
		}
		err = ss.GetPreferencesWithDefaults(query)
		require.NoError(t, err)
		require.Equal(t, int64(3), query.Result.HomeDashboardId)
	})

	t.Run("GetPreferencesWithDefaults with saved org and other teams home dashboard should return org home dashboard", func(t *testing.T) {
		err := SavePreferences(&models.SavePreferencesCommand{OrgId: 1, HomeDashboardId: 1})
		require.NoError(t, err)
		err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, TeamId: 2, HomeDashboardId: 2})
		require.NoError(t, err)
		err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, TeamId: 3, HomeDashboardId: 3})
		require.NoError(t, err)

		query := &models.GetPreferencesWithDefaultsQuery{User: &models.SignedInUser{OrgId: 1}}
		err = ss.GetPreferencesWithDefaults(query)
		require.NoError(t, err)
		require.Equal(t, int64(1), query.Result.HomeDashboardId)
	})

	t.Run("GetPreferencesWithDefaults with saved org, teams and user home dashboard should return user home dashboard", func(t *testing.T) {
		err := SavePreferences(&models.SavePreferencesCommand{OrgId: 1, HomeDashboardId: 1})
		require.NoError(t, err)
		err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, TeamId: 2, HomeDashboardId: 2})
		require.NoError(t, err)
		err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, TeamId: 3, HomeDashboardId: 3})
		require.NoError(t, err)
		err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, UserId: 1, HomeDashboardId: 4})
		require.NoError(t, err)

		query := &models.GetPreferencesWithDefaultsQuery{
			User: &models.SignedInUser{OrgId: 1, UserId: 1, Teams: []int64{2, 3}},
		}
		err = ss.GetPreferencesWithDefaults(query)
		require.NoError(t, err)
		require.Equal(t, int64(4), query.Result.HomeDashboardId)
	})

	t.Run("GetPreferencesWithDefaults with saved org, other teams and user home dashboard should return org home dashboard", func(t *testing.T) {
		err := SavePreferences(&models.SavePreferencesCommand{OrgId: 1, HomeDashboardId: 1})
		require.NoError(t, err)
		err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, TeamId: 2, HomeDashboardId: 2})
		require.NoError(t, err)
		err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, TeamId: 3, HomeDashboardId: 3})
		require.NoError(t, err)
		err = SavePreferences(&models.SavePreferencesCommand{OrgId: 1, UserId: 1, HomeDashboardId: 4})
		require.NoError(t, err)

		query := &models.GetPreferencesWithDefaultsQuery{
			User: &models.SignedInUser{OrgId: 1, UserId: 2},
		}
		err = ss.GetPreferencesWithDefaults(query)
		require.NoError(t, err)
		require.Equal(t, int64(1), query.Result.HomeDashboardId)
	})
}
<|endoftext|>