<commit_before>package storage

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"time"

	"github.com/chrislusf/seaweedfs/weed/glog"
	. "github.com/chrislusf/seaweedfs/weed/storage/types"
)

// isFileUnchanged checks whether this needle to write is same as last one.
// It requires serialized access in the same volume.
func (v *Volume) isFileUnchanged(n *Needle) bool {
	if v.Ttl.String() != "" {
		return false
	}
	nv, ok := v.nm.Get(n.Id)
	if ok && nv.Offset > 0 {
		oldNeedle := new(Needle)
		err := oldNeedle.ReadData(v.dataFile, int64(nv.Offset)*NeedlePaddingSize, nv.Size, v.Version())
		if err != nil {
			glog.V(0).Infof("Failed to check updated file %v", err)
			return false
		}
		if oldNeedle.Checksum == n.Checksum && bytes.Equal(oldNeedle.Data, n.Data) {
			n.DataSize = oldNeedle.DataSize
			return true
		}
	}
	return false
}

// Destroy removes everything related to this volume
func (v *Volume) Destroy() (err error) {
	if v.readOnly {
		err = fmt.Errorf("%s is read-only", v.dataFile.Name())
		return
	}
	v.Close()
	os.Remove(v.FileName() + ".dat")
	if v.nm != nil {
		err = v.nm.Destroy()
	}
	os.Remove(v.FileName() + ".cpd")
	os.Remove(v.FileName() + ".cpx")
	os.Remove(v.FileName() + ".ldb")
	os.Remove(v.FileName() + ".bdb")
	return
}

// AppendBlob append a blob to end of the data file, used in replication
func (v *Volume) AppendBlob(b []byte) (offset int64, err error) {
	if v.readOnly {
		err = fmt.Errorf("%s is read-only", v.dataFile.Name())
		return
	}
	v.dataFileAccessLock.Lock()
	defer v.dataFileAccessLock.Unlock()
	if offset, err = v.dataFile.Seek(0, 2); err != nil {
		glog.V(0).Infof("failed to seek the end of file: %v", err)
		return
	}
	//ensure file writing starting from aligned positions
	if offset%NeedlePaddingSize != 0 {
		offset = offset + (NeedlePaddingSize - offset%NeedlePaddingSize)
		if offset, err = v.dataFile.Seek(offset, 0); err != nil {
			glog.V(0).Infof("failed to align in datafile %s: %v", v.dataFile.Name(), err)
			return
		}
	}
	_, err = v.dataFile.Write(b)
	return
}

func (v *Volume) writeNeedle(n *Needle) (size uint32, err error) {
	glog.V(4).Infof("writing needle %s", NewFileIdFromNeedle(v.Id, n).String())
	if v.readOnly {
		err = fmt.Errorf("%s is read-only", v.dataFile.Name())
		return
	}
	v.dataFileAccessLock.Lock()
	defer v.dataFileAccessLock.Unlock()
	if v.isFileUnchanged(n) {
		size = n.DataSize
		glog.V(4).Infof("needle is unchanged!")
		return
	}
	var offset int64
	if offset, err = v.dataFile.Seek(0, 2); err != nil {
		glog.V(0).Infof("failed to seek the end of file: %v", err)
		return
	}

	//ensure file writing starting from aligned positions
	if offset%NeedlePaddingSize != 0 {
		offset = offset + (NeedlePaddingSize - offset%NeedlePaddingSize)
		if offset, err = v.dataFile.Seek(offset, 0); err != nil {
			glog.V(0).Infof("failed to align in datafile %s: %v", v.dataFile.Name(), err)
			return
		}
	}

	n.AppendAtNs = uint64(time.Now().UnixNano())
	if size, _, err = n.Append(v.dataFile, v.Version()); err != nil {
		if e := v.dataFile.Truncate(offset); e != nil {
			err = fmt.Errorf("%s\ncannot truncate %s: %v", err, v.dataFile.Name(), e)
		}
		return
	}

	nv, ok := v.nm.Get(n.Id)
	if !ok || int64(nv.Offset)*NeedlePaddingSize < offset {
		if err = v.nm.Put(n.Id, Offset(offset/NeedlePaddingSize), n.Size); err != nil {
			glog.V(4).Infof("failed to save in needle map %d: %v", n.Id, err)
		}
	}
	if v.lastModifiedTime < n.LastModified {
		v.lastModifiedTime = n.LastModified
	}
	return
}

func (v *Volume) deleteNeedle(n *Needle) (uint32, error) {
	glog.V(4).Infof("delete needle %s", NewFileIdFromNeedle(v.Id, n).String())
	if v.readOnly {
		return 0, fmt.Errorf("%s is read-only", v.dataFile.Name())
	}
	v.dataFileAccessLock.Lock()
	defer v.dataFileAccessLock.Unlock()
	nv, ok := v.nm.Get(n.Id)
	//fmt.Println("key", n.Id, "volume offset", nv.Offset, "data_size", n.Size, "cached size", nv.Size)
	if ok && nv.Size != TombstoneFileSize {
		size := nv.Size
		offset, err := v.dataFile.Seek(0, 2)
		if err != nil {
			return size, err
		}
		if err := v.nm.Delete(n.Id, Offset(offset/NeedlePaddingSize)); err != nil {
			return size, err
		}
		n.Data = nil
		n.AppendAtNs = uint64(time.Now().UnixNano())
		_, _, err = n.Append(v.dataFile, v.Version())
		return size, err
	}
	return 0, nil
}

// read fills in Needle content by looking up n.Id from NeedleMapper
func (v *Volume) readNeedle(n *Needle) (int, error) {
	nv, ok := v.nm.Get(n.Id)
	if !ok || nv.Offset == 0 {
		return -1, errors.New("Not Found")
	}
	if nv.Size == TombstoneFileSize {
		return -1, errors.New("Already Deleted")
	}
	err := n.ReadData(v.dataFile, int64(nv.Offset)*NeedlePaddingSize, nv.Size, v.Version())
	if err != nil {
		return 0, err
	}
	bytesRead := len(n.Data)
	if !n.HasTtl() {
		return bytesRead, nil
	}
	ttlMinutes := n.Ttl.Minutes()
	if ttlMinutes == 0 {
		return bytesRead, nil
	}
	if !n.HasLastModifiedDate() {
		return bytesRead, nil
	}
	if uint64(time.Now().Unix()) < n.LastModified+uint64(ttlMinutes*60) {
		return bytesRead, nil
	}
	return -1, errors.New("Not Found")
}

func ScanVolumeFile(dirname string, collection string, id VolumeId,
	needleMapKind NeedleMapType,
	visitSuperBlock func(SuperBlock) error,
	readNeedleBody bool,
	visitNeedle func(n *Needle, offset int64) error) (err error) {
	var v *Volume
	if v, err = loadVolumeWithoutIndex(dirname, collection, id, needleMapKind); err != nil {
		return fmt.Errorf("Failed to load volume %d: %v", id, err)
	}
	if err = visitSuperBlock(v.SuperBlock); err != nil {
		return fmt.Errorf("Failed to process volume %d super block: %v", id, err)
	}
	defer v.Close()

	version := v.Version()

	offset := int64(v.SuperBlock.BlockSize())
	n, rest, e := ReadNeedleHeader(v.dataFile, version, offset)
	if e != nil {
		err = fmt.Errorf("cannot read needle header: %v", e)
		return
	}
	for n != nil {
		if readNeedleBody {
			if err = n.ReadNeedleBody(v.dataFile, version, offset+NeedleEntrySize, rest); err != nil {
				glog.V(0).Infof("cannot read needle body: %v", err)
				//err = fmt.Errorf("cannot read needle body: %v", err)
				//return
			}
		}
		err = visitNeedle(n, offset)
		if err == io.EOF {
			return nil
		}
		if err != nil {
			glog.V(0).Infof("visit needle error: %v", err)
		}
		offset += NeedleEntrySize + rest
		glog.V(4).Infof("==> new entry offset %d", offset)
		if n, rest, err = ReadNeedleHeader(v.dataFile, version, offset); err != nil {
			if err == io.EOF {
				return nil
			}
			return fmt.Errorf("cannot read needle header: %v", err)
		}
		glog.V(4).Infof("new entry needle size:%d rest:%d", n.Size, rest)
	}

	return
}
<commit_msg>remove index file<commit_after>package storage

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"time"

	"github.com/chrislusf/seaweedfs/weed/glog"
	. "github.com/chrislusf/seaweedfs/weed/storage/types"
)

// isFileUnchanged checks whether this needle to write is same as last one.
// It requires serialized access in the same volume.
func (v *Volume) isFileUnchanged(n *Needle) bool {
	if v.Ttl.String() != "" {
		return false
	}
	nv, ok := v.nm.Get(n.Id)
	if ok && nv.Offset > 0 {
		oldNeedle := new(Needle)
		err := oldNeedle.ReadData(v.dataFile, int64(nv.Offset)*NeedlePaddingSize, nv.Size, v.Version())
		if err != nil {
			glog.V(0).Infof("Failed to check updated file %v", err)
			return false
		}
		if oldNeedle.Checksum == n.Checksum && bytes.Equal(oldNeedle.Data, n.Data) {
			n.DataSize = oldNeedle.DataSize
			return true
		}
	}
	return false
}

// Destroy removes everything related to this volume
func (v *Volume) Destroy() (err error) {
	if v.readOnly {
		err = fmt.Errorf("%s is read-only", v.dataFile.Name())
		return
	}
	v.Close()
	os.Remove(v.FileName() + ".dat")
	os.Remove(v.FileName() + ".idx")
	os.Remove(v.FileName() + ".cpd")
	os.Remove(v.FileName() + ".cpx")
	os.Remove(v.FileName() + ".ldb")
	os.Remove(v.FileName() + ".bdb")
	return
}

// AppendBlob append a blob to end of the data file, used in replication
func (v *Volume) AppendBlob(b []byte) (offset int64, err error) {
	if v.readOnly {
		err = fmt.Errorf("%s is read-only", v.dataFile.Name())
		return
	}
	v.dataFileAccessLock.Lock()
	defer v.dataFileAccessLock.Unlock()
	if offset, err = v.dataFile.Seek(0, 2); err != nil {
		glog.V(0).Infof("failed to seek the end of file: %v", err)
		return
	}
	//ensure file writing starting from aligned positions
	if offset%NeedlePaddingSize != 0 {
		offset = offset + (NeedlePaddingSize - offset%NeedlePaddingSize)
		if offset, err = v.dataFile.Seek(offset, 0); err != nil {
			glog.V(0).Infof("failed to align in datafile %s: %v", v.dataFile.Name(), err)
			return
		}
	}
	_, err = v.dataFile.Write(b)
	return
}

func (v *Volume) writeNeedle(n *Needle) (size uint32, err error) {
	glog.V(4).Infof("writing needle %s", NewFileIdFromNeedle(v.Id, n).String())
	if v.readOnly {
		err = fmt.Errorf("%s is read-only", v.dataFile.Name())
		return
	}
	v.dataFileAccessLock.Lock()
	defer v.dataFileAccessLock.Unlock()
	if v.isFileUnchanged(n) {
		size = n.DataSize
		glog.V(4).Infof("needle is unchanged!")
		return
	}
	var offset int64
	if offset, err = v.dataFile.Seek(0, 2); err != nil {
		glog.V(0).Infof("failed to seek the end of file: %v", err)
		return
	}

	//ensure file writing starting from aligned positions
	if offset%NeedlePaddingSize != 0 {
		offset = offset + (NeedlePaddingSize - offset%NeedlePaddingSize)
		if offset, err = v.dataFile.Seek(offset, 0); err != nil {
			glog.V(0).Infof("failed to align in datafile %s: %v", v.dataFile.Name(), err)
			return
		}
	}

	n.AppendAtNs = uint64(time.Now().UnixNano())
	if size, _, err = n.Append(v.dataFile, v.Version()); err != nil {
		if e := v.dataFile.Truncate(offset); e != nil {
			err = fmt.Errorf("%s\ncannot truncate %s: %v", err, v.dataFile.Name(), e)
		}
		return
	}

	nv, ok := v.nm.Get(n.Id)
	if !ok || int64(nv.Offset)*NeedlePaddingSize < offset {
		if err = v.nm.Put(n.Id, Offset(offset/NeedlePaddingSize), n.Size); err != nil {
			glog.V(4).Infof("failed to save in needle map %d: %v", n.Id, err)
		}
	}
	if v.lastModifiedTime < n.LastModified {
		v.lastModifiedTime = n.LastModified
	}
	return
}

func (v *Volume) deleteNeedle(n *Needle) (uint32, error) {
	glog.V(4).Infof("delete needle %s", NewFileIdFromNeedle(v.Id, n).String())
	if v.readOnly {
		return 0, fmt.Errorf("%s is read-only", v.dataFile.Name())
	}
	v.dataFileAccessLock.Lock()
	defer v.dataFileAccessLock.Unlock()
	nv, ok := v.nm.Get(n.Id)
	//fmt.Println("key", n.Id, "volume offset", nv.Offset, "data_size", n.Size, "cached size", nv.Size)
	if ok && nv.Size != TombstoneFileSize {
		size := nv.Size
		offset, err := v.dataFile.Seek(0, 2)
		if err != nil {
			return size, err
		}
		if err := v.nm.Delete(n.Id, Offset(offset/NeedlePaddingSize)); err != nil {
			return size, err
		}
		n.Data = nil
		n.AppendAtNs = uint64(time.Now().UnixNano())
		_, _, err = n.Append(v.dataFile, v.Version())
		return size, err
	}
	return 0, nil
}

// read fills in Needle content by looking up n.Id from NeedleMapper
func (v *Volume) readNeedle(n *Needle) (int, error) {
	nv, ok := v.nm.Get(n.Id)
	if !ok || nv.Offset == 0 {
		return -1, errors.New("Not Found")
	}
	if nv.Size == TombstoneFileSize {
		return -1, errors.New("Already Deleted")
	}
	err := n.ReadData(v.dataFile, int64(nv.Offset)*NeedlePaddingSize, nv.Size, v.Version())
	if err != nil {
		return 0, err
	}
	bytesRead := len(n.Data)
	if !n.HasTtl() {
		return bytesRead, nil
	}
	ttlMinutes := n.Ttl.Minutes()
	if ttlMinutes == 0 {
		return bytesRead, nil
	}
	if !n.HasLastModifiedDate() {
		return bytesRead, nil
	}
	if uint64(time.Now().Unix()) < n.LastModified+uint64(ttlMinutes*60) {
		return bytesRead, nil
	}
	return -1, errors.New("Not Found")
}

func ScanVolumeFile(dirname string, collection string, id VolumeId,
	needleMapKind NeedleMapType,
	visitSuperBlock func(SuperBlock) error,
	readNeedleBody bool,
	visitNeedle func(n *Needle, offset int64) error) (err error) {
	var v *Volume
	if v, err = loadVolumeWithoutIndex(dirname, collection, id, needleMapKind); err != nil {
		return fmt.Errorf("Failed to load volume %d: %v", id, err)
	}
	if err = visitSuperBlock(v.SuperBlock); err != nil {
		return fmt.Errorf("Failed to process volume %d super block: %v", id, err)
	}
	defer v.Close()

	version := v.Version()

	offset := int64(v.SuperBlock.BlockSize())
	n, rest, e := ReadNeedleHeader(v.dataFile, version, offset)
	if e != nil {
		err = fmt.Errorf("cannot read needle header: %v", e)
		return
	}
	for n != nil {
		if readNeedleBody {
			if err = n.ReadNeedleBody(v.dataFile, version, offset+NeedleEntrySize, rest); err != nil {
				glog.V(0).Infof("cannot read needle body: %v", err)
				//err = fmt.Errorf("cannot read needle body: %v", err)
				//return
			}
		}
		err = visitNeedle(n, offset)
		if err == io.EOF {
			return nil
		}
		if err != nil {
			glog.V(0).Infof("visit needle error: %v", err)
		}
		offset += NeedleEntrySize + rest
		glog.V(4).Infof("==> new entry offset %d", offset)
		if n, rest, err = ReadNeedleHeader(v.dataFile, version, offset); err != nil {
			if err == io.EOF {
				return nil
			}
			return fmt.Errorf("cannot read needle header: %v", err)
		}
		glog.V(4).Infof("new entry needle size:%d rest:%d", n.Size, rest)
	}

	return
}
<|endoftext|>


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

package provisioner

import (
	"sync"
	"time"

	"github.com/juju/errors"
	"github.com/juju/loggo"
	"github.com/juju/names"

	"github.com/juju/juju/agent"
	apiprovisioner "github.com/juju/juju/api/provisioner"
	"github.com/juju/juju/environmentserver/authentication"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/instance"
	"github.com/juju/juju/state/watcher"
	"github.com/juju/juju/watcher"
	"github.com/juju/juju/worker"
	"github.com/juju/juju/worker/catacomb"
	"github.com/juju/juju/worker/environ"
)

var logger = loggo.GetLogger("juju.provisioner")

// Ensure our structs implement the required Provisioner interface.
var _ Provisioner = (*environProvisioner)(nil)
var _ Provisioner = (*containerProvisioner)(nil)

var (
	retryStrategyDelay = 10 * time.Second
	retryStrategyCount = 3
)

// Provisioner represents a running provisioner worker.
type Provisioner interface {
	worker.Worker
	getMachineWatcher() (watcher.StringsWatcher, error)
	getRetryWatcher() (watcher.NotifyWatcher, error)
}

// environProvisioner represents a running provisioning worker for machine nodes
// belonging to an environment.
type environProvisioner struct {
	provisioner
	environ environs.Environ
	configObserver
}

// containerProvisioner represents a running provisioning worker for containers
// hosted on a machine.
type containerProvisioner struct {
	provisioner
	containerType instance.ContainerType
	machine       *apiprovisioner.Machine
	configObserver
}

// provisioner providers common behaviour for a running provisioning worker.
type provisioner struct {
	Provisioner
	st          *apiprovisioner.State
	agentConfig agent.Config
	broker      environs.InstanceBroker
	toolsFinder ToolsFinder
	catacomb    catacomb.Catacomb
}

// RetryStrategy defines the retry behavior when encountering a retryable
// error during provisioning.
type RetryStrategy struct {
	retryDelay time.Duration
	retryCount int
}

// NewRetryStrategy returns a new retry strategy with the specified delay and
// count for use with retryable provisioning errors.
func NewRetryStrategy(delay time.Duration, count int) RetryStrategy {
	return RetryStrategy{
		retryDelay: delay,
		retryCount: count,
	}
}

// configObserver is implemented so that tests can see
// when the environment configuration changes.
type configObserver struct {
	sync.Mutex
	observer chan<- *config.Config
}

// notify notifies the observer of a configuration change.
func (o *configObserver) notify(cfg *config.Config) {
	o.Lock()
	if o.observer != nil {
		o.observer <- cfg
	}
	o.Unlock()
}

// Kill implements worker.Worker.Kill.
func (p *provisioner) Kill() {
	p.catacomb.Kill(nil)
}

// Wait implements worker.Worker.Wait.
func (p *provisioner) Wait() error {
	return p.catacomb.Wait()
}

// getToolsFinder returns a ToolsFinder for the provided State.
// This exists for mocking.
var getToolsFinder = func(st *apiprovisioner.State) ToolsFinder {
	return st
}

// getStartTask creates a new worker for the provisioner,
func (p *provisioner) getStartTask(harvestMode config.HarvestMode) (ProvisionerTask, error) {
	auth, err := authentication.NewAPIAuthenticator(p.st)
	if err != nil {
		return nil, err
	}
	// Start responding to changes in machines, and to any further updates
	// to the environment config.
	machineWatcher, err := p.getMachineWatcher()
	if err != nil {
		return nil, err
	}
	retryWatcher, err := p.getRetryWatcher()
	if err != nil && !errors.IsNotImplemented(err) {
		return nil, err
	}
	tag := p.agentConfig.Tag()
	machineTag, ok := tag.(names.MachineTag)
	if !ok {
		errors.Errorf("expacted names.MachineTag, got %T", tag)
	}

	envCfg, err := p.st.EnvironConfig()
	if err != nil {
		return nil, errors.Annotate(err, "could not retrieve the environment config.")
	}

	secureServerConnection := false
	if info, ok := p.agentConfig.StateServingInfo(); ok {
		secureServerConnection = info.CAPrivateKey != ""
	}
	task, err := NewProvisionerTask(
		machineTag,
		harvestMode,
		p.st,
		p.toolsFinder,
		machineWatcher,
		retryWatcher,
		p.broker,
		auth,
		envCfg.ImageStream(),
		secureServerConnection,
		RetryStrategy{retryDelay: retryStrategyDelay, retryCount: retryStrategyCount},
	)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return task, nil
}

// NewEnvironProvisioner returns a new Provisioner for an environment.
// When new machines are added to the state, it allocates instances
// from the environment and allocates them to the new machines.
func NewEnvironProvisioner(st *apiprovisioner.State, agentConfig agent.Config) (Provisioner, error) {
	p := &environProvisioner{
		provisioner: provisioner{
			st:          st,
			agentConfig: agentConfig,
			toolsFinder: getToolsFinder(st),
		},
	}
	p.Provisioner = p
	logger.Tracef("Starting environ provisioner for %q", p.agentConfig.Tag())

	err := catacomb.Invoke(catacomb.Plan{
		Site: &p.catacomb,
		Work: p.loop,
	})
	if err != nil {
		return nil, errors.Trace(err)
	}
	return p, nil
}

func (p *environProvisioner) loop() error {
	var environConfigChanges <-chan struct{}
	environWatcher, err := p.st.WatchForEnvironConfigChanges()
	if err != nil {
		return loggedErrorStack(errors.Trace(err))
	}
	if err := p.catacomb.Add(environWatcher); err != nil {
		return errors.Trace(err)
	}
	environConfigChanges = environWatcher.Changes()

	p.environ, err = environ.WaitForEnviron(environWatcher, p.st, p.catacomb.Dying())
	if err != nil {
		if err == environ.ErrWaitAborted {
			return p.catacomb.ErrDying()
		}
		return loggedErrorStack(errors.Trace(err))
	}
	p.broker = p.environ

	harvestMode := p.environ.Config().ProvisionerHarvestMode()
	task, err := p.getStartTask(harvestMode)
	if err != nil {
		return loggedErrorStack(errors.Trace(err))
	}
	if err := p.catacomb.Add(task); err != nil {
		return errors.Trace(err)
	}

	for {
		select {
		case <-p.catacomb.Dying():
			return p.catacomb.ErrDying()
		case _, ok := <-environConfigChanges:
			if !ok {
				return errors.New("environment configuration watcher closed")
			}
			environConfig, err := p.st.EnvironConfig()
			if err != nil {
				return errors.Annotate(err, "cannot load environment configuration")
			}
			if err := p.setConfig(environConfig); err != nil {
				return errors.Annotate(err, "loaded invalid environment configuration")
			}
			task.SetHarvestMode(environConfig.ProvisionerHarvestMode())
		}
	}
}

func (p *environProvisioner) getMachineWatcher() (watcher.StringsWatcher, error) {
	return p.st.WatchEnvironMachines()
}

func (p *environProvisioner) getRetryWatcher() (watcher.NotifyWatcher, error) {
	return p.st.WatchMachineErrorRetry()
}

// setConfig updates the environment configuration and notifies
// the config observer.
func (p *environProvisioner) setConfig(environConfig *config.Config) error {
	if err := p.environ.SetConfig(environConfig); err != nil {
		return err
	}
	p.configObserver.notify(environConfig)
	return nil
}

// NewContainerProvisioner returns a new Provisioner. When new machines
// are added to the state, it allocates instances from the environment
// and allocates them to the new machines.
func NewContainerProvisioner(
	containerType instance.ContainerType,
	st *apiprovisioner.State,
	agentConfig agent.Config,
	broker environs.InstanceBroker,
	toolsFinder ToolsFinder,
) (Provisioner, error) {

	p := &containerProvisioner{
		provisioner: provisioner{
			st:          st,
			agentConfig: agentConfig,
			broker:      broker,
			toolsFinder: toolsFinder,
		},
		containerType: containerType,
	}
	p.Provisioner = p
	logger.Tracef("Starting %s provisioner for %q", p.containerType, p.agentConfig.Tag())

	err := catacomb.Invoke(catacomb.Plan{
		Site: &p.catacomb,
		Work: p.loop,
	})
	if err != nil {
		return nil, errors.Trace(err)
	}
	return p, nil
}

func (p *containerProvisioner) loop() error {
	environWatcher, err := p.st.WatchForEnvironConfigChanges()
	if err != nil {
		return errors.Trace(err)
	}
	if err := p.catacomb.Add(environWatcher); err != nil {
		return errors.Trace(err)
	}

	config, err := p.st.EnvironConfig()
	if err != nil {
		return err
	}
	harvestMode := config.ProvisionerHarvestMode()

	task, err := p.getStartTask(harvestMode)
	if err != nil {
		return err
	}
	if err := p.catacomb.Add(task); err != nil {
		return errors.Trace(err)
	}

	for {
		select {
		case <-p.catacomb.Dying():
			return p.catacomb.ErrDying()
		case _, ok := <-environWatcher.Changes():
			if !ok {
				return errors.New("environment configuratioon watch closed")
			}
			environConfig, err := p.st.EnvironConfig()
			if err != nil {
				return errors.Annotate(err, "cannot load environment configuration")
			}
			p.configObserver.notify(environConfig)
			task.SetHarvestMode(environConfig.ProvisionerHarvestMode())
		}
	}
}

func (p *containerProvisioner) getMachine() (*apiprovisioner.Machine, error) {
	if p.machine == nil {
		tag := p.agentConfig.Tag()
		machineTag, ok := tag.(names.MachineTag)
		if !ok {
			return nil, errors.Errorf("expected names.MachineTag, got %T", tag)
		}
		var err error
		if p.machine, err = p.st.Machine(machineTag); err != nil {
			logger.Errorf("%s is not in state", machineTag)
			return nil, err
		}
	}
	return p.machine, nil
}

func (p *containerProvisioner) getMachineWatcher() (watcher.StringsWatcher, error) {
	machine, err := p.getMachine()
	if err != nil {
		return nil, err
	}
	return machine.WatchContainers(p.containerType)
}

func (p *containerProvisioner) getRetryWatcher() (watcher.NotifyWatcher, error) {
	return nil, errors.NotImplementedf("getRetryWatcher")
}
<commit_msg>worker/provisioner: Fix imports<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package provisioner

import (
	"sync"
	"time"

	"github.com/juju/errors"
	"github.com/juju/loggo"
	"github.com/juju/names"

	"github.com/juju/juju/agent"
	apiprovisioner "github.com/juju/juju/api/provisioner"
	"github.com/juju/juju/environmentserver/authentication"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/instance"
	"github.com/juju/juju/watcher"
	"github.com/juju/juju/worker"
	"github.com/juju/juju/worker/catacomb"
	"github.com/juju/juju/worker/environ"
)

var logger = loggo.GetLogger("juju.provisioner")

// Ensure our structs implement the required Provisioner interface.
var _ Provisioner = (*environProvisioner)(nil)
var _ Provisioner = (*containerProvisioner)(nil)

var (
	retryStrategyDelay = 10 * time.Second
	retryStrategyCount = 3
)

// Provisioner represents a running provisioner worker.
type Provisioner interface {
	worker.Worker
	getMachineWatcher() (watcher.StringsWatcher, error)
	getRetryWatcher() (watcher.NotifyWatcher, error)
}

// environProvisioner represents a running provisioning worker for machine nodes
// belonging to an environment.
type environProvisioner struct {
	provisioner
	environ environs.Environ
	configObserver
}

// containerProvisioner represents a running provisioning worker for containers
// hosted on a machine.
type containerProvisioner struct {
	provisioner
	containerType instance.ContainerType
	machine       *apiprovisioner.Machine
	configObserver
}

// provisioner providers common behaviour for a running provisioning worker.
type provisioner struct {
	Provisioner
	st          *apiprovisioner.State
	agentConfig agent.Config
	broker      environs.InstanceBroker
	toolsFinder ToolsFinder
	catacomb    catacomb.Catacomb
}

// RetryStrategy defines the retry behavior when encountering a retryable
// error during provisioning.
type RetryStrategy struct {
	retryDelay time.Duration
	retryCount int
}

// NewRetryStrategy returns a new retry strategy with the specified delay and
// count for use with retryable provisioning errors.
func NewRetryStrategy(delay time.Duration, count int) RetryStrategy {
	return RetryStrategy{
		retryDelay: delay,
		retryCount: count,
	}
}

// configObserver is implemented so that tests can see
// when the environment configuration changes.
type configObserver struct {
	sync.Mutex
	observer chan<- *config.Config
}

// notify notifies the observer of a configuration change.
func (o *configObserver) notify(cfg *config.Config) {
	o.Lock()
	if o.observer != nil {
		o.observer <- cfg
	}
	o.Unlock()
}

// Kill implements worker.Worker.Kill.
func (p *provisioner) Kill() {
	p.catacomb.Kill(nil)
}

// Wait implements worker.Worker.Wait.
func (p *provisioner) Wait() error {
	return p.catacomb.Wait()
}

// getToolsFinder returns a ToolsFinder for the provided State.
// This exists for mocking.
var getToolsFinder = func(st *apiprovisioner.State) ToolsFinder {
	return st
}

// getStartTask creates a new worker for the provisioner,
func (p *provisioner) getStartTask(harvestMode config.HarvestMode) (ProvisionerTask, error) {
	auth, err := authentication.NewAPIAuthenticator(p.st)
	if err != nil {
		return nil, err
	}
	// Start responding to changes in machines, and to any further updates
	// to the environment config.
	machineWatcher, err := p.getMachineWatcher()
	if err != nil {
		return nil, err
	}
	retryWatcher, err := p.getRetryWatcher()
	if err != nil && !errors.IsNotImplemented(err) {
		return nil, err
	}
	tag := p.agentConfig.Tag()
	machineTag, ok := tag.(names.MachineTag)
	if !ok {
		errors.Errorf("expacted names.MachineTag, got %T", tag)
	}

	envCfg, err := p.st.EnvironConfig()
	if err != nil {
		return nil, errors.Annotate(err, "could not retrieve the environment config.")
	}

	secureServerConnection := false
	if info, ok := p.agentConfig.StateServingInfo(); ok {
		secureServerConnection = info.CAPrivateKey != ""
	}
	task, err := NewProvisionerTask(
		machineTag,
		harvestMode,
		p.st,
		p.toolsFinder,
		machineWatcher,
		retryWatcher,
		p.broker,
		auth,
		envCfg.ImageStream(),
		secureServerConnection,
		RetryStrategy{retryDelay: retryStrategyDelay, retryCount: retryStrategyCount},
	)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return task, nil
}

// NewEnvironProvisioner returns a new Provisioner for an environment.
// When new machines are added to the state, it allocates instances
// from the environment and allocates them to the new machines.
func NewEnvironProvisioner(st *apiprovisioner.State, agentConfig agent.Config) (Provisioner, error) {
	p := &environProvisioner{
		provisioner: provisioner{
			st:          st,
			agentConfig: agentConfig,
			toolsFinder: getToolsFinder(st),
		},
	}
	p.Provisioner = p
	logger.Tracef("Starting environ provisioner for %q", p.agentConfig.Tag())

	err := catacomb.Invoke(catacomb.Plan{
		Site: &p.catacomb,
		Work: p.loop,
	})
	if err != nil {
		return nil, errors.Trace(err)
	}
	return p, nil
}

func (p *environProvisioner) loop() error {
	var environConfigChanges <-chan struct{}
	environWatcher, err := p.st.WatchForEnvironConfigChanges()
	if err != nil {
		return loggedErrorStack(errors.Trace(err))
	}
	if err := p.catacomb.Add(environWatcher); err != nil {
		return errors.Trace(err)
	}
	environConfigChanges = environWatcher.Changes()

	p.environ, err = environ.WaitForEnviron(environWatcher, p.st, p.catacomb.Dying())
	if err != nil {
		if err == environ.ErrWaitAborted {
			return p.catacomb.ErrDying()
		}
		return loggedErrorStack(errors.Trace(err))
	}
	p.broker = p.environ

	harvestMode := p.environ.Config().ProvisionerHarvestMode()
	task, err := p.getStartTask(harvestMode)
	if err != nil {
		return loggedErrorStack(errors.Trace(err))
	}
	if err := p.catacomb.Add(task); err != nil {
		return errors.Trace(err)
	}

	for {
		select {
		case <-p.catacomb.Dying():
			return p.catacomb.ErrDying()
		case _, ok := <-environConfigChanges:
			if !ok {
				return errors.New("environment configuration watcher closed")
			}
			environConfig, err := p.st.EnvironConfig()
			if err != nil {
				return errors.Annotate(err, "cannot load environment configuration")
			}
			if err := p.setConfig(environConfig); err != nil {
				return errors.Annotate(err, "loaded invalid environment configuration")
			}
			task.SetHarvestMode(environConfig.ProvisionerHarvestMode())
		}
	}
}

func (p *environProvisioner) getMachineWatcher() (watcher.StringsWatcher, error) {
	return p.st.WatchEnvironMachines()
}

func (p *environProvisioner) getRetryWatcher() (watcher.NotifyWatcher, error) {
	return p.st.WatchMachineErrorRetry()
}

// setConfig updates the environment configuration and notifies
// the config observer.
func (p *environProvisioner) setConfig(environConfig *config.Config) error {
	if err := p.environ.SetConfig(environConfig); err != nil {
		return err
	}
	p.configObserver.notify(environConfig)
	return nil
}

// NewContainerProvisioner returns a new Provisioner. When new machines
// are added to the state, it allocates instances from the environment
// and allocates them to the new machines.
func NewContainerProvisioner(
	containerType instance.ContainerType,
	st *apiprovisioner.State,
	agentConfig agent.Config,
	broker environs.InstanceBroker,
	toolsFinder ToolsFinder,
) (Provisioner, error) {

	p := &containerProvisioner{
		provisioner: provisioner{
			st:          st,
			agentConfig: agentConfig,
			broker:      broker,
			toolsFinder: toolsFinder,
		},
		containerType: containerType,
	}
	p.Provisioner = p
	logger.Tracef("Starting %s provisioner for %q", p.containerType, p.agentConfig.Tag())

	err := catacomb.Invoke(catacomb.Plan{
		Site: &p.catacomb,
		Work: p.loop,
	})
	if err != nil {
		return nil, errors.Trace(err)
	}
	return p, nil
}

func (p *containerProvisioner) loop() error {
	environWatcher, err := p.st.WatchForEnvironConfigChanges()
	if err != nil {
		return errors.Trace(err)
	}
	if err := p.catacomb.Add(environWatcher); err != nil {
		return errors.Trace(err)
	}

	config, err := p.st.EnvironConfig()
	if err != nil {
		return err
	}
	harvestMode := config.ProvisionerHarvestMode()

	task, err := p.getStartTask(harvestMode)
	if err != nil {
		return err
	}
	if err := p.catacomb.Add(task); err != nil {
		return errors.Trace(err)
	}

	for {
		select {
		case <-p.catacomb.Dying():
			return p.catacomb.ErrDying()
		case _, ok := <-environWatcher.Changes():
			if !ok {
				return errors.New("environment configuratioon watch closed")
			}
			environConfig, err := p.st.EnvironConfig()
			if err != nil {
				return errors.Annotate(err, "cannot load environment configuration")
			}
			p.configObserver.notify(environConfig)
			task.SetHarvestMode(environConfig.ProvisionerHarvestMode())
		}
	}
}

func (p *containerProvisioner) getMachine() (*apiprovisioner.Machine, error) {
	if p.machine == nil {
		tag := p.agentConfig.Tag()
		machineTag, ok := tag.(names.MachineTag)
		if !ok {
			return nil, errors.Errorf("expected names.MachineTag, got %T", tag)
		}
		var err error
		if p.machine, err = p.st.Machine(machineTag); err != nil {
			logger.Errorf("%s is not in state", machineTag)
			return nil, err
		}
	}
	return p.machine, nil
}

func (p *containerProvisioner) getMachineWatcher() (watcher.StringsWatcher, error) {
	machine, err := p.getMachine()
	if err != nil {
		return nil, err
	}
	return machine.WatchContainers(p.containerType)
}

func (p *containerProvisioner) getRetryWatcher() (watcher.NotifyWatcher, error) {
	return nil, errors.NotImplementedf("getRetryWatcher")
}
<|endoftext|>


<commit_before>package router

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"io"
	"sync"
)

type Peers struct {
	sync.RWMutex
	ourself *Peer
	table   map[PeerName]*Peer
	onGC    func(*Peer)
}

type UnknownPeersError struct {
}

type NameCollisionError struct {
	Name PeerName
}

func NewPeers(ourself *Peer, onGC func(*Peer)) *Peers {
	return &Peers{
		ourself: ourself,
		table:   make(map[PeerName]*Peer),
		onGC:    onGC}
}

func (peers *Peers) FetchWithDefault(peer *Peer) *Peer {
	peers.RLock()
	res, found := peers.fetchAlias(peer)
	peers.RUnlock()
	if found {
		return res
	}
	peers.Lock()
	defer peers.Unlock()
	res, found = peers.fetchAlias(peer)
	if found {
		return res
	}
	peers.table[peer.Name] = peer
	peer.IncrementLocalRefCount()
	return peer
}

func (peers *Peers) Fetch(name PeerName) (*Peer, bool) {
	peers.RLock()
	defer peers.RUnlock()
	peer, found := peers.table[name]
	return peer, found // GRRR, why can't I inline this!?
}

func (peers *Peers) ForEach(fun func(PeerName, *Peer)) {
	peers.RLock()
	defer peers.RUnlock()
	for name, peer := range peers.table {
		fun(name, peer)
	}
}

// Merge an incoming update with our own topology.
//
// We add peers hitherto unknown to us, and update peers for which the
// update contains a more recent version than known to us. The return
// value is an "improved" update containing just these new/updated
// elements.
func (peers *Peers) ApplyUpdate(update []byte) ([]byte, error) {
	peers.Lock()

	newPeers, decodedUpdate, decodedConns, err := peers.decodeUpdate(update)
	if err != nil {
		peers.Unlock()
		return nil, err
	}

	// By this point, we know the update doesn't refer to any peers we
	// have no knowledge of. We can now apply the update. Start by
	// adding in any new peers into the cache.
	for name, newPeer := range newPeers {
		peers.table[name] = newPeer
	}

	// Now apply the updates
	newUpdate := peers.applyUpdate(decodedUpdate, decodedConns)

	for _, peerRemoved := range peers.garbageCollect() {
		delete(newUpdate, peerRemoved.Name)
	}

	// Don't need to hold peers lock any longer
	peers.Unlock()

	return encodePeersMap(newUpdate), nil
}

func (peers *Peers) EncodeAllPeers() []byte {
	peers.RLock()
	defer peers.RUnlock()
	return encodePeersMap(peers.table)
}

func EncodePeers(peers ...*Peer) []byte {
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	for _, peer := range peers {
		peer.encodePeer(enc)
	}
	return buf.Bytes()
}

func (peers *Peers) GarbageCollect() []*Peer {
	peers.Lock()
	defer peers.Unlock()
	return peers.garbageCollect()
}

func (peers *Peers) String() string {
	var buf bytes.Buffer
	peers.ForEach(func(name PeerName, peer *Peer) {
		buf.WriteString(fmt.Sprint(peer, "\n"))
		peer.ForEachConnection(func(remoteName PeerName, conn Connection) {
			established := ""
			if !conn.Established() {
				established = " (unestablished)"
			}
			buf.WriteString(fmt.Sprintf("   -> %v [%v%s]\n", remoteName, conn.RemoteTCPAddr(), established))
		})
	})
	return buf.String()
}

func (peers *Peers) fetchAlias(peer *Peer) (*Peer, bool) {
	if existingPeer, found := peers.table[peer.Name]; found {
		if existingPeer.UID == peer.UID {
			existingPeer.IncrementLocalRefCount()
			return existingPeer, true
		} else {
			return nil, true
		}
	}
	return nil, false
}

func (peers *Peers) garbageCollect() []*Peer {
	removed := []*Peer{}
	for name, peer := range peers.table {
		found, _ := peers.ourself.Routes(peer, false)
		if !found && !peer.IsLocallyReferenced() {
			delete(peers.table, name)
			peers.onGC(peer)
			removed = append(removed, peer)
		}
	}
	return removed
}

func encodePeersMap(peers map[PeerName]*Peer) []byte {
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	for _, peer := range peers {
		peer.encodePeer(enc)
	}
	return buf.Bytes()
}

func (peers *Peers) decodeUpdate(update []byte) (newPeers map[PeerName]*Peer, decodedUpdate []*Peer, decodedConns [][]byte, err error) {
	newPeers = make(map[PeerName]*Peer)
	decodedUpdate = []*Peer{}
	decodedConns = [][]byte{}

	updateBuf := new(bytes.Buffer)
	updateBuf.Write(update)
	decoder := gob.NewDecoder(updateBuf)

	for {
		nameByte, uid, version, connsBuf, decErr := decodePeerNoConns(decoder)
		if decErr == io.EOF {
			break
		} else if decErr != nil {
			err = decErr
			return
		}
		name := PeerNameFromBin(nameByte)
		newPeer := NewPeer(name, uid, version)
		decodedUpdate = append(decodedUpdate, newPeer)
		decodedConns = append(decodedConns, connsBuf)
		existingPeer, found := peers.table[name]
		if !found {
			newPeers[name] = newPeer
		} else if existingPeer.UID != newPeer.UID {
			err = NameCollisionError{Name: newPeer.Name}
			return
		}
	}

	unknownPeers := false
	for _, connsBuf := range decodedConns {
		decErr := connsIterator(connsBuf, func(remoteNameByte []byte, _ string) {
			remoteName := PeerNameFromBin(remoteNameByte)
			if _, found := newPeers[remoteName]; found {
				return
			}
			if _, found := peers.table[remoteName]; found {
				return
			}
			// Update refers to a peer which we have no knowledge
			// of. Thus we can't apply the update. Abort.
			unknownPeers = true
		})
		if decErr == io.EOF {
			continue
		} else if decErr != nil {
			err = decErr
			return
		}
	}
	if unknownPeers {
		err = UnknownPeersError{}
		return
	}
	return
}

func (peers *Peers) applyUpdate(decodedUpdate []*Peer, decodedConns [][]byte) map[PeerName]*Peer {
	newUpdate := make(map[PeerName]*Peer)
	for idx, newPeer := range decodedUpdate {
		connsBuf := decodedConns[idx]
		name := newPeer.Name
		// guaranteed to find peer in the peers.table
		peer := peers.table[name]
		if peer != newPeer &&
			(peer == peers.ourself || peer.Version() >= newPeer.Version()) {
			// Nobody but us updates us. And if we know more about a
			// peer than what's in the the update, we ignore the
			// latter.
			continue
		}
		// If we're here, either it was a new peer, or the update has
		// more info about the peer than we do. Either case, we need
		// to set version and conns and include the updated peer in
		// the outgoing update.

		// Can peer have been updated by anyone else in the mean time?
		// No - we know that peer is not ourself, so the only prospect
		// for an update would be someone else calling
		// router.Peers.ApplyUpdate. But ApplyUpdate takes the Lock on
		// the router.Peers, so there can be no race here.
		conns := readConnsMap(peer, connsBuf, peers.table)
		peer.SetVersionAndConnections(newPeer.Version(), conns)
		newUpdate[name] = peer
	}
	return newUpdate
}

func (peer *Peer) encodePeer(enc *gob.Encoder) {
	peer.RLock()
	defer peer.RUnlock()

	checkFatal(enc.Encode(peer.NameByte))
	checkFatal(enc.Encode(peer.UID))
	checkFatal(enc.Encode(peer.version))

	connsBuf := new(bytes.Buffer)
	connsEnc := gob.NewEncoder(connsBuf)
	for _, conn := range peer.connections {
		// DANGER holding rlock on peer, going to take rlock on conn
		if !conn.Established() {
			continue
		}
		checkFatal(connsEnc.Encode(conn.Remote().NameByte))
		checkFatal(connsEnc.Encode(conn.RemoteTCPAddr()))
	}
	checkFatal(enc.Encode(connsBuf.Bytes()))
}

func decodePeerNoConns(dec *gob.Decoder) (nameByte []byte, uid uint64, version uint64, conns []byte, err error) {
	if err = dec.Decode(&nameByte); err != nil {
		return
	}
	if err = dec.Decode(&uid); err != nil {
		return
	}
	if err = dec.Decode(&version); err != nil {
		return
	}
	if err = dec.Decode(&conns); err != nil {
		return
	}
	return
}

func connsIterator(input []byte, fun func([]byte, string)) error {
	buf := new(bytes.Buffer)
	buf.Write(input)
	dec := gob.NewDecoder(buf)
	for {
		var nameByte []byte
		if err := dec.Decode(&nameByte); err != nil {
			return err
		}
		var foundAt string
		if err := dec.Decode(&foundAt); err != nil {
			return err
		}
		fun(nameByte, string(foundAt))
	}
}

func readConnsMap(peer *Peer, buf []byte, table map[PeerName]*Peer) map[PeerName]Connection {
	conns := make(map[PeerName]Connection)
	if err := connsIterator(buf, func(nameByte []byte, remoteTCPAddr string) {
		name := PeerNameFromBin(nameByte)
		remotePeer := table[name]
		conn := NewRemoteConnection(peer, remotePeer, remoteTCPAddr)
		conns[name] = conn
	}); err != io.EOF {
		// this should never happen since we've already successfully
		// decoded the same data in decodeUpdate
		checkFatal(err)
	}
	return conns
}
<commit_msg>improve peer gc efficiency Instead of separately calculating routes to every individual peer, carry out one calculation for routes to all peers. Same as unicast routes except taking into account asymmetric connections.<commit_after>package router

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"io"
	"sync"
)

type Peers struct {
	sync.RWMutex
	ourself *Peer
	table   map[PeerName]*Peer
	onGC    func(*Peer)
}

type UnknownPeersError struct {
}

type NameCollisionError struct {
	Name PeerName
}

func NewPeers(ourself *Peer, onGC func(*Peer)) *Peers {
	return &Peers{
		ourself: ourself,
		table:   make(map[PeerName]*Peer),
		onGC:    onGC}
}

func (peers *Peers) FetchWithDefault(peer *Peer) *Peer {
	peers.RLock()
	res, found := peers.fetchAlias(peer)
	peers.RUnlock()
	if found {
		return res
	}
	peers.Lock()
	defer peers.Unlock()
	res, found = peers.fetchAlias(peer)
	if found {
		return res
	}
	peers.table[peer.Name] = peer
	peer.IncrementLocalRefCount()
	return peer
}

func (peers *Peers) Fetch(name PeerName) (*Peer, bool) {
	peers.RLock()
	defer peers.RUnlock()
	peer, found := peers.table[name]
	return peer, found // GRRR, why can't I inline this!?
}

func (peers *Peers) ForEach(fun func(PeerName, *Peer)) {
	peers.RLock()
	defer peers.RUnlock()
	for name, peer := range peers.table {
		fun(name, peer)
	}
}

// Merge an incoming update with our own topology.
//
// We add peers hitherto unknown to us, and update peers for which the
// update contains a more recent version than known to us. The return
// value is an "improved" update containing just these new/updated
// elements.
func (peers *Peers) ApplyUpdate(update []byte) ([]byte, error) {
	peers.Lock()

	newPeers, decodedUpdate, decodedConns, err := peers.decodeUpdate(update)
	if err != nil {
		peers.Unlock()
		return nil, err
	}

	// By this point, we know the update doesn't refer to any peers we
	// have no knowledge of. We can now apply the update. Start by
	// adding in any new peers into the cache.
	for name, newPeer := range newPeers {
		peers.table[name] = newPeer
	}

	// Now apply the updates
	newUpdate := peers.applyUpdate(decodedUpdate, decodedConns)

	for _, peerRemoved := range peers.garbageCollect() {
		delete(newUpdate, peerRemoved.Name)
	}

	// Don't need to hold peers lock any longer
	peers.Unlock()

	return encodePeersMap(newUpdate), nil
}

func (peers *Peers) EncodeAllPeers() []byte {
	peers.RLock()
	defer peers.RUnlock()
	return encodePeersMap(peers.table)
}

func EncodePeers(peers ...*Peer) []byte {
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	for _, peer := range peers {
		peer.encodePeer(enc)
	}
	return buf.Bytes()
}

func (peers *Peers) GarbageCollect() []*Peer {
	peers.Lock()
	defer peers.Unlock()
	return peers.garbageCollect()
}

func (peers *Peers) String() string {
	var buf bytes.Buffer
	peers.ForEach(func(name PeerName, peer *Peer) {
		buf.WriteString(fmt.Sprint(peer, "\n"))
		peer.ForEachConnection(func(remoteName PeerName, conn Connection) {
			established := ""
			if !conn.Established() {
				established = " (unestablished)"
			}
			buf.WriteString(fmt.Sprintf("   -> %v [%v%s]\n", remoteName, conn.RemoteTCPAddr(), established))
		})
	})
	return buf.String()
}

func (peers *Peers) fetchAlias(peer *Peer) (*Peer, bool) {
	if existingPeer, found := peers.table[peer.Name]; found {
		if existingPeer.UID == peer.UID {
			existingPeer.IncrementLocalRefCount()
			return existingPeer, true
		} else {
			return nil, true
		}
	}
	return nil, false
}

func (peers *Peers) garbageCollect() []*Peer {
	removed := []*Peer{}
	_, reachable := peers.ourself.Routes(nil, false)
	for name, peer := range peers.table {
		if _, found := reachable[peer.Name]; !found && !peer.IsLocallyReferenced() {
			delete(peers.table, name)
			peers.onGC(peer)
			removed = append(removed, peer)
		}
	}
	return removed
}

func encodePeersMap(peers map[PeerName]*Peer) []byte {
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	for _, peer := range peers {
		peer.encodePeer(enc)
	}
	return buf.Bytes()
}

func (peers *Peers) decodeUpdate(update []byte) (newPeers map[PeerName]*Peer, decodedUpdate []*Peer, decodedConns [][]byte, err error) {
	newPeers = make(map[PeerName]*Peer)
	decodedUpdate = []*Peer{}
	decodedConns = [][]byte{}

	updateBuf := new(bytes.Buffer)
	updateBuf.Write(update)
	decoder := gob.NewDecoder(updateBuf)

	for {
		nameByte, uid, version, connsBuf, decErr := decodePeerNoConns(decoder)
		if decErr == io.EOF {
			break
		} else if decErr != nil {
			err = decErr
			return
		}
		name := PeerNameFromBin(nameByte)
		newPeer := NewPeer(name, uid, version)
		decodedUpdate = append(decodedUpdate, newPeer)
		decodedConns = append(decodedConns, connsBuf)
		existingPeer, found := peers.table[name]
		if !found {
			newPeers[name] = newPeer
		} else if existingPeer.UID != newPeer.UID {
			err = NameCollisionError{Name: newPeer.Name}
			return
		}
	}

	unknownPeers := false
	for _, connsBuf := range decodedConns {
		decErr := connsIterator(connsBuf, func(remoteNameByte []byte, _ string) {
			remoteName := PeerNameFromBin(remoteNameByte)
			if _, found := newPeers[remoteName]; found {
				return
			}
			if _, found := peers.table[remoteName]; found {
				return
			}
			// Update refers to a peer which we have no knowledge
			// of. Thus we can't apply the update. Abort.
			unknownPeers = true
		})
		if decErr == io.EOF {
			continue
		} else if decErr != nil {
			err = decErr
			return
		}
	}
	if unknownPeers {
		err = UnknownPeersError{}
		return
	}
	return
}

func (peers *Peers) applyUpdate(decodedUpdate []*Peer, decodedConns [][]byte) map[PeerName]*Peer {
	newUpdate := make(map[PeerName]*Peer)
	for idx, newPeer := range decodedUpdate {
		connsBuf := decodedConns[idx]
		name := newPeer.Name
		// guaranteed to find peer in the peers.table
		peer := peers.table[name]
		if peer != newPeer &&
			(peer == peers.ourself || peer.Version() >= newPeer.Version()) {
			// Nobody but us updates us. And if we know more about a
			// peer than what's in the the update, we ignore the
			// latter.
			continue
		}
		// If we're here, either it was a new peer, or the update has
		// more info about the peer than we do. Either case, we need
		// to set version and conns and include the updated peer in
		// the outgoing update.

		// Can peer have been updated by anyone else in the mean time?
		// No - we know that peer is not ourself, so the only prospect
		// for an update would be someone else calling
		// router.Peers.ApplyUpdate. But ApplyUpdate takes the Lock on
		// the router.Peers, so there can be no race here.
		conns := readConnsMap(peer, connsBuf, peers.table)
		peer.SetVersionAndConnections(newPeer.Version(), conns)
		newUpdate[name] = peer
	}
	return newUpdate
}

func (peer *Peer) encodePeer(enc *gob.Encoder) {
	peer.RLock()
	defer peer.RUnlock()

	checkFatal(enc.Encode(peer.NameByte))
	checkFatal(enc.Encode(peer.UID))
	checkFatal(enc.Encode(peer.version))

	connsBuf := new(bytes.Buffer)
	connsEnc := gob.NewEncoder(connsBuf)
	for _, conn := range peer.connections {
		// DANGER holding rlock on peer, going to take rlock on conn
		if !conn.Established() {
			continue
		}
		checkFatal(connsEnc.Encode(conn.Remote().NameByte))
		checkFatal(connsEnc.Encode(conn.RemoteTCPAddr()))
	}
	checkFatal(enc.Encode(connsBuf.Bytes()))
}

func decodePeerNoConns(dec *gob.Decoder) (nameByte []byte, uid uint64, version uint64, conns []byte, err error) {
	if err = dec.Decode(&nameByte); err != nil {
		return
	}
	if err = dec.Decode(&uid); err != nil {
		return
	}
	if err = dec.Decode(&version); err != nil {
		return
	}
	if err = dec.Decode(&conns); err != nil {
		return
	}
	return
}

func connsIterator(input []byte, fun func([]byte, string)) error {
	buf := new(bytes.Buffer)
	buf.Write(input)
	dec := gob.NewDecoder(buf)
	for {
		var nameByte []byte
		if err := dec.Decode(&nameByte); err != nil {
			return err
		}
		var foundAt string
		if err := dec.Decode(&foundAt); err != nil {
			return err
		}
		fun(nameByte, string(foundAt))
	}
}

func readConnsMap(peer *Peer, buf []byte, table map[PeerName]*Peer) map[PeerName]Connection {
	conns := make(map[PeerName]Connection)
	if err := connsIterator(buf, func(nameByte []byte, remoteTCPAddr string) {
		name := PeerNameFromBin(nameByte)
		remotePeer := table[name]
		conn := NewRemoteConnection(peer, remotePeer, remoteTCPAddr)
		conns[name] = conn
	}); err != io.EOF {
		// this should never happen since we've already successfully
		// decoded the same data in decodeUpdate
		checkFatal(err)
	}
	return conns
}
<|endoftext|>


<commit_before>package fit

import (
	"bytes"
	"testing"
)

// Previous go-fuzz crasher inputs. Verify that they stay fixed by
// decoding them.
var goFuzzCrasherInputs = [...]string{
	// GpsMetaData is a known message number but there was no GpsMetaData
	// message definition.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"0\x04\x8c0\x04\x860\x02\x840\x02\x840\x02\x84\x00\x01\x0000" +
		"0000000000000\x04A0\x00\xa0\x00\x02" +
		"0\x02\x840\x02\x84\x01",

	// Field definition had different base type from the one listed in the
	// profile.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"0\x04\x8c0\x04\x860\x02\x840\x02\x840\x02\x84\x00\x01\x0000" +
		"0000000000000\x04C0\x00\x14\x00\x12" +
		"0\x04\x86\r\x04\x880\x04\x850\x04\x860\x04\x860\x04\x860\x02" +
		"\x840\x02\x840\x02\x840\x02\x840\x02\x840\x02\x840\x01\x020" +
		"\x01\x020\x01\x020\x01\x010\x01\xea0\x01\x02\x0300000" +
		"000",

	// Did not check for unknown message number during definition message
	// validation. Caused index out of range on profile lookup.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"0\x04\x8c0\x04\x860\x02\x840\x02\x840\x02\x84\x00\x01\x0000" +
		"0000000000000\x01C0\x000\x00\x12" +
		"00\x8600\x8500\x8500\x8600\x8600\x00\xff0" +
		"\x040000000000000000000" +
		"00000000000000",

	// Lookup in profile table for fieldNumInvalid (255) caused index out of range.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@\x00\x00\x00\x00\x00" +
		"\x00@\x00\x00\x00\x00\x04\x8c\x04\x00\xff\x01\x02\x84\x02\x02\x84\x05\x02\x84" +
		"\x00\x01\f\x00\xcf\xd9b\xef\x99\x0f\xff438512483" +
		"556860\x00\x06\x03\x04\x01\x00",

	// Padding in parseDataFields was not reset on each iteration. No moved
	// inside loop and not possible.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"0\x04\x00\x01\x00\x000\x02\xa300@00\x8400\x0000" +
		"00000",

	// Field definition size was less than field definition base type size.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"0\x00\x00\x01\x02\x8900\x8400@00\x8400\x0000" +
		"00",

	// Field definition type was sint32 and profile was uint32. Only allow
	// compatible types that will not panic when setting using reflection.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"\x03\x04\x8500\x8600\x8400\x8400\x8400\x0000" +
		"000",

	// Field definition type in profile was string, but field definition
	// type was enum. Both are unsigned, but not compatible.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"0\x04\x8c0\x04\x860\x02\x840\x02\x840\x02\x84\b\x01\x0000" +
		"00000000000000",

	// Definition message field was string, but profile was not. Not
	// compatible types.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"0\x04\x8c0\x04\x860\x02\x840\x02\x840\x02\x84\x00\x01\x0000" +
		"0000000000000\x04A0\x001\x00\x02" +
		"\x00\x02\a00\x00\x010\x00",

	// Array profile field, but definition base type size was greater than
	// profile base type size.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"0\x04\x8c0\x04\x860\x02\x840\x02\x840\x02\x84\x00\x01\x0000" +
		"0000000000000\x04A0\x00\x01\x00\x02" +
		"\x00\x02\x8400\x02\x0100",

	// Require exact correct base type if profile array field.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"0\x04\x8c0\x04\x860\x02\x840\x02\x840\x02\x84\x00\x01\x0000" +
		"0000000000000\x04B0\x00\xb2\x00\a" +
		"0\x04\x860\x04\x8c0\x02\x840\x02\x840\x02\x840\x01\x02\x01\x01" +
		"\x02\x020000000000000000",

	// Allow only compatible types if definition base type size is less the
	// profile base type size.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"0\x04\x8c0\x04\x860\x02\x840\x02\x840\x02\x84\x00\x01\x0000" +
		"0000000000000\tA0\x003\x00\x02" +
		"0\x02\x84\x01\x01\x01\xb8000",

	// We should not do any padding when the profile field is an array.
	"\f\x10000000.FIT@0\x01\x00\x00\x050\x04" +
		"\x8c0\x04\x860\x02\x840\x02\x84\x00\x01\x000000000" +
		"000000\x02@0\x01\x00\x13\x14\xfd\x04\x86;\f\x86\x03" +
		"\x04\x85\x04\x04\x85\x05\x04\x85\x06\x04\x85\a\x03\x04\x850\x04\x850\x04" +
		"\x860\x04\x860\x04\x860\x02\x840\x02\x840\x02\x840\x02\x840" +
		"\x02\x840\x02\x840\x02\x840\x02\x840\x020000000" +
		"0000000000",

	// Indexing into scratch buffer not handled correctly for some array fields.
	"\f\x10000000.FIT@0\x01\x00\x00\x050\x04" +
		"\x8c0\x04\x860\x02\x840\x02\x840\x01\x00\x00\x86\x03\x04\x86\x00\x01" +
		"\x00\x01\x01\x00\x04\x01\x02C\x00\x01\x00\x13\x14\xfd\x04\x86\x02\x04\x86\x03" +
		"\x04\x85\x04\x04\x85\x05\x04\x85\x06\x04\x85\a\x04\x86\b\x04\x86\t\x04\x86" +
		"\xfe\x02\x84K\x04\x84L\x02\x84\r\x02\x84\x0e\x02\x84\x15\x02\x84\x16\x02" +
		"\x84\x00\x01\x00\x01\x01\x00\x18\x01\x00\x19\x01\x00\x03)\xe6\a\xa3)\xe6" +
		"\a\x12\x1d\x85a.\xcb\xfb\xb4\x97\x1d\x85a\x00\x00\x12\xcb\xfb\xb2W" +
		"\x00\x005\xb5\x00\x005\xb5\x00\x00\x02=\x00\x00\x00\x00",

	// Appending to a slice using reflection was not done correctly for some
	// fields. Led to refactor of array handling in general.
	"\f\x10000000.FIT@0\x01\x00\x00\x050\x04" +
		"\x8c0\x04\x860\x02\x840\x02\x84\x00\x01\x000000000" +
		"000000\n@0\x01\x00\xb2\x01\n\x02\x84000",

	// Floats and and signed integers of equal size is not compatible base
	// types. Reflection panic.
	"\f\x10000000.FIT@0\x01\x00\x00\x050\x04" +
		"\x8c0\x04\x860\x02\x840\x02\x84\x00\x01\x000000000" +
		"000000\x02B0\x01\x00\x14\x06\xfd\x04\x86\v\x04\x88\x01" +
		"\x04\x85\x05\x04\x86\x02\x02\x84\x06\x02\x84\xcb00000000",
}

func TestFuzzCrasherInputs(t *testing.T) {
	for i, input := range goFuzzCrasherInputs {
		t.Logf("Crasher input: %d", i)
		Decode(bytes.NewReader([]byte(input)))
	}
}
<commit_msg>fuzz: explictly ignore return value and error (errcheck)<commit_after>package fit

import (
	"bytes"
	"testing"
)

// Previous go-fuzz crasher inputs. Verify that they stay fixed by
// decoding them.
var goFuzzCrasherInputs = [...]string{
	// GpsMetaData is a known message number but there was no GpsMetaData
	// message definition.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"0\x04\x8c0\x04\x860\x02\x840\x02\x840\x02\x84\x00\x01\x0000" +
		"0000000000000\x04A0\x00\xa0\x00\x02" +
		"0\x02\x840\x02\x84\x01",

	// Field definition had different base type from the one listed in the
	// profile.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"0\x04\x8c0\x04\x860\x02\x840\x02\x840\x02\x84\x00\x01\x0000" +
		"0000000000000\x04C0\x00\x14\x00\x12" +
		"0\x04\x86\r\x04\x880\x04\x850\x04\x860\x04\x860\x04\x860\x02" +
		"\x840\x02\x840\x02\x840\x02\x840\x02\x840\x02\x840\x01\x020" +
		"\x01\x020\x01\x020\x01\x010\x01\xea0\x01\x02\x0300000" +
		"000",

	// Did not check for unknown message number during definition message
	// validation. Caused index out of range on profile lookup.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"0\x04\x8c0\x04\x860\x02\x840\x02\x840\x02\x84\x00\x01\x0000" +
		"0000000000000\x01C0\x000\x00\x12" +
		"00\x8600\x8500\x8500\x8600\x8600\x00\xff0" +
		"\x040000000000000000000" +
		"00000000000000",

	// Lookup in profile table for fieldNumInvalid (255) caused index out of range.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@\x00\x00\x00\x00\x00" +
		"\x00@\x00\x00\x00\x00\x04\x8c\x04\x00\xff\x01\x02\x84\x02\x02\x84\x05\x02\x84" +
		"\x00\x01\f\x00\xcf\xd9b\xef\x99\x0f\xff438512483" +
		"556860\x00\x06\x03\x04\x01\x00",

	// Padding in parseDataFields was not reset on each iteration. No moved
	// inside loop and not possible.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"0\x04\x00\x01\x00\x000\x02\xa300@00\x8400\x0000" +
		"00000",

	// Field definition size was less than field definition base type size.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"0\x00\x00\x01\x02\x8900\x8400@00\x8400\x0000" +
		"00",

	// Field definition type was sint32 and profile was uint32. Only allow
	// compatible types that will not panic when setting using reflection.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"\x03\x04\x8500\x8600\x8400\x8400\x8400\x0000" +
		"000",

	// Field definition type in profile was string, but field definition
	// type was enum. Both are unsigned, but not compatible.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"0\x04\x8c0\x04\x860\x02\x840\x02\x840\x02\x84\b\x01\x0000" +
		"00000000000000",

	// Definition message field was string, but profile was not. Not
	// compatible types.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"0\x04\x8c0\x04\x860\x02\x840\x02\x840\x02\x84\x00\x01\x0000" +
		"0000000000000\x04A0\x001\x00\x02" +
		"\x00\x02\a00\x00\x010\x00",

	// Array profile field, but definition base type size was greater than
	// profile base type size.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"0\x04\x8c0\x04\x860\x02\x840\x02\x840\x02\x84\x00\x01\x0000" +
		"0000000000000\x04A0\x00\x01\x00\x02" +
		"\x00\x02\x8400\x02\x0100",

	// Require exact correct base type if profile array field.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"0\x04\x8c0\x04\x860\x02\x840\x02\x840\x02\x84\x00\x01\x0000" +
		"0000000000000\x04B0\x00\xb2\x00\a" +
		"0\x04\x860\x04\x8c0\x02\x840\x02\x840\x02\x840\x01\x02\x01\x01" +
		"\x02\x020000000000000000",

	// Allow only compatible types if definition base type size is less the
	// profile base type size.
	"\x0e\x10W\x04\xdf\xdb\x01\x00.FIT\xc4\x1e@0\x00\x00\x00\x06" +
		"0\x04\x8c0\x04\x860\x02\x840\x02\x840\x02\x84\x00\x01\x0000" +
		"0000000000000\tA0\x003\x00\x02" +
		"0\x02\x84\x01\x01\x01\xb8000",

	// We should not do any padding when the profile field is an array.
	"\f\x10000000.FIT@0\x01\x00\x00\x050\x04" +
		"\x8c0\x04\x860\x02\x840\x02\x84\x00\x01\x000000000" +
		"000000\x02@0\x01\x00\x13\x14\xfd\x04\x86;\f\x86\x03" +
		"\x04\x85\x04\x04\x85\x05\x04\x85\x06\x04\x85\a\x03\x04\x850\x04\x850\x04" +
		"\x860\x04\x860\x04\x860\x02\x840\x02\x840\x02\x840\x02\x840" +
		"\x02\x840\x02\x840\x02\x840\x02\x840\x020000000" +
		"0000000000",

	// Indexing into scratch buffer not handled correctly for some array fields.
	"\f\x10000000.FIT@0\x01\x00\x00\x050\x04" +
		"\x8c0\x04\x860\x02\x840\x02\x840\x01\x00\x00\x86\x03\x04\x86\x00\x01" +
		"\x00\x01\x01\x00\x04\x01\x02C\x00\x01\x00\x13\x14\xfd\x04\x86\x02\x04\x86\x03" +
		"\x04\x85\x04\x04\x85\x05\x04\x85\x06\x04\x85\a\x04\x86\b\x04\x86\t\x04\x86" +
		"\xfe\x02\x84K\x04\x84L\x02\x84\r\x02\x84\x0e\x02\x84\x15\x02\x84\x16\x02" +
		"\x84\x00\x01\x00\x01\x01\x00\x18\x01\x00\x19\x01\x00\x03)\xe6\a\xa3)\xe6" +
		"\a\x12\x1d\x85a.\xcb\xfb\xb4\x97\x1d\x85a\x00\x00\x12\xcb\xfb\xb2W" +
		"\x00\x005\xb5\x00\x005\xb5\x00\x00\x02=\x00\x00\x00\x00",

	// Appending to a slice using reflection was not done correctly for some
	// fields. Led to refactor of array handling in general.
	"\f\x10000000.FIT@0\x01\x00\x00\x050\x04" +
		"\x8c0\x04\x860\x02\x840\x02\x84\x00\x01\x000000000" +
		"000000\n@0\x01\x00\xb2\x01\n\x02\x84000",

	// Floats and and signed integers of equal size is not compatible base
	// types. Reflection panic.
	"\f\x10000000.FIT@0\x01\x00\x00\x050\x04" +
		"\x8c0\x04\x860\x02\x840\x02\x84\x00\x01\x000000000" +
		"000000\x02B0\x01\x00\x14\x06\xfd\x04\x86\v\x04\x88\x01" +
		"\x04\x85\x05\x04\x86\x02\x02\x84\x06\x02\x84\xcb00000000",
}

func TestFuzzCrasherInputs(t *testing.T) {
	for i, input := range goFuzzCrasherInputs {
		t.Logf("Crasher input: %d", i)
		_, _ = Decode(bytes.NewReader([]byte(input)))
	}
}
<|endoftext|>


<commit_before>package js

import (
	"github.com/loadimpact/speedboat/runner"
	"github.com/robertkrimen/otto"
	"net/http"
	"time"
)

type JSRunner struct {
	BaseVM *otto.Otto
	Script *otto.Script

	httpClient *http.Client
}

func New() (r *JSRunner, err error) {
	r = &JSRunner{}

	// Create a base VM
	r.BaseVM = otto.New()

	// Bridge basic functions
	r.BaseVM.Set("sleep", jsSleepFactory(time.Sleep))

	// Use a single HTTP client for this
	r.httpClient = &http.Client{
		Transport: &http.Transport{
			DisableKeepAlives: true,
		},
	}
	r.BaseVM.Set("get", jsHTTPGetFactory(func(url string) (*http.Response, error) {
		return r.httpClient.Get(url)
	}))

	return r, nil
}

func (r *JSRunner) Load(filename, src string) (err error) {
	r.Script, err = r.BaseVM.Compile(filename, src)
	return err
}

func (r *JSRunner) RunVU(stop <-chan interface{}) <-chan interface{} {
	out := make(chan interface{})

	go func() {
		defer close(out)

	runLoop:
		for {
			select {
			case <-stop:
				break runLoop
			default:
				vm := r.BaseVM.Copy()
				for res := range r.RunIteration(vm) {
					out <- res
				}
			}
		}
	}()

	return out
}

func (r *JSRunner) RunIteration(vm *otto.Otto) <-chan interface{} {
	out := make(chan interface{})

	go func() {
		defer close(out)

		// Log has to be bridged here, as it needs a reference to the channel
		vm.Set("log", jsLogFactory(func(text string) {
			out <- runner.NewLogEntry(text)
		}))

		startTime := time.Now()
		_, err := vm.Run(r.Script)
		duration := time.Since(startTime)

		if err != nil {
			out <- runner.NewError(err)
		}

		out <- runner.NewMetric(startTime, duration)
	}()

	return out
}
<commit_msg>Reinstating the VU panic handler<commit_after>package js

import (
	"github.com/loadimpact/speedboat/runner"
	"github.com/robertkrimen/otto"
	"net/http"
	"time"
)

type JSRunner struct {
	BaseVM *otto.Otto
	Script *otto.Script

	httpClient *http.Client
}

func New() (r *JSRunner, err error) {
	r = &JSRunner{}

	// Create a base VM
	r.BaseVM = otto.New()

	// Bridge basic functions
	r.BaseVM.Set("sleep", jsSleepFactory(time.Sleep))

	// Use a single HTTP client for this
	r.httpClient = &http.Client{
		Transport: &http.Transport{
			DisableKeepAlives: true,
		},
	}
	r.BaseVM.Set("get", jsHTTPGetFactory(func(url string) (*http.Response, error) {
		return r.httpClient.Get(url)
	}))

	return r, nil
}

func (r *JSRunner) Load(filename, src string) (err error) {
	r.Script, err = r.BaseVM.Compile(filename, src)
	return err
}

func (r *JSRunner) RunVU(stop <-chan interface{}) <-chan interface{} {
	out := make(chan interface{})

	go func() {
		defer close(out)

	runLoop:
		for {
			select {
			case <-stop:
				break runLoop
			default:
				vm := r.BaseVM.Copy()
				for res := range r.RunIteration(vm) {
					out <- res
				}
			}
		}
	}()

	return out
}

func (r *JSRunner) RunIteration(vm *otto.Otto) <-chan interface{} {
	out := make(chan interface{})

	go func() {
		defer close(out)
		defer func() {
			if err := recover(); err != nil {
				out <- runner.NewError(err.(JSError))
			}
		}()

		// Log has to be bridged here, as it needs a reference to the channel
		vm.Set("log", jsLogFactory(func(text string) {
			out <- runner.NewLogEntry(text)
		}))

		startTime := time.Now()
		_, err := vm.Run(r.Script)
		duration := time.Since(startTime)

		if err != nil {
			out <- runner.NewError(err)
		}

		out <- runner.NewMetric(startTime, duration)
	}()

	return out
}
<|endoftext|>


<commit_before>package jsoniter

import (
	"fmt"
	"io"
)

// ValueType the type for JSON element
type ValueType int

const (
	// Invalid invalid JSON element
	Invalid ValueType = iota
	// String JSON element "string"
	String
	// Number JSON element 100 or 0.10
	Number
	// Nil JSON element null
	Nil
	// Bool JSON element true or false
	Bool
	// Array JSON element []
	Array
	// Object JSON element {}
	Object
)

var hexDigits []byte
var valueTypes []ValueType

func init() {
	hexDigits = make([]byte, 256)
	for i := 0; i < len(hexDigits); i++ {
		hexDigits[i] = 255
	}
	for i := '0'; i <= '9'; i++ {
		hexDigits[i] = byte(i - '0')
	}
	for i := 'a'; i <= 'f'; i++ {
		hexDigits[i] = byte((i - 'a') + 10)
	}
	for i := 'A'; i <= 'F'; i++ {
		hexDigits[i] = byte((i - 'A') + 10)
	}
	valueTypes = make([]ValueType, 256)
	for i := 0; i < len(valueTypes); i++ {
		valueTypes[i] = Invalid
	}
	valueTypes['"'] = String
	valueTypes['-'] = Number
	valueTypes['0'] = Number
	valueTypes['1'] = Number
	valueTypes['2'] = Number
	valueTypes['3'] = Number
	valueTypes['4'] = Number
	valueTypes['5'] = Number
	valueTypes['6'] = Number
	valueTypes['7'] = Number
	valueTypes['8'] = Number
	valueTypes['9'] = Number
	valueTypes['t'] = Bool
	valueTypes['f'] = Bool
	valueTypes['n'] = Nil
	valueTypes['['] = Array
	valueTypes['{'] = Object
}

// Iterator is a io.Reader like object, with JSON specific read functions.
// Error is not returned as return value, but stored as Error member on this iterator instance.
type Iterator struct {
	cfg              *frozenConfig
	reader           io.Reader
	buf              []byte
	head             int
	tail             int
	captureStartedAt int
	captured         []byte
	Error            error
}

// NewIterator creates an empty Iterator instance
func NewIterator(cfg API) *Iterator {
	return &Iterator{
		cfg:    cfg.(*frozenConfig),
		reader: nil,
		buf:    nil,
		head:   0,
		tail:   0,
	}
}

// Parse creates an Iterator instance from io.Reader
func Parse(cfg API, reader io.Reader, bufSize int) *Iterator {
	return &Iterator{
		cfg:    cfg.(*frozenConfig),
		reader: reader,
		buf:    make([]byte, bufSize),
		head:   0,
		tail:   0,
	}
}

// ParseBytes creates an Iterator instance from byte array
func ParseBytes(cfg API, input []byte) *Iterator {
	return &Iterator{
		cfg:    cfg.(*frozenConfig),
		reader: nil,
		buf:    input,
		head:   0,
		tail:   len(input),
	}
}

// ParseString creates an Iterator instance from string
func ParseString(cfg API, input string) *Iterator {
	return ParseBytes(cfg, []byte(input))
}

// Pool returns a pool can provide more iterator with same configuration
func (iter *Iterator) Pool() IteratorPool {
	return iter.cfg
}

// Reset reuse iterator instance by specifying another reader
func (iter *Iterator) Reset(reader io.Reader) *Iterator {
	iter.reader = reader
	iter.head = 0
	iter.tail = 0
	return iter
}

// ResetBytes reuse iterator instance by specifying another byte array as input
func (iter *Iterator) ResetBytes(input []byte) *Iterator {
	iter.reader = nil
	iter.buf = input
	iter.head = 0
	iter.tail = len(input)
	return iter
}

// WhatIsNext gets ValueType of relatively next json element
func (iter *Iterator) WhatIsNext() ValueType {
	valueType := valueTypes[iter.nextToken()]
	iter.unreadByte()
	return valueType
}

func (iter *Iterator) skipWhitespacesWithoutLoadMore() bool {
	for i := iter.head; i < iter.tail; i++ {
		c := iter.buf[i]
		switch c {
		case ' ', '\n', '\t', '\r':
			continue
		}
		iter.head = i
		return false
	}
	return true
}

func (iter *Iterator) isObjectEnd() bool {
	c := iter.nextToken()
	if c == ',' {
		return false
	}
	if c == '}' {
		return true
	}
	iter.ReportError("isObjectEnd", "object ended prematurely")
	return true
}

func (iter *Iterator) nextToken() byte {
	// a variation of skip whitespaces, returning the next non-whitespace token
	for {
		for i := iter.head; i < iter.tail; i++ {
			c := iter.buf[i]
			switch c {
			case ' ', '\n', '\t', '\r':
				continue
			}
			iter.head = i + 1
			return c
		}
		if !iter.loadMore() {
			return 0
		}
	}
}

// ReportError record a error in iterator instance with current position.
func (iter *Iterator) ReportError(operation string, msg string) {
	if iter.Error != nil {
		if iter.Error != io.EOF {
			return
		}
	}
	peekStart := iter.head - 10
	if peekStart < 0 {
		peekStart = 0
	}
	iter.Error = fmt.Errorf("%s: %s, parsing %v ...%s... at %s", operation, msg, iter.head,
		string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail]))
}

// CurrentBuffer gets current buffer as string for debugging purpose
func (iter *Iterator) CurrentBuffer() string {
	peekStart := iter.head - 10
	if peekStart < 0 {
		peekStart = 0
	}
	return fmt.Sprintf("parsing %v ...|%s|... at %s", iter.head,
		string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail]))
}

func (iter *Iterator) readByte() (ret byte) {
	if iter.head == iter.tail {
		if iter.loadMore() {
			ret = iter.buf[iter.head]
			iter.head++
			return ret
		}
		return 0
	}
	ret = iter.buf[iter.head]
	iter.head++
	return ret
}

func (iter *Iterator) loadMore() bool {
	if iter.reader == nil {
		if iter.Error == nil {
			iter.head = iter.tail
			iter.Error = io.EOF
		}
		return false
	}
	if iter.captureStartedAt != -1 {
		iter.captured = append(iter.captured,
			iter.buf[iter.captureStartedAt:iter.tail]...)
		iter.captureStartedAt = 0
	}
	for {
		n, err := iter.reader.Read(iter.buf)
		if n == 0 {
			if err != nil {
				if iter.Error == nil {
					iter.Error = err
				}
				return false
			}
		} else {
			iter.head = 0
			iter.tail = n
			return true
		}
	}
}

func (iter *Iterator) unreadByte() {
	if iter.head == 0 {
		iter.ReportError("unreadByte", "unread too many bytes")
		return
	}
	iter.head--
	return
}

// Read read the next JSON element as generic interface{}.
func (iter *Iterator) Read() interface{} {
	valueType := iter.WhatIsNext()
	switch valueType {
	case String:
		return iter.ReadString()
	case Number:
		return iter.ReadFloat64()
	case Nil:
		iter.skipFourBytes('n', 'u', 'l', 'l')
		return nil
	case Bool:
		return iter.ReadBool()
	case Array:
		arr := []interface{}{}
		iter.ReadArrayCB(func(iter *Iterator) bool {
			arr = append(arr, iter.Read())
			return true
		})
		return arr
	case Object:
		obj := map[string]interface{}{}
		iter.ReadObjectCB(func(Iter *Iterator, field string) bool {
			obj[field] = iter.Read()
			return true
		})
		return obj
	default:
		iter.ReportError("Read", fmt.Sprintf("unexpected value type: %v", valueType))
		return nil
	}
}
<commit_msg>Fix #123, make iterator read int if using number<commit_after>package jsoniter

import (
	"fmt"
	"io"
)

// ValueType the type for JSON element
type ValueType int

const (
	// Invalid invalid JSON element
	Invalid ValueType = iota
	// String JSON element "string"
	String
	// Number JSON element 100 or 0.10
	Number
	// Nil JSON element null
	Nil
	// Bool JSON element true or false
	Bool
	// Array JSON element []
	Array
	// Object JSON element {}
	Object
)

var hexDigits []byte
var valueTypes []ValueType

func init() {
	hexDigits = make([]byte, 256)
	for i := 0; i < len(hexDigits); i++ {
		hexDigits[i] = 255
	}
	for i := '0'; i <= '9'; i++ {
		hexDigits[i] = byte(i - '0')
	}
	for i := 'a'; i <= 'f'; i++ {
		hexDigits[i] = byte((i - 'a') + 10)
	}
	for i := 'A'; i <= 'F'; i++ {
		hexDigits[i] = byte((i - 'A') + 10)
	}
	valueTypes = make([]ValueType, 256)
	for i := 0; i < len(valueTypes); i++ {
		valueTypes[i] = Invalid
	}
	valueTypes['"'] = String
	valueTypes['-'] = Number
	valueTypes['0'] = Number
	valueTypes['1'] = Number
	valueTypes['2'] = Number
	valueTypes['3'] = Number
	valueTypes['4'] = Number
	valueTypes['5'] = Number
	valueTypes['6'] = Number
	valueTypes['7'] = Number
	valueTypes['8'] = Number
	valueTypes['9'] = Number
	valueTypes['t'] = Bool
	valueTypes['f'] = Bool
	valueTypes['n'] = Nil
	valueTypes['['] = Array
	valueTypes['{'] = Object
}

// Iterator is a io.Reader like object, with JSON specific read functions.
// Error is not returned as return value, but stored as Error member on this iterator instance.
type Iterator struct {
	cfg              *frozenConfig
	reader           io.Reader
	buf              []byte
	head             int
	tail             int
	captureStartedAt int
	captured         []byte
	Error            error
}

// NewIterator creates an empty Iterator instance
func NewIterator(cfg API) *Iterator {
	return &Iterator{
		cfg:    cfg.(*frozenConfig),
		reader: nil,
		buf:    nil,
		head:   0,
		tail:   0,
	}
}

// Parse creates an Iterator instance from io.Reader
func Parse(cfg API, reader io.Reader, bufSize int) *Iterator {
	return &Iterator{
		cfg:    cfg.(*frozenConfig),
		reader: reader,
		buf:    make([]byte, bufSize),
		head:   0,
		tail:   0,
	}
}

// ParseBytes creates an Iterator instance from byte array
func ParseBytes(cfg API, input []byte) *Iterator {
	return &Iterator{
		cfg:    cfg.(*frozenConfig),
		reader: nil,
		buf:    input,
		head:   0,
		tail:   len(input),
	}
}

// ParseString creates an Iterator instance from string
func ParseString(cfg API, input string) *Iterator {
	return ParseBytes(cfg, []byte(input))
}

// Pool returns a pool can provide more iterator with same configuration
func (iter *Iterator) Pool() IteratorPool {
	return iter.cfg
}

// Reset reuse iterator instance by specifying another reader
func (iter *Iterator) Reset(reader io.Reader) *Iterator {
	iter.reader = reader
	iter.head = 0
	iter.tail = 0
	return iter
}

// ResetBytes reuse iterator instance by specifying another byte array as input
func (iter *Iterator) ResetBytes(input []byte) *Iterator {
	iter.reader = nil
	iter.buf = input
	iter.head = 0
	iter.tail = len(input)
	return iter
}

// WhatIsNext gets ValueType of relatively next json element
func (iter *Iterator) WhatIsNext() ValueType {
	valueType := valueTypes[iter.nextToken()]
	iter.unreadByte()
	return valueType
}

func (iter *Iterator) skipWhitespacesWithoutLoadMore() bool {
	for i := iter.head; i < iter.tail; i++ {
		c := iter.buf[i]
		switch c {
		case ' ', '\n', '\t', '\r':
			continue
		}
		iter.head = i
		return false
	}
	return true
}

func (iter *Iterator) isObjectEnd() bool {
	c := iter.nextToken()
	if c == ',' {
		return false
	}
	if c == '}' {
		return true
	}
	iter.ReportError("isObjectEnd", "object ended prematurely")
	return true
}

func (iter *Iterator) nextToken() byte {
	// a variation of skip whitespaces, returning the next non-whitespace token
	for {
		for i := iter.head; i < iter.tail; i++ {
			c := iter.buf[i]
			switch c {
			case ' ', '\n', '\t', '\r':
				continue
			}
			iter.head = i + 1
			return c
		}
		if !iter.loadMore() {
			return 0
		}
	}
}

// ReportError record a error in iterator instance with current position.
func (iter *Iterator) ReportError(operation string, msg string) {
	if iter.Error != nil {
		if iter.Error != io.EOF {
			return
		}
	}
	peekStart := iter.head - 10
	if peekStart < 0 {
		peekStart = 0
	}
	iter.Error = fmt.Errorf("%s: %s, parsing %v ...%s... at %s", operation, msg, iter.head,
		string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail]))
}

// CurrentBuffer gets current buffer as string for debugging purpose
func (iter *Iterator) CurrentBuffer() string {
	peekStart := iter.head - 10
	if peekStart < 0 {
		peekStart = 0
	}
	return fmt.Sprintf("parsing %v ...|%s|... at %s", iter.head,
		string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail]))
}

func (iter *Iterator) readByte() (ret byte) {
	if iter.head == iter.tail {
		if iter.loadMore() {
			ret = iter.buf[iter.head]
			iter.head++
			return ret
		}
		return 0
	}
	ret = iter.buf[iter.head]
	iter.head++
	return ret
}

func (iter *Iterator) loadMore() bool {
	if iter.reader == nil {
		if iter.Error == nil {
			iter.head = iter.tail
			iter.Error = io.EOF
		}
		return false
	}
	if iter.captureStartedAt != -1 {
		iter.captured = append(iter.captured,
			iter.buf[iter.captureStartedAt:iter.tail]...)
		iter.captureStartedAt = 0
	}
	for {
		n, err := iter.reader.Read(iter.buf)
		if n == 0 {
			if err != nil {
				if iter.Error == nil {
					iter.Error = err
				}
				return false
			}
		} else {
			iter.head = 0
			iter.tail = n
			return true
		}
	}
}

func (iter *Iterator) unreadByte() {
	if iter.head == 0 {
		iter.ReportError("unreadByte", "unread too many bytes")
		return
	}
	iter.head--
	return
}

// Read read the next JSON element as generic interface{}.
func (iter *Iterator) Read() interface{} {
	valueType := iter.WhatIsNext()
	switch valueType {
	case String:
		return iter.ReadString()
	case Number:
		if iter.cfg.configBeforeFrozen.UseNumber {
			return iter.ReadInt()
		}
		return iter.ReadFloat64()
	case Nil:
		iter.skipFourBytes('n', 'u', 'l', 'l')
		return nil
	case Bool:
		return iter.ReadBool()
	case Array:
		arr := []interface{}{}
		iter.ReadArrayCB(func(iter *Iterator) bool {
			arr = append(arr, iter.Read())
			return true
		})
		return arr
	case Object:
		obj := map[string]interface{}{}
		iter.ReadObjectCB(func(Iter *Iterator, field string) bool {
			obj[field] = iter.Read()
			return true
		})
		return obj
	default:
		iter.ReportError("Read", fmt.Sprintf("unexpected value type: %v", valueType))
		return nil
	}
}
<|endoftext|>


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

package provisioner

import (
	"github.com/juju/errors"
	"github.com/juju/names"

	"github.com/juju/juju/api/base"
	"github.com/juju/juju/api/common"
	"github.com/juju/juju/api/watcher"
	"github.com/juju/juju/apiserver/params"
	"github.com/juju/juju/network"
	"github.com/juju/juju/tools"
	"github.com/juju/juju/version"
)

// State provides access to the Machiner API facade.
type State struct {
	*common.EnvironWatcher
	*common.APIAddresser

	facade base.FacadeCaller
}

const provisionerFacade = "Provisioner"

// NewState creates a new client-side Machiner facade.
func NewState(caller base.APICaller) *State {
	facadeCaller := base.NewFacadeCaller(caller, provisionerFacade)
	return &State{
		EnvironWatcher: common.NewEnvironWatcher(facadeCaller),
		APIAddresser:   common.NewAPIAddresser(facadeCaller),
		facade:         facadeCaller}
}

// machineLife requests the lifecycle of the given machine from the server.
func (st *State) machineLife(tag names.MachineTag) (params.Life, error) {
	return common.Life(st.facade, tag)
}

// Machine provides access to methods of a state.Machine through the facade.
func (st *State) Machine(tag names.MachineTag) (*Machine, error) {
	life, err := st.machineLife(tag)
	if err != nil {
		return nil, err
	}
	return &Machine{
		tag:  tag,
		life: life,
		st:   st,
	}, nil
}

// WatchEnvironMachines returns a StringsWatcher that notifies of
// changes to the lifecycles of the machines (but not containers) in
// the current environment.
func (st *State) WatchEnvironMachines() (watcher.StringsWatcher, error) {
	var result params.StringsWatchResult
	err := st.facade.FacadeCall("WatchEnvironMachines", nil, &result)
	if err != nil {
		return nil, err
	}
	if err := result.Error; err != nil {
		return nil, result.Error
	}
	w := watcher.NewStringsWatcher(st.facade.RawAPICaller(), result)
	return w, nil
}

func (st *State) WatchMachineErrorRetry() (watcher.NotifyWatcher, error) {
	var result params.NotifyWatchResult
	err := st.facade.FacadeCall("WatchMachineErrorRetry", nil, &result)
	if err != nil {
		return nil, err
	}
	if err := result.Error; err != nil {
		return nil, result.Error
	}
	w := watcher.NewNotifyWatcher(st.facade.RawAPICaller(), result)
	return w, nil
}

// StateAddresses returns the list of addresses used to connect to the state.
func (st *State) StateAddresses() ([]string, error) {
	var result params.StringsResult
	err := st.facade.FacadeCall("StateAddresses", nil, &result)
	if err != nil {
		return nil, err
	}
	return result.Result, nil
}

// ContainerManagerConfig returns information from the environment config that is
// needed for configuring the container manager.
func (st *State) ContainerManagerConfig(args params.ContainerManagerConfigParams) (result params.ContainerManagerConfig, err error) {
	err = st.facade.FacadeCall("ContainerManagerConfig", args, &result)
	return result, err
}

// ContainerConfig returns information from the environment config that is
// needed for container cloud-init.
func (st *State) ContainerConfig() (result params.ContainerConfig, err error) {
	err = st.facade.FacadeCall("ContainerConfig", nil, &result)
	return result, err
}

// MachinesWithTransientErrors returns a slice of machines and corresponding status information
// for those machines which have transient provisioning errors.
func (st *State) MachinesWithTransientErrors() ([]*Machine, []params.StatusResult, error) {
	var results params.StatusResults
	err := st.facade.FacadeCall("MachinesWithTransientErrors", nil, &results)
	if err != nil {
		return nil, nil, err
	}
	machines := make([]*Machine, len(results.Results))
	for i, status := range results.Results {
		if status.Error != nil {
			continue
		}
		machines[i] = &Machine{
			tag:  names.NewMachineTag(status.Id),
			life: status.Life,
			st:   st,
		}
	}
	return machines, results.Results, nil
}

// FindTools returns al ist of tools matching the specified version number and
// series, and, if non-empty, arch.
func (st *State) FindTools(v version.Number, series string, arch *string) (tools.List, error) {
	args := params.FindToolsParams{
		Number:       v,
		Series:       series,
		MajorVersion: -1,
		MinorVersion: -1,
	}
	if arch != nil {
		args.Arch = *arch
	}
	var result params.FindToolsResult
	if err := st.facade.FacadeCall("FindTools", args, &result); err != nil {
		return nil, err
	}
	if result.Error != nil {
		return nil, result.Error
	}
	return result.List, nil
}

// ReleaseContainerAddresses releases a static IP address allocated to a
// container.
func (st *State) ReleaseContainerAddresses(containerTag names.MachineTag) (err error) {
	defer errors.DeferredAnnotatef(&err, "ReleaseAddress for %v failed", containerTag)
	var result params.ErrorResults
	args := params.Entities{
		Entities: []params.Entity{{Tag: containerTag.String()}},
	}
	if err := st.facade.FacadeCall("ReleaseContainerAddresses", args, &result); err != nil {
		return err
	}
	return result.OneError()
}

// PrepareContainerInterfaceInfo returns the necessary information to
// configure network interfaces of a container with allocated static
// IP addresses.
//
// TODO(dimitern): Before we start using this, we need to rename both
// the method and the network.InterfaceInfo type to be called
// InterfaceConfig.
func (st *State) PrepareContainerInterfaceInfo(containerTag names.MachineTag) ([]network.InterfaceInfo, error) {
	var result params.MachineNetworkConfigResults
	args := params.Entities{
		Entities: []params.Entity{{Tag: containerTag.String()}},
	}
	if err := st.facade.FacadeCall("PrepareContainerInterfaceInfo", args, &result); err != nil {
		return nil, err
	}
	if len(result.Results) != 1 {
		return nil, errors.Errorf("expected 1 result, got %d", len(result.Results))
	}
	if err := result.Results[0].Error; err != nil {
		return nil, err
	}
	ifaceInfo := make([]network.InterfaceInfo, len(result.Results[0].Config))
	for i, netInfo := range result.Results[0].Config {
		ifaceInfo[i] = network.InterfaceInfo{
			DeviceIndex:      netInfo.DeviceIndex,
			MACAddress:       netInfo.MACAddress,
			CIDR:             netInfo.CIDR,
			NetworkName:      netInfo.NetworkName,
			ProviderId:       network.Id(netInfo.ProviderId),
			ProviderSubnetId: network.Id(netInfo.ProviderSubnetId),
			VLANTag:          netInfo.VLANTag,
			InterfaceName:    netInfo.InterfaceName,
			Disabled:         netInfo.Disabled,
			NoAutoStart:      netInfo.NoAutoStart,
			ConfigType:       network.InterfaceConfigType(netInfo.ConfigType),
			Address:          network.NewAddress(netInfo.Address, network.ScopeUnknown),
			DNSServers:       network.NewAddresses(netInfo.DNSServers...),
			GatewayAddress:   network.NewAddress(netInfo.GatewayAddress, network.ScopeUnknown),
			ExtraConfig:      netInfo.ExtraConfig,
		}
	}
	return ifaceInfo, nil
}
<commit_msg>Error message improvement<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package provisioner

import (
	"github.com/juju/errors"
	"github.com/juju/names"

	"github.com/juju/juju/api/base"
	"github.com/juju/juju/api/common"
	"github.com/juju/juju/api/watcher"
	"github.com/juju/juju/apiserver/params"
	"github.com/juju/juju/network"
	"github.com/juju/juju/tools"
	"github.com/juju/juju/version"
)

// State provides access to the Machiner API facade.
type State struct {
	*common.EnvironWatcher
	*common.APIAddresser

	facade base.FacadeCaller
}

const provisionerFacade = "Provisioner"

// NewState creates a new client-side Machiner facade.
func NewState(caller base.APICaller) *State {
	facadeCaller := base.NewFacadeCaller(caller, provisionerFacade)
	return &State{
		EnvironWatcher: common.NewEnvironWatcher(facadeCaller),
		APIAddresser:   common.NewAPIAddresser(facadeCaller),
		facade:         facadeCaller}
}

// machineLife requests the lifecycle of the given machine from the server.
func (st *State) machineLife(tag names.MachineTag) (params.Life, error) {
	return common.Life(st.facade, tag)
}

// Machine provides access to methods of a state.Machine through the facade.
func (st *State) Machine(tag names.MachineTag) (*Machine, error) {
	life, err := st.machineLife(tag)
	if err != nil {
		return nil, err
	}
	return &Machine{
		tag:  tag,
		life: life,
		st:   st,
	}, nil
}

// WatchEnvironMachines returns a StringsWatcher that notifies of
// changes to the lifecycles of the machines (but not containers) in
// the current environment.
func (st *State) WatchEnvironMachines() (watcher.StringsWatcher, error) {
	var result params.StringsWatchResult
	err := st.facade.FacadeCall("WatchEnvironMachines", nil, &result)
	if err != nil {
		return nil, err
	}
	if err := result.Error; err != nil {
		return nil, result.Error
	}
	w := watcher.NewStringsWatcher(st.facade.RawAPICaller(), result)
	return w, nil
}

func (st *State) WatchMachineErrorRetry() (watcher.NotifyWatcher, error) {
	var result params.NotifyWatchResult
	err := st.facade.FacadeCall("WatchMachineErrorRetry", nil, &result)
	if err != nil {
		return nil, err
	}
	if err := result.Error; err != nil {
		return nil, result.Error
	}
	w := watcher.NewNotifyWatcher(st.facade.RawAPICaller(), result)
	return w, nil
}

// StateAddresses returns the list of addresses used to connect to the state.
func (st *State) StateAddresses() ([]string, error) {
	var result params.StringsResult
	err := st.facade.FacadeCall("StateAddresses", nil, &result)
	if err != nil {
		return nil, err
	}
	return result.Result, nil
}

// ContainerManagerConfig returns information from the environment config that is
// needed for configuring the container manager.
func (st *State) ContainerManagerConfig(args params.ContainerManagerConfigParams) (result params.ContainerManagerConfig, err error) {
	err = st.facade.FacadeCall("ContainerManagerConfig", args, &result)
	return result, err
}

// ContainerConfig returns information from the environment config that is
// needed for container cloud-init.
func (st *State) ContainerConfig() (result params.ContainerConfig, err error) {
	err = st.facade.FacadeCall("ContainerConfig", nil, &result)
	return result, err
}

// MachinesWithTransientErrors returns a slice of machines and corresponding status information
// for those machines which have transient provisioning errors.
func (st *State) MachinesWithTransientErrors() ([]*Machine, []params.StatusResult, error) {
	var results params.StatusResults
	err := st.facade.FacadeCall("MachinesWithTransientErrors", nil, &results)
	if err != nil {
		return nil, nil, err
	}
	machines := make([]*Machine, len(results.Results))
	for i, status := range results.Results {
		if status.Error != nil {
			continue
		}
		machines[i] = &Machine{
			tag:  names.NewMachineTag(status.Id),
			life: status.Life,
			st:   st,
		}
	}
	return machines, results.Results, nil
}

// FindTools returns al ist of tools matching the specified version number and
// series, and, if non-empty, arch.
func (st *State) FindTools(v version.Number, series string, arch *string) (tools.List, error) {
	args := params.FindToolsParams{
		Number:       v,
		Series:       series,
		MajorVersion: -1,
		MinorVersion: -1,
	}
	if arch != nil {
		args.Arch = *arch
	}
	var result params.FindToolsResult
	if err := st.facade.FacadeCall("FindTools", args, &result); err != nil {
		return nil, err
	}
	if result.Error != nil {
		return nil, result.Error
	}
	return result.List, nil
}

// ReleaseContainerAddresses releases a static IP address allocated to a
// container.
func (st *State) ReleaseContainerAddresses(containerTag names.MachineTag) (err error) {
	defer errors.DeferredAnnotatef(&err, "cannot release static addresses for %q", containerTag.Id())
	var result params.ErrorResults
	args := params.Entities{
		Entities: []params.Entity{{Tag: containerTag.String()}},
	}
	if err := st.facade.FacadeCall("ReleaseContainerAddresses", args, &result); err != nil {
		return err
	}
	return result.OneError()
}

// PrepareContainerInterfaceInfo returns the necessary information to
// configure network interfaces of a container with allocated static
// IP addresses.
//
// TODO(dimitern): Before we start using this, we need to rename both
// the method and the network.InterfaceInfo type to be called
// InterfaceConfig.
func (st *State) PrepareContainerInterfaceInfo(containerTag names.MachineTag) ([]network.InterfaceInfo, error) {
	var result params.MachineNetworkConfigResults
	args := params.Entities{
		Entities: []params.Entity{{Tag: containerTag.String()}},
	}
	if err := st.facade.FacadeCall("PrepareContainerInterfaceInfo", args, &result); err != nil {
		return nil, err
	}
	if len(result.Results) != 1 {
		return nil, errors.Errorf("expected 1 result, got %d", len(result.Results))
	}
	if err := result.Results[0].Error; err != nil {
		return nil, err
	}
	ifaceInfo := make([]network.InterfaceInfo, len(result.Results[0].Config))
	for i, netInfo := range result.Results[0].Config {
		ifaceInfo[i] = network.InterfaceInfo{
			DeviceIndex:      netInfo.DeviceIndex,
			MACAddress:       netInfo.MACAddress,
			CIDR:             netInfo.CIDR,
			NetworkName:      netInfo.NetworkName,
			ProviderId:       network.Id(netInfo.ProviderId),
			ProviderSubnetId: network.Id(netInfo.ProviderSubnetId),
			VLANTag:          netInfo.VLANTag,
			InterfaceName:    netInfo.InterfaceName,
			Disabled:         netInfo.Disabled,
			NoAutoStart:      netInfo.NoAutoStart,
			ConfigType:       network.InterfaceConfigType(netInfo.ConfigType),
			Address:          network.NewAddress(netInfo.Address, network.ScopeUnknown),
			DNSServers:       network.NewAddresses(netInfo.DNSServers...),
			GatewayAddress:   network.NewAddress(netInfo.GatewayAddress, network.ScopeUnknown),
			ExtraConfig:      netInfo.ExtraConfig,
		}
	}
	return ifaceInfo, nil
}
<|endoftext|>