<commit_before>// Copyright (c) 2017, Boise State University All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"context"
	"crypto/rand"
	"errors"
	"fmt"
	"log"
	"path"
	"regexp"
	"sync"
	"time"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/client"
	"github.com/docker/go-connections/nat"
)

const (
	// jupyterNotebookImageMatch matches images from jupyter/docker-stacks, for
	// example: jupyter/minimal-notebook
	jupyterNotebookImageMatch = `[a-zA-Z0-9]+/[a-zA-Z0-9]+-notebook[:]{0,1}[a-zA-Z0-9]*`

	// allImageMatch applies no filter
	allImageMatch = `.*`

	// defaultContainerLifetime is used if a lifetime is not provided
	defaultContainerLifetime = time.Minute * 10

	// defaultMaxContainers governs the port set size and triggers reclamation
	defaultMaxContainers = 100
)

// tempNotebook holds context for a single container
type tempNotebook struct {
	// id is the docker container id.
	id string
	// hash is  a random generated hash that is used in the path of the server.
	hash string
	// imageName is the name of the image used to start the container
	imageName string
	// lastAccessed is when the container was used last.
	lastAccessed time.Time
	// port is the passthrough port for the reverse proxy.
	port int
}

// notebookPool holds data regarding running notebooks.
type notebookPool struct {
	// guards the entire struct
	sync.Mutex

	// availableImages is a list of docker images that installed on the machine,
	// and match the imageMatch expression
	availableImages map[string]struct{}

	// imageMatch filters available images by name
	imageMatch *regexp.Regexp

	// containerMap is stores the contexts for the containers.
	containerMap map[string]*tempNotebook

	// portSet holds free ports
	portSet *portRange

	// maxContainers governs the port set size and resource reclamation.
	maxContainers int

	// containerLifetime governs when the container resources are reclaimed.
	containerLifetime time.Duration

	// token is the security token for auto-auth
	token string

	// killCollection stops the automated resource reclamation
	killCollection chan struct{}

	// lastCollection is the timestamp the last time the containers were
	// reclaimed.
	lastCollection time.Time

	// deregisterMux is a channel for sending a path that needs to be
	// de-registered from the server mux.
	deregisterMux chan string
}

// errNotebookPoolFull indicates the pool is at maxContainers
var errNotebookPoolFull = errors.New("container pool hit max size limit")

// newNotebookPool creates a notebookPool and sets defaults, overriding some
// with passed arguments.
func newNotebookPool(imageRegexp string, maxContainers int, lifetime time.Duration) (*notebookPool, error) {
	if imageRegexp == "" {
		imageRegexp = jupyterNotebookImageMatch
	}
	if int64(lifetime) <= 0 {
		lifetime = defaultContainerLifetime
	}
	if maxContainers < 1 {
		maxContainers = defaultMaxContainers
	}
	imageMatch, err := regexp.Compile(imageRegexp)
	if err != nil {
		return nil, err
	}
	imageMap := map[string]struct{}{}
	cli, err := client.NewEnvClient()
	if err != nil {
		return nil, err
	}
	images, err := cli.ImageList(context.Background(), types.ImageListOptions{})
	if err != nil {
		return nil, err
	}
	for _, image := range images {
		if len(image.RepoTags) < 1 || !imageMatch.MatchString(image.RepoTags[0]) {
			continue
		}
		log.Printf("found image %s", image.RepoTags[0])
		imageMap[image.RepoTags[0]] = struct{}{}
	}
	pool := &notebookPool{
		availableImages:   imageMap,
		imageMatch:        imageMatch,
		containerMap:      make(map[string]*tempNotebook),
		portSet:           newPortRange(8000, maxContainers),
		maxContainers:     maxContainers,
		containerLifetime: lifetime,
		killCollection:    make(chan struct{}),
		deregisterMux:     make(chan string),
	}
	pool.startCollector(time.Duration(int64(lifetime) / 4))
	pool.lastCollection = time.Now()
	return pool, nil
}

// defaultHashSize is used for the unique hash generation
const defaultHashSize = 32

// newHash makes a n byte hash and returns the hex encoding.
func newHash(n int) string {
	b := make([]byte, n)
	_, err := rand.Read(b[:])
	if err != nil {
		panic(err)
	}
	return fmt.Sprintf("%x", b)
}

// newNotebook initializes and sets values for a new notebook.
func (p *notebookPool) newNotebook(image string, pull bool) (*tempNotebook, error) {
	ctx := context.Background()
	cli, err := client.NewEnvClient()
	if err != nil {
		return nil, err
	}

	// TODO(kyle): possibly provide tag support
	if pull {
		log.Printf("pulling container %s", image)
		_, err = cli.ImagePull(ctx, image, types.ImagePullOptions{})
		if err != nil {
			return nil, err
		}
		log.Printf("successfully pulled")
	}

	hash := newHash(defaultHashSize)

	port, err := p.portSet.Acquire()
	if err != nil {
		return nil, err
	}
	portString := fmt.Sprintf("%d", port)

	var pSet = nat.PortSet{}
	pt, err := nat.NewPort("tcp", portString)
	pSet[pt] = struct{}{}
	containerConfig := container.Config{
		Hostname: "0.0.0.0",
		User:     "jovyan",
		Cmd: []string{`jupyter`,
			`notebook`,
			`--no-browser`,
			`--port`,
			portString,
			`--ip=0.0.0.0`,
			fmt.Sprintf("--NotebookApp.base_url=%s", path.Join("/book", hash)),
			`--NotebookApp.port_retries=0`,
			fmt.Sprintf(`--NotebookApp.token="%s"`, p.token),
			`--NotebookApp.disable_check_xsrf=True`,
		},
		Env:          []string{fmt.Sprintf("CONFIGPROXY_AUTH_TOKEN=%s", p.token)},
		Image:        image,
		ExposedPorts: pSet,
	}

	hostConfig := container.HostConfig{
		NetworkMode: "host",
	}

	resp, err := cli.ContainerCreate(ctx, &containerConfig, &hostConfig, nil, "")
	if err != nil {
		p.portSet.Drop(port)
		return nil, err
	}

	if err := cli.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}); err != nil {
		p.portSet.Drop(port)
		return nil, err
	}
	log.Printf("created container: %s", resp.ID)
	t := &tempNotebook{resp.ID, hash, image, time.Now(), port}
	err = p.addNotebook(t)
	if err != nil {
		log.Print(err)
		p.portSet.Drop(port)
		return nil, err
	}
	return t, nil
}

// size returns the size of the containerMap with appropriate locks
func (p *notebookPool) size() int {
	p.Lock()
	n := len(p.containerMap)
	p.Unlock()
	return n
}

// addNotebook adds a tempNotebook to the containerMap, if there is room.
func (p *notebookPool) addNotebook(t *tempNotebook) error {
	n := p.size()
	log.Printf("pool size: %d of %d", n+1, p.maxContainers)
	if p.size()+1 > p.maxContainers {
		p.releaseContainers(false)
	}
	if p.size()+1 > p.maxContainers {
		return errNotebookPoolFull
	}
	p.Lock()
	p.containerMap[t.hash] = t
	p.Unlock()
	return nil
}

// stopAndKillContainer requests the stopping (docker stop) and the removal of
// the container (docker rm).  Errors are logged, but not returned and rm is
// always called.
func (p *notebookPool) stopAndKillContainer(id string) {
	d := time.Minute
	cli, err := client.NewEnvClient()
	if err != nil {
		log.Print(err)
	}
	ctx := context.Background()
	if err := cli.ContainerStop(ctx, id, &d); err != nil {
		log.Print(err)
	}
	if err := cli.ContainerRemove(ctx, id, types.ContainerRemoveOptions{Force: true}); err != nil {
		log.Print(err)
	}
}

// activeNotebooks fetchs copies of the tempNotebooks and returns them as a
// slice.
func (p *notebookPool) activeNotebooks() []tempNotebook {
	nbs := make([]tempNotebook, p.size())
	p.Lock()
	i := 0
	for _, nb := range p.containerMap {
		nbs[i] = *nb
		i++
	}
	p.Unlock()
	return nbs
}

// zombieNotebooks queries docker for containers that aren't under our
// supervision.  These can block ports assigned to our containers.
func (p *notebookPool) zombieContainers() ([]types.Container, error) {
	var cs []types.Container
	ids := map[string]struct{}{}
	p.Lock()
	for _, c := range p.containerMap {
		ids[c.id] = struct{}{}
	}
	p.Unlock()
	cli, err := client.NewEnvClient()
	opts := types.ContainerListOptions{}
	containers, err := cli.ContainerList(context.Background(), opts)
	if err != nil {
		return nil, err
	}
	for _, c := range containers {
		// If we manage it, leave it be
		if _, ok := ids[c.ID]; ok {
			continue
		}
		cs = append(cs, c)
	}
	return cs, nil
}

// nextCollection returns when the collector is run again
func (p *notebookPool) NextCollection() time.Time {
	return p.lastCollection.Add(p.containerLifetime)
}

// startCollector launches a goroutine that checks for expired containers at
// interval d.  d is typically set to containerLifetime / 4.  Call
// stopCollector to stop the reclamation.
func (p *notebookPool) startCollector(d time.Duration) {
	go func() {
		ticker := time.NewTicker(d)
		for {
			select {
			case <-ticker.C:
				p.releaseContainers(false)
				p.lastCollection = time.Now()
			case <-p.killCollection:
				ticker.Stop()
				return
			}
		}
	}()
}

// stopCollector sends a message on a channel to kill the auto reclamation.
func (p *notebookPool) stopCollector() {
	p.killCollection <- struct{}{}
}

// releaseContainers checks for expired containers and frees them from the
// containerMap.  It also frees the port in the portSet.  If force is true, age
// is ignored.
func (p *notebookPool) releaseContainers(force bool) error {
	p.Lock()
	trash := []tempNotebook{}
	for _, c := range p.containerMap {
		age := time.Now().Sub(c.lastAccessed)
		if age.Seconds() > p.containerLifetime.Seconds() || force {
			log.Printf("age: %v\n", age)
			trash = append(trash, *c)
		}
	}
	p.Unlock()
	for _, c := range trash {
		c := c
		go func() {
			log.Printf("attempting to release container %s last accessed at %v", c.id, c.lastAccessed)
			p.stopAndKillContainer(c.id)
			p.portSet.Drop(c.port)
			p.Lock()
			delete(p.containerMap, c.hash)
			p.Unlock()
			// This isn't very elegant, but we couldn't delete the pattern from the mux
			// before, but now we can with the vendored/updated copy in mux.go.  We add
			// a trailing slice when we register the path, so we must add it here too.
			p.deregisterMux <- path.Join("/book", c.hash) + "/"
		}()
	}
	return nil
}

// killZombieContainers stops and kills any docker containers that aren't under
// out supervision.
//
// FIXME(kyle): not currently called at any time, when, why, etc...
func (p *notebookPool) killZombieContainers() error {
	zombies, err := p.zombieContainers()
	if err != nil {
		return err
	}
	for _, c := range zombies {
		p.stopAndKillContainer(c.ID)
	}
	return nil
}
<commit_msg>fix reclamation time<commit_after>// Copyright (c) 2017, Boise State University All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"context"
	"crypto/rand"
	"errors"
	"fmt"
	"log"
	"path"
	"regexp"
	"sync"
	"time"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/client"
	"github.com/docker/go-connections/nat"
)

const (
	// jupyterNotebookImageMatch matches images from jupyter/docker-stacks, for
	// example: jupyter/minimal-notebook
	jupyterNotebookImageMatch = `[a-zA-Z0-9]+/[a-zA-Z0-9]+-notebook[:]{0,1}[a-zA-Z0-9]*`

	// allImageMatch applies no filter
	allImageMatch = `.*`

	// defaultContainerLifetime is used if a lifetime is not provided
	defaultContainerLifetime = time.Minute * 10

	// defaultMaxContainers governs the port set size and triggers reclamation
	defaultMaxContainers = 100

	// collectionFraction is the fraction of lifetime to collect containers.  For
	// example 4 collects every 1/4 of the container lifetime.
	collectionFraction = 4
)

// tempNotebook holds context for a single container
type tempNotebook struct {
	// id is the docker container id.
	id string
	// hash is  a random generated hash that is used in the path of the server.
	hash string
	// imageName is the name of the image used to start the container
	imageName string
	// lastAccessed is when the container was used last.
	lastAccessed time.Time
	// port is the passthrough port for the reverse proxy.
	port int
}

// notebookPool holds data regarding running notebooks.
type notebookPool struct {
	// guards the entire struct
	sync.Mutex

	// availableImages is a list of docker images that installed on the machine,
	// and match the imageMatch expression
	availableImages map[string]struct{}

	// imageMatch filters available images by name
	imageMatch *regexp.Regexp

	// containerMap is stores the contexts for the containers.
	containerMap map[string]*tempNotebook

	// portSet holds free ports
	portSet *portRange

	// maxContainers governs the port set size and resource reclamation.
	maxContainers int

	// containerLifetime governs when the container resources are reclaimed.
	containerLifetime time.Duration

	// token is the security token for auto-auth
	token string

	// killCollection stops the automated resource reclamation
	killCollection chan struct{}

	// lastCollection is the timestamp the last time the containers were
	// reclaimed.
	lastCollection time.Time

	// deregisterMux is a channel for sending a path that needs to be
	// de-registered from the server mux.
	deregisterMux chan string
}

// errNotebookPoolFull indicates the pool is at maxContainers
var errNotebookPoolFull = errors.New("container pool hit max size limit")

// newNotebookPool creates a notebookPool and sets defaults, overriding some
// with passed arguments.
func newNotebookPool(imageRegexp string, maxContainers int, lifetime time.Duration) (*notebookPool, error) {
	if imageRegexp == "" {
		imageRegexp = jupyterNotebookImageMatch
	}
	if int64(lifetime) <= 0 {
		lifetime = defaultContainerLifetime
	}
	if maxContainers < 1 {
		maxContainers = defaultMaxContainers
	}
	imageMatch, err := regexp.Compile(imageRegexp)
	if err != nil {
		return nil, err
	}
	imageMap := map[string]struct{}{}
	cli, err := client.NewEnvClient()
	if err != nil {
		return nil, err
	}
	images, err := cli.ImageList(context.Background(), types.ImageListOptions{})
	if err != nil {
		return nil, err
	}
	for _, image := range images {
		if len(image.RepoTags) < 1 || !imageMatch.MatchString(image.RepoTags[0]) {
			continue
		}
		log.Printf("found image %s", image.RepoTags[0])
		imageMap[image.RepoTags[0]] = struct{}{}
	}
	pool := &notebookPool{
		availableImages:   imageMap,
		imageMatch:        imageMatch,
		containerMap:      make(map[string]*tempNotebook),
		portSet:           newPortRange(8000, maxContainers),
		maxContainers:     maxContainers,
		containerLifetime: lifetime,
		killCollection:    make(chan struct{}),
		deregisterMux:     make(chan string),
	}
	pool.startCollector(time.Duration(int64(lifetime) / collectionFraction))
	pool.lastCollection = time.Now()
	return pool, nil
}

// defaultHashSize is used for the unique hash generation
const defaultHashSize = 32

// newHash makes a n byte hash and returns the hex encoding.
func newHash(n int) string {
	b := make([]byte, n)
	_, err := rand.Read(b[:])
	if err != nil {
		panic(err)
	}
	return fmt.Sprintf("%x", b)
}

// newNotebook initializes and sets values for a new notebook.
func (p *notebookPool) newNotebook(image string, pull bool) (*tempNotebook, error) {
	ctx := context.Background()
	cli, err := client.NewEnvClient()
	if err != nil {
		return nil, err
	}

	// TODO(kyle): possibly provide tag support
	if pull {
		log.Printf("pulling container %s", image)
		_, err = cli.ImagePull(ctx, image, types.ImagePullOptions{})
		if err != nil {
			return nil, err
		}
		log.Printf("successfully pulled")
	}

	hash := newHash(defaultHashSize)

	port, err := p.portSet.Acquire()
	if err != nil {
		return nil, err
	}
	portString := fmt.Sprintf("%d", port)

	var pSet = nat.PortSet{}
	pt, err := nat.NewPort("tcp", portString)
	pSet[pt] = struct{}{}
	containerConfig := container.Config{
		Hostname: "0.0.0.0",
		User:     "jovyan",
		Cmd: []string{`jupyter`,
			`notebook`,
			`--no-browser`,
			`--port`,
			portString,
			`--ip=0.0.0.0`,
			fmt.Sprintf("--NotebookApp.base_url=%s", path.Join("/book", hash)),
			`--NotebookApp.port_retries=0`,
			fmt.Sprintf(`--NotebookApp.token="%s"`, p.token),
			`--NotebookApp.disable_check_xsrf=True`,
		},
		Env:          []string{fmt.Sprintf("CONFIGPROXY_AUTH_TOKEN=%s", p.token)},
		Image:        image,
		ExposedPorts: pSet,
	}

	hostConfig := container.HostConfig{
		NetworkMode: "host",
	}

	resp, err := cli.ContainerCreate(ctx, &containerConfig, &hostConfig, nil, "")
	if err != nil {
		p.portSet.Drop(port)
		return nil, err
	}

	if err := cli.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}); err != nil {
		p.portSet.Drop(port)
		return nil, err
	}
	log.Printf("created container: %s", resp.ID)
	t := &tempNotebook{resp.ID, hash, image, time.Now(), port}
	err = p.addNotebook(t)
	if err != nil {
		log.Print(err)
		p.portSet.Drop(port)
		return nil, err
	}
	return t, nil
}

// size returns the size of the containerMap with appropriate locks
func (p *notebookPool) size() int {
	p.Lock()
	n := len(p.containerMap)
	p.Unlock()
	return n
}

// addNotebook adds a tempNotebook to the containerMap, if there is room.
func (p *notebookPool) addNotebook(t *tempNotebook) error {
	n := p.size()
	log.Printf("pool size: %d of %d", n+1, p.maxContainers)
	if p.size()+1 > p.maxContainers {
		p.releaseContainers(false)
	}
	if p.size()+1 > p.maxContainers {
		return errNotebookPoolFull
	}
	p.Lock()
	p.containerMap[t.hash] = t
	p.Unlock()
	return nil
}

// stopAndKillContainer requests the stopping (docker stop) and the removal of
// the container (docker rm).  Errors are logged, but not returned and rm is
// always called.
func (p *notebookPool) stopAndKillContainer(id string) {
	d := time.Minute
	cli, err := client.NewEnvClient()
	if err != nil {
		log.Print(err)
	}
	ctx := context.Background()
	if err := cli.ContainerStop(ctx, id, &d); err != nil {
		log.Print(err)
	}
	if err := cli.ContainerRemove(ctx, id, types.ContainerRemoveOptions{Force: true}); err != nil {
		log.Print(err)
	}
}

// activeNotebooks fetchs copies of the tempNotebooks and returns them as a
// slice.
func (p *notebookPool) activeNotebooks() []tempNotebook {
	nbs := make([]tempNotebook, p.size())
	p.Lock()
	i := 0
	for _, nb := range p.containerMap {
		nbs[i] = *nb
		i++
	}
	p.Unlock()
	return nbs
}

// zombieNotebooks queries docker for containers that aren't under our
// supervision.  These can block ports assigned to our containers.
func (p *notebookPool) zombieContainers() ([]types.Container, error) {
	var cs []types.Container
	ids := map[string]struct{}{}
	p.Lock()
	for _, c := range p.containerMap {
		ids[c.id] = struct{}{}
	}
	p.Unlock()
	cli, err := client.NewEnvClient()
	opts := types.ContainerListOptions{}
	containers, err := cli.ContainerList(context.Background(), opts)
	if err != nil {
		return nil, err
	}
	for _, c := range containers {
		// If we manage it, leave it be
		if _, ok := ids[c.ID]; ok {
			continue
		}
		cs = append(cs, c)
	}
	return cs, nil
}

// nextCollection returns when the collector is run again
func (p *notebookPool) NextCollection() time.Time {
	return p.lastCollection.Add(p.containerLifetime / collectionFraction)
}

// startCollector launches a goroutine that checks for expired containers at
// interval d.  d is typically set to containerLifetime / collectionFraction.  Call
// stopCollector to stop the reclamation.
func (p *notebookPool) startCollector(d time.Duration) {
	go func() {
		ticker := time.NewTicker(d)
		for {
			select {
			case <-ticker.C:
				p.releaseContainers(false)
				p.lastCollection = time.Now()
			case <-p.killCollection:
				ticker.Stop()
				return
			}
		}
	}()
}

// stopCollector sends a message on a channel to kill the auto reclamation.
func (p *notebookPool) stopCollector() {
	p.killCollection <- struct{}{}
}

// releaseContainers checks for expired containers and frees them from the
// containerMap.  It also frees the port in the portSet.  If force is true, age
// is ignored.
func (p *notebookPool) releaseContainers(force bool) error {
	p.Lock()
	trash := []tempNotebook{}
	for _, c := range p.containerMap {
		age := time.Now().Sub(c.lastAccessed)
		if age.Seconds() > p.containerLifetime.Seconds() || force {
			log.Printf("age: %v\n", age)
			trash = append(trash, *c)
		}
	}
	p.Unlock()
	for _, c := range trash {
		c := c
		go func() {
			log.Printf("attempting to release container %s last accessed at %v", c.id, c.lastAccessed)
			p.stopAndKillContainer(c.id)
			p.portSet.Drop(c.port)
			p.Lock()
			delete(p.containerMap, c.hash)
			p.Unlock()
			// This isn't very elegant, but we couldn't delete the pattern from the mux
			// before, but now we can with the vendored/updated copy in mux.go.  We add
			// a trailing slice when we register the path, so we must add it here too.
			p.deregisterMux <- path.Join("/book", c.hash) + "/"
		}()
	}
	return nil
}

// killZombieContainers stops and kills any docker containers that aren't under
// out supervision.
//
// FIXME(kyle): not currently called at any time, when, why, etc...
func (p *notebookPool) killZombieContainers() error {
	zombies, err := p.zombieContainers()
	if err != nil {
		return err
	}
	for _, c := range zombies {
		p.stopAndKillContainer(c.ID)
	}
	return nil
}
<|endoftext|>


<commit_before>package baa

import (
	"errors"
	"log"
	"net/http"
	"os"
	"strings"
	"sync"
)

const (
	// DEV mode
	DEV = "development"
	// PROD mode
	PROD = "production"
	// TEST mode
	TEST = "test"
)

// Env default application runtime environment
var Env string

// Baa provlider an application
type Baa struct {
	debug           bool
	name            string
	di              DIer
	router          Router
	pool            sync.Pool
	errorHandler    ErrorHandleFunc
	notFoundHandler HandlerFunc
	middleware      []HandlerFunc
}

// Middleware middleware handler
type Middleware interface{}

// HandlerFunc context handler func
type HandlerFunc func(*Context)

// ErrorHandleFunc HTTP error handleFunc
type ErrorHandleFunc func(error, *Context)

// appInstances storage application instances
var appInstances map[string]*Baa

// defaultAppName default application name
const defaultAppName = "_default_"

// New create a baa application without any config.
func New() *Baa {
	b := new(Baa)
	b.middleware = make([]HandlerFunc, 0)
	b.pool = sync.Pool{
		New: func() interface{} {
			return NewContext(nil, nil, b)
		},
	}
	if Env != PROD {
		b.debug = true
	}
	b.SetDIer(NewDI())
	b.SetDI("router", NewTree(b))
	b.SetDI("logger", log.New(os.Stderr, "[Baa] ", log.LstdFlags))
	b.SetDI("render", newRender())
	b.SetNotFound(b.DefaultNotFoundHandler)
	return b
}

// Instance register or returns named application
func Instance(name string) *Baa {
	if name == "" {
		name = defaultAppName
	}
	if appInstances[name] == nil {
		appInstances[name] = New()
		appInstances[name].name = defaultAppName
	}
	return appInstances[name]
}

// Default initial a default app then returns
func Default() *Baa {
	return Instance(defaultAppName)
}

// Server returns the internal *http.Server.
func (b *Baa) Server(addr string) *http.Server {
	s := &http.Server{Addr: addr}
	return s
}

// Run runs a server.
func (b *Baa) Run(addr string) {
	b.run(b.Server(addr))
}

// RunTLS runs a server with TLS configuration.
func (b *Baa) RunTLS(addr, certfile, keyfile string) {
	b.run(b.Server(addr), certfile, keyfile)
}

// RunServer runs a custom server.
func (b *Baa) RunServer(s *http.Server) {
	b.run(s)
}

// RunTLSServer runs a custom server with TLS configuration.
func (b *Baa) RunTLSServer(s *http.Server, crtFile, keyFile string) {
	b.run(s, crtFile, keyFile)
}

func (b *Baa) run(s *http.Server, files ...string) {
	s.Handler = b
	b.Logger().Printf("Run mode: %s", Env)
	if len(files) == 0 {
		b.Logger().Printf("Listen %s", s.Addr)
		b.Logger().Fatal(s.ListenAndServe())
	} else if len(files) == 2 {
		b.Logger().Printf("Listen %s with TLS", s.Addr)
		b.Logger().Fatal(s.ListenAndServeTLS(files[0], files[1]))
	} else {
		panic("invalid TLS configuration")
	}
}

func (b *Baa) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	c := b.pool.Get().(*Context)
	c.Reset(w, r)

	// build handler chain
	h := b.Router().Match(r.Method, r.URL.Path, c)
	// notFound
	if h == nil {
		c.handlers = append(c.handlers, b.notFoundHandler)
	} else {
		c.handlers = append(c.handlers, h...)
	}

	c.Next()

	b.pool.Put(c)
}

// SetDIer set baa di
func (b *Baa) SetDIer(v DIer) {
	b.di = v
}

// SetDebug set baa debug
func (b *Baa) SetDebug(v bool) {
	b.debug = v
}

// Debug returns baa debug state
func (b *Baa) Debug() bool {
	return b.debug
}

// Logger return baa logger
func (b *Baa) Logger() Logger {
	return b.GetDI("logger").(Logger)
}

// Render return baa render
func (b *Baa) Render() Renderer {
	return b.GetDI("render").(Renderer)
}

// Router return baa router
func (b *Baa) Router() Router {
	if b.router == nil {
		b.router = b.GetDI("router").(Router)
	}
	return b.router
}

// Use registers a middleware
func (b *Baa) Use(m ...Middleware) {
	for i := range m {
		if m[i] != nil {
			b.middleware = append(b.middleware, wrapMiddleware(m[i]))
		}
	}
}

// SetDI registers a dependency injection
func (b *Baa) SetDI(name string, h interface{}) {
	switch name {
	case "logger":
		if _, ok := h.(Logger); !ok {
			panic("DI logger must be implement interface baa.Logger")
		}
	case "render":
		if _, ok := h.(Renderer); !ok {
			panic("DI render must be implement interface baa.Renderer")
		}
	case "router":
		if _, ok := h.(Router); !ok {
			panic("DI router must be implement interface baa.Router")
		}
	}
	b.di.Set(name, h)
}

// GetDI fetch a registered dependency injection
func (b *Baa) GetDI(name string) interface{} {
	return b.di.Get(name)
}

// Static set static file route
// h used for set Expries ...
func (b *Baa) Static(prefix string, dir string, index bool, h HandlerFunc) {
	if prefix == "" {
		panic("baa.Static prefix can not be empty")
	}
	if dir == "" {
		panic("baa.Static dir can not be empty")
	}
	b.Get(prefix+"*", newStatic(prefix, dir, index, h))
}

// StaticFile shortcut for serve file
func (b *Baa) StaticFile(pattern string, path string) RouteNode {
	return b.Get(pattern, func(c *Context) {
		if err := serveFile(path, c); err != nil {
			c.Error(err)
		}
	})
}

// SetAutoHead sets the value who determines whether add HEAD method automatically
// when GET method is added. Combo router will not be affected by this value.
func (b *Baa) SetAutoHead(v bool) {
	b.Router().SetAutoHead(v)
}

// SetAutoTrailingSlash optional trailing slash.
func (b *Baa) SetAutoTrailingSlash(v bool) {
	b.Router().SetAutoTrailingSlash(v)
}

// Route is a shortcut for same handlers but different HTTP methods.
//
// Example:
// 		baa.Route("/", "GET,POST", h)
func (b *Baa) Route(pattern, methods string, h ...HandlerFunc) RouteNode {
	var ru RouteNode
	var ms []string
	if methods == "*" {
		for m := range RouterMethods {
			ms = append(ms, m)
		}
	} else {
		ms = strings.Split(methods, ",")
	}
	for _, m := range ms {
		ru = b.Router().Add(strings.TrimSpace(m), pattern, h)
	}
	return ru
}

// Group registers a list of same prefix route
func (b *Baa) Group(pattern string, f func(), h ...HandlerFunc) {
	b.Router().GroupAdd(pattern, f, h)
}

// Any is a shortcut for b.Router().handle("*", pattern, handlers)
func (b *Baa) Any(pattern string, h ...HandlerFunc) RouteNode {
	var ru RouteNode
	for m := range RouterMethods {
		ru = b.Router().Add(m, pattern, h)
	}
	return ru
}

// Delete is a shortcut for b.Route(pattern, "DELETE", handlers)
func (b *Baa) Delete(pattern string, h ...HandlerFunc) RouteNode {
	return b.Router().Add("DELETE", pattern, h)
}

// Get is a shortcut for b.Route(pattern, "GET", handlers)
func (b *Baa) Get(pattern string, h ...HandlerFunc) RouteNode {
	return b.Router().Add("GET", pattern, h)
}

// Head is a shortcut forb.Route(pattern, "Head", handlers)
func (b *Baa) Head(pattern string, h ...HandlerFunc) RouteNode {
	return b.Router().Add("HEAD", pattern, h)
}

// Options is a shortcut for b.Route(pattern, "Options", handlers)
func (b *Baa) Options(pattern string, h ...HandlerFunc) RouteNode {
	return b.Router().Add("OPTIONS", pattern, h)
}

// Patch is a shortcut for b.Route(pattern, "PATCH", handlers)
func (b *Baa) Patch(pattern string, h ...HandlerFunc) RouteNode {
	return b.Router().Add("PATCH", pattern, h)
}

// Post is a shortcut for b.Route(pattern, "POST", handlers)
func (b *Baa) Post(pattern string, h ...HandlerFunc) RouteNode {
	return b.Router().Add("POST", pattern, h)
}

// Put is a shortcut for b.Route(pattern, "Put", handlers)
func (b *Baa) Put(pattern string, h ...HandlerFunc) RouteNode {
	return b.Router().Add("PUT", pattern, h)
}

// SetNotFound set not found route handler
func (b *Baa) SetNotFound(h HandlerFunc) {
	b.notFoundHandler = h
}

// NotFound execute not found handler
func (b *Baa) NotFound(c *Context) {
	if b.notFoundHandler != nil {
		b.notFoundHandler(c)
		return
	}
	http.NotFound(c.Resp, c.Req)
}

// SetError set error handler
func (b *Baa) SetError(h ErrorHandleFunc) {
	b.errorHandler = h
}

// Error execute internal error handler
func (b *Baa) Error(err error, c *Context) {
	if err == nil {
		err = errors.New("Internal Server Error")
	}
	if b.errorHandler != nil {
		b.errorHandler(err, c)
		return
	}
	code := http.StatusInternalServerError
	msg := http.StatusText(code)
	if b.debug {
		msg = err.Error()
	}
	b.Logger().Println(err)
	http.Error(c.Resp, msg, code)
}

// DefaultNotFoundHandler invokes the default HTTP error handler.
func (b *Baa) DefaultNotFoundHandler(c *Context) {
	code := http.StatusNotFound
	msg := http.StatusText(code)
	http.Error(c.Resp, msg, code)
}

// URLFor use named route return format url
func (b *Baa) URLFor(name string, args ...interface{}) string {
	return b.Router().URLFor(name, args...)
}

// wrapMiddleware wraps middleware.
func wrapMiddleware(m Middleware) HandlerFunc {
	switch m := m.(type) {
	case HandlerFunc:
		return m
	case func(*Context):
		return m
	case http.Handler, http.HandlerFunc:
		return WrapHandlerFunc(func(c *Context) {
			m.(http.Handler).ServeHTTP(c.Resp, c.Req)
		})
	case func(http.ResponseWriter, *http.Request):
		return WrapHandlerFunc(func(c *Context) {
			m(c.Resp, c.Req)
		})
	default:
		panic("unknown middleware")
	}
}

// WrapHandlerFunc wrap for context handler chain
func WrapHandlerFunc(h HandlerFunc) HandlerFunc {
	return func(c *Context) {
		h(c)
		c.Next()
	}
}

func init() {
	appInstances = make(map[string]*Baa)
	Env = os.Getenv("BAA_ENV")
	if Env == "" {
		Env = DEV
	}
}
<commit_msg>fix instance name<commit_after>package baa

import (
	"errors"
	"log"
	"net/http"
	"os"
	"strings"
	"sync"
)

const (
	// DEV mode
	DEV = "development"
	// PROD mode
	PROD = "production"
	// TEST mode
	TEST = "test"
)

// Env default application runtime environment
var Env string

// Baa provlider an application
type Baa struct {
	debug           bool
	name            string
	di              DIer
	router          Router
	pool            sync.Pool
	errorHandler    ErrorHandleFunc
	notFoundHandler HandlerFunc
	middleware      []HandlerFunc
}

// Middleware middleware handler
type Middleware interface{}

// HandlerFunc context handler func
type HandlerFunc func(*Context)

// ErrorHandleFunc HTTP error handleFunc
type ErrorHandleFunc func(error, *Context)

// appInstances storage application instances
var appInstances map[string]*Baa

// defaultAppName default application name
const defaultAppName = "_default_"

// New create a baa application without any config.
func New() *Baa {
	b := new(Baa)
	b.middleware = make([]HandlerFunc, 0)
	b.pool = sync.Pool{
		New: func() interface{} {
			return NewContext(nil, nil, b)
		},
	}
	if Env != PROD {
		b.debug = true
	}
	b.SetDIer(NewDI())
	b.SetDI("router", NewTree(b))
	b.SetDI("logger", log.New(os.Stderr, "[Baa] ", log.LstdFlags))
	b.SetDI("render", newRender())
	b.SetNotFound(b.DefaultNotFoundHandler)
	return b
}

// Instance register or returns named application
func Instance(name string) *Baa {
	if name == "" {
		name = defaultAppName
	}
	if appInstances[name] == nil {
		appInstances[name] = New()
		appInstances[name].name = name
	}
	return appInstances[name]
}

// Default initial a default app then returns
func Default() *Baa {
	return Instance(defaultAppName)
}

// Server returns the internal *http.Server.
func (b *Baa) Server(addr string) *http.Server {
	s := &http.Server{Addr: addr}
	return s
}

// Run runs a server.
func (b *Baa) Run(addr string) {
	b.run(b.Server(addr))
}

// RunTLS runs a server with TLS configuration.
func (b *Baa) RunTLS(addr, certfile, keyfile string) {
	b.run(b.Server(addr), certfile, keyfile)
}

// RunServer runs a custom server.
func (b *Baa) RunServer(s *http.Server) {
	b.run(s)
}

// RunTLSServer runs a custom server with TLS configuration.
func (b *Baa) RunTLSServer(s *http.Server, crtFile, keyFile string) {
	b.run(s, crtFile, keyFile)
}

func (b *Baa) run(s *http.Server, files ...string) {
	s.Handler = b
	b.Logger().Printf("Run mode: %s", Env)
	if len(files) == 0 {
		b.Logger().Printf("Listen %s", s.Addr)
		b.Logger().Fatal(s.ListenAndServe())
	} else if len(files) == 2 {
		b.Logger().Printf("Listen %s with TLS", s.Addr)
		b.Logger().Fatal(s.ListenAndServeTLS(files[0], files[1]))
	} else {
		panic("invalid TLS configuration")
	}
}

func (b *Baa) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	c := b.pool.Get().(*Context)
	c.Reset(w, r)

	// build handler chain
	h := b.Router().Match(r.Method, r.URL.Path, c)
	// notFound
	if h == nil {
		c.handlers = append(c.handlers, b.notFoundHandler)
	} else {
		c.handlers = append(c.handlers, h...)
	}

	c.Next()

	b.pool.Put(c)
}

// SetDIer set baa di
func (b *Baa) SetDIer(v DIer) {
	b.di = v
}

// SetDebug set baa debug
func (b *Baa) SetDebug(v bool) {
	b.debug = v
}

// Debug returns baa debug state
func (b *Baa) Debug() bool {
	return b.debug
}

// Logger return baa logger
func (b *Baa) Logger() Logger {
	return b.GetDI("logger").(Logger)
}

// Render return baa render
func (b *Baa) Render() Renderer {
	return b.GetDI("render").(Renderer)
}

// Router return baa router
func (b *Baa) Router() Router {
	if b.router == nil {
		b.router = b.GetDI("router").(Router)
	}
	return b.router
}

// Use registers a middleware
func (b *Baa) Use(m ...Middleware) {
	for i := range m {
		if m[i] != nil {
			b.middleware = append(b.middleware, wrapMiddleware(m[i]))
		}
	}
}

// SetDI registers a dependency injection
func (b *Baa) SetDI(name string, h interface{}) {
	switch name {
	case "logger":
		if _, ok := h.(Logger); !ok {
			panic("DI logger must be implement interface baa.Logger")
		}
	case "render":
		if _, ok := h.(Renderer); !ok {
			panic("DI render must be implement interface baa.Renderer")
		}
	case "router":
		if _, ok := h.(Router); !ok {
			panic("DI router must be implement interface baa.Router")
		}
	}
	b.di.Set(name, h)
}

// GetDI fetch a registered dependency injection
func (b *Baa) GetDI(name string) interface{} {
	return b.di.Get(name)
}

// Static set static file route
// h used for set Expries ...
func (b *Baa) Static(prefix string, dir string, index bool, h HandlerFunc) {
	if prefix == "" {
		panic("baa.Static prefix can not be empty")
	}
	if dir == "" {
		panic("baa.Static dir can not be empty")
	}
	b.Get(prefix+"*", newStatic(prefix, dir, index, h))
}

// StaticFile shortcut for serve file
func (b *Baa) StaticFile(pattern string, path string) RouteNode {
	return b.Get(pattern, func(c *Context) {
		if err := serveFile(path, c); err != nil {
			c.Error(err)
		}
	})
}

// SetAutoHead sets the value who determines whether add HEAD method automatically
// when GET method is added. Combo router will not be affected by this value.
func (b *Baa) SetAutoHead(v bool) {
	b.Router().SetAutoHead(v)
}

// SetAutoTrailingSlash optional trailing slash.
func (b *Baa) SetAutoTrailingSlash(v bool) {
	b.Router().SetAutoTrailingSlash(v)
}

// Route is a shortcut for same handlers but different HTTP methods.
//
// Example:
// 		baa.Route("/", "GET,POST", h)
func (b *Baa) Route(pattern, methods string, h ...HandlerFunc) RouteNode {
	var ru RouteNode
	var ms []string
	if methods == "*" {
		for m := range RouterMethods {
			ms = append(ms, m)
		}
	} else {
		ms = strings.Split(methods, ",")
	}
	for _, m := range ms {
		ru = b.Router().Add(strings.TrimSpace(m), pattern, h)
	}
	return ru
}

// Group registers a list of same prefix route
func (b *Baa) Group(pattern string, f func(), h ...HandlerFunc) {
	b.Router().GroupAdd(pattern, f, h)
}

// Any is a shortcut for b.Router().handle("*", pattern, handlers)
func (b *Baa) Any(pattern string, h ...HandlerFunc) RouteNode {
	var ru RouteNode
	for m := range RouterMethods {
		ru = b.Router().Add(m, pattern, h)
	}
	return ru
}

// Delete is a shortcut for b.Route(pattern, "DELETE", handlers)
func (b *Baa) Delete(pattern string, h ...HandlerFunc) RouteNode {
	return b.Router().Add("DELETE", pattern, h)
}

// Get is a shortcut for b.Route(pattern, "GET", handlers)
func (b *Baa) Get(pattern string, h ...HandlerFunc) RouteNode {
	return b.Router().Add("GET", pattern, h)
}

// Head is a shortcut forb.Route(pattern, "Head", handlers)
func (b *Baa) Head(pattern string, h ...HandlerFunc) RouteNode {
	return b.Router().Add("HEAD", pattern, h)
}

// Options is a shortcut for b.Route(pattern, "Options", handlers)
func (b *Baa) Options(pattern string, h ...HandlerFunc) RouteNode {
	return b.Router().Add("OPTIONS", pattern, h)
}

// Patch is a shortcut for b.Route(pattern, "PATCH", handlers)
func (b *Baa) Patch(pattern string, h ...HandlerFunc) RouteNode {
	return b.Router().Add("PATCH", pattern, h)
}

// Post is a shortcut for b.Route(pattern, "POST", handlers)
func (b *Baa) Post(pattern string, h ...HandlerFunc) RouteNode {
	return b.Router().Add("POST", pattern, h)
}

// Put is a shortcut for b.Route(pattern, "Put", handlers)
func (b *Baa) Put(pattern string, h ...HandlerFunc) RouteNode {
	return b.Router().Add("PUT", pattern, h)
}

// SetNotFound set not found route handler
func (b *Baa) SetNotFound(h HandlerFunc) {
	b.notFoundHandler = h
}

// NotFound execute not found handler
func (b *Baa) NotFound(c *Context) {
	if b.notFoundHandler != nil {
		b.notFoundHandler(c)
		return
	}
	http.NotFound(c.Resp, c.Req)
}

// SetError set error handler
func (b *Baa) SetError(h ErrorHandleFunc) {
	b.errorHandler = h
}

// Error execute internal error handler
func (b *Baa) Error(err error, c *Context) {
	if err == nil {
		err = errors.New("Internal Server Error")
	}
	if b.errorHandler != nil {
		b.errorHandler(err, c)
		return
	}
	code := http.StatusInternalServerError
	msg := http.StatusText(code)
	if b.debug {
		msg = err.Error()
	}
	b.Logger().Println(err)
	http.Error(c.Resp, msg, code)
}

// DefaultNotFoundHandler invokes the default HTTP error handler.
func (b *Baa) DefaultNotFoundHandler(c *Context) {
	code := http.StatusNotFound
	msg := http.StatusText(code)
	http.Error(c.Resp, msg, code)
}

// URLFor use named route return format url
func (b *Baa) URLFor(name string, args ...interface{}) string {
	return b.Router().URLFor(name, args...)
}

// wrapMiddleware wraps middleware.
func wrapMiddleware(m Middleware) HandlerFunc {
	switch m := m.(type) {
	case HandlerFunc:
		return m
	case func(*Context):
		return m
	case http.Handler, http.HandlerFunc:
		return WrapHandlerFunc(func(c *Context) {
			m.(http.Handler).ServeHTTP(c.Resp, c.Req)
		})
	case func(http.ResponseWriter, *http.Request):
		return WrapHandlerFunc(func(c *Context) {
			m(c.Resp, c.Req)
		})
	default:
		panic("unknown middleware")
	}
}

// WrapHandlerFunc wrap for context handler chain
func WrapHandlerFunc(h HandlerFunc) HandlerFunc {
	return func(c *Context) {
		h(c)
		c.Next()
	}
}

func init() {
	appInstances = make(map[string]*Baa)
	Env = os.Getenv("BAA_ENV")
	if Env == "" {
		Env = DEV
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2015 Google Inc. All rights reserved.

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 e2e

import (
	"fmt"
	"strconv"
	"sync"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util/wait"

	"github.com/golang/glog"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

// Delete a Replication Controller and all pods it spawned
func DeleteRC(c *client.Client, ns, name string) error {
	rc, err := c.ReplicationControllers(ns).Get(name)
	if err != nil {
		return fmt.Errorf("Failed to find replication controller %s in namespace %s: %v", name, ns, err)
	}

	rc.Spec.Replicas = 0

	if _, err := c.ReplicationControllers(ns).Update(rc); err != nil {
		return fmt.Errorf("Failed to resize replication controller %s to zero: %v", name, err)
	}

	if err := wait.Poll(time.Second, time.Minute*20, client.ControllerHasDesiredReplicas(c, rc)); err != nil {
		return fmt.Errorf("Error waiting for replication controller %s replicas to reach 0: %v", name, err)
	}

	// Delete the replication controller.
	if err := c.ReplicationControllers(ns).Delete(name); err != nil {
		return fmt.Errorf("Failed to delete replication controller %s: %v", name, err)
	}
	return nil
}

// Launch a Replication Controller and wait for all pods it spawns
// to become running
func RunRC(c *client.Client, name string, ns, image string, replicas int) {
	defer GinkgoRecover()

	var last int
	current := 0
	same := 0

	defer func() {
		By("Cleaning up the replication controller")
		err := DeleteRC(c, ns, name)
		Expect(err).NotTo(HaveOccurred())
	}()

	By(fmt.Sprintf("Creating replication controller %s", name))
	_, err := c.ReplicationControllers(ns).Create(&api.ReplicationController{
		ObjectMeta: api.ObjectMeta{
			Name: name,
		},
		Spec: api.ReplicationControllerSpec{
			Replicas: replicas,
			Selector: map[string]string{
				"name": name,
			},
			Template: &api.PodTemplateSpec{
				ObjectMeta: api.ObjectMeta{
					Labels: map[string]string{"name": name},
				},
				Spec: api.PodSpec{
					Containers: []api.Container{
						{
							Name:  name,
							Image: image,
							Ports: []api.ContainerPort{{ContainerPort: 80}},
						},
					},
				},
			},
		},
	})
	Expect(err).NotTo(HaveOccurred())

	By(fmt.Sprintf("Making sure all %d replicas exist", replicas))
	label := labels.SelectorFromSet(labels.Set(map[string]string{"name": name}))
	pods, err := c.Pods(ns).List(label)
	Expect(err).NotTo(HaveOccurred())
	current = len(pods.Items)
	failCount := 5
	for same < failCount && current < replicas {
		glog.Infof("Controller %s: Found %d pods out of %d", name, current, replicas)
		if last < current {
			same = 0
		} else if last == current {
			same++
		} else if current < last {
			Failf("Controller %s: Number of submitted pods dropped from %d to %d", last, current)
		}

		if same >= failCount {
			glog.Infof("No pods submitted for the last %d checks", failCount)
		}

		last = current
		time.Sleep(5 * time.Second)
		pods, err = c.Pods(ns).List(label)
		Expect(err).NotTo(HaveOccurred())
		current = len(pods.Items)
	}
	Expect(current).To(Equal(replicas))
	glog.Infof("Controller %s: Found %d pods out of %d", name, current, replicas)

	By("Waiting for each pod to be running")
	same = 0
	last = 0
	failCount = 10
	current = 0
	for same < failCount && current < replicas {
		current = 0
		waiting := 0
		pending := 0
		unknown := 0
		time.Sleep(10 * time.Second)

		currentPods, listErr := c.Pods(ns).List(label)
		Expect(listErr).NotTo(HaveOccurred())
		if len(currentPods.Items) != len(pods.Items) {
			Failf("Number of reported pods changed: %d vs %d", len(currentPods.Items), len(pods.Items))
		}
		for _, p := range currentPods.Items {
			if p.Status.Phase == api.PodRunning {
				current++
			} else if p.Status.Phase == api.PodPending {
				if p.Status.Host == "" {
					waiting++
				} else {
					pending++
				}
			} else if p.Status.Phase == api.PodUnknown {
				unknown++
			}
		}
		glog.Infof("Pod States: %d running, %d pending, %d waiting, %d unknown ", current, pending, waiting, unknown)
		if last < current {
			same = 0
		} else if last == current {
			same++
		} else if current < last {
			Failf("Number of running pods dropped from %d to %d", last, current)
		}
		if same >= failCount {
			glog.Infof("No pods started for the last %d checks", failCount)
		}
		last = current
	}
	Expect(current).To(Equal(replicas))
}

// This test suite can take a long time to run, so by default it is added to
// the ginkgo.skip list (see driver.go).
// To run this suite you must explicitly ask for it by setting the
// -t/--test flag or ginkgo.focus flag.
var _ = Describe("Density", func() {
	var c *client.Client
	var minionCount int
	var RCName string
	var ns string

	BeforeEach(func() {
		var err error
		c, err = loadClient()
		expectNoError(err)
		minions, err := c.Nodes().List()
		expectNoError(err)
		minionCount = len(minions.Items)
		Expect(minionCount).NotTo(BeZero())
		ns = api.NamespaceDefault
	})

	AfterEach(func() {
		// Remove any remaining pods from this test if the
		// replication controller still exists and the replica count
		// isn't 0.  This means the controller wasn't cleaned up
		// during the test so clean it up here
		rc, err := c.ReplicationControllers(ns).Get(RCName)
		if err == nil && rc.Spec.Replicas != 0 {
			DeleteRC(c, ns, RCName)
		}
	})

	// Tests with "Skipped" substring in their name will be skipped when running
	// e2e test suite without --ginkgo.focus & --ginkgo.skip flags.

	for _, count := range []int{30, 50, 100} {
		name := fmt.Sprintf("should allow starting %d pods per node", count)
		if count > 30 {
			name = "[Skipped] " + name
		}
		It(name, func() {
			RCName = "my-hostname-density" + strconv.Itoa(count) + "-" + string(util.NewUUID())
			RunRC(c, RCName, ns, "kubernetes/pause:go", count*minionCount)
		})
	}

	It("[Skipped] should have master components that can handle many short-lived pods", func() {
		threads := 5
		var wg sync.WaitGroup
		wg.Add(threads)
		for i := 0; i < threads; i++ {
			go func() {
				defer wg.Done()
				for i := 0; i < 10; i++ {
					name := "my-hostname-thrash-" + string(util.NewUUID())
					RunRC(c, name, ns, "kubernetes/pause:go", 10*minionCount)
				}
			}()
		}
		wg.Wait()
	})
})
<commit_msg>Don't run Density test in e2e runs until #6059 is fixed<commit_after>/*
Copyright 2015 Google Inc. All rights reserved.

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 e2e

import (
	"fmt"
	"strconv"
	"sync"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util/wait"

	"github.com/golang/glog"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

// Delete a Replication Controller and all pods it spawned
func DeleteRC(c *client.Client, ns, name string) error {
	rc, err := c.ReplicationControllers(ns).Get(name)
	if err != nil {
		return fmt.Errorf("Failed to find replication controller %s in namespace %s: %v", name, ns, err)
	}

	rc.Spec.Replicas = 0

	if _, err := c.ReplicationControllers(ns).Update(rc); err != nil {
		return fmt.Errorf("Failed to resize replication controller %s to zero: %v", name, err)
	}

	if err := wait.Poll(time.Second, time.Minute*20, client.ControllerHasDesiredReplicas(c, rc)); err != nil {
		return fmt.Errorf("Error waiting for replication controller %s replicas to reach 0: %v", name, err)
	}

	// Delete the replication controller.
	if err := c.ReplicationControllers(ns).Delete(name); err != nil {
		return fmt.Errorf("Failed to delete replication controller %s: %v", name, err)
	}
	return nil
}

// Launch a Replication Controller and wait for all pods it spawns
// to become running
func RunRC(c *client.Client, name string, ns, image string, replicas int) {
	defer GinkgoRecover()

	var last int
	current := 0
	same := 0

	defer func() {
		By("Cleaning up the replication controller")
		err := DeleteRC(c, ns, name)
		Expect(err).NotTo(HaveOccurred())
	}()

	By(fmt.Sprintf("Creating replication controller %s", name))
	_, err := c.ReplicationControllers(ns).Create(&api.ReplicationController{
		ObjectMeta: api.ObjectMeta{
			Name: name,
		},
		Spec: api.ReplicationControllerSpec{
			Replicas: replicas,
			Selector: map[string]string{
				"name": name,
			},
			Template: &api.PodTemplateSpec{
				ObjectMeta: api.ObjectMeta{
					Labels: map[string]string{"name": name},
				},
				Spec: api.PodSpec{
					Containers: []api.Container{
						{
							Name:  name,
							Image: image,
							Ports: []api.ContainerPort{{ContainerPort: 80}},
						},
					},
				},
			},
		},
	})
	Expect(err).NotTo(HaveOccurred())

	By(fmt.Sprintf("Making sure all %d replicas exist", replicas))
	label := labels.SelectorFromSet(labels.Set(map[string]string{"name": name}))
	pods, err := c.Pods(ns).List(label)
	Expect(err).NotTo(HaveOccurred())
	current = len(pods.Items)
	failCount := 5
	for same < failCount && current < replicas {
		glog.Infof("Controller %s: Found %d pods out of %d", name, current, replicas)
		if last < current {
			same = 0
		} else if last == current {
			same++
		} else if current < last {
			Failf("Controller %s: Number of submitted pods dropped from %d to %d", last, current)
		}

		if same >= failCount {
			glog.Infof("No pods submitted for the last %d checks", failCount)
		}

		last = current
		time.Sleep(5 * time.Second)
		pods, err = c.Pods(ns).List(label)
		Expect(err).NotTo(HaveOccurred())
		current = len(pods.Items)
	}
	Expect(current).To(Equal(replicas))
	glog.Infof("Controller %s: Found %d pods out of %d", name, current, replicas)

	By("Waiting for each pod to be running")
	same = 0
	last = 0
	failCount = 10
	current = 0
	for same < failCount && current < replicas {
		current = 0
		waiting := 0
		pending := 0
		unknown := 0
		time.Sleep(10 * time.Second)

		currentPods, listErr := c.Pods(ns).List(label)
		Expect(listErr).NotTo(HaveOccurred())
		if len(currentPods.Items) != len(pods.Items) {
			Failf("Number of reported pods changed: %d vs %d", len(currentPods.Items), len(pods.Items))
		}
		for _, p := range currentPods.Items {
			if p.Status.Phase == api.PodRunning {
				current++
			} else if p.Status.Phase == api.PodPending {
				if p.Status.Host == "" {
					waiting++
				} else {
					pending++
				}
			} else if p.Status.Phase == api.PodUnknown {
				unknown++
			}
		}
		glog.Infof("Pod States: %d running, %d pending, %d waiting, %d unknown ", current, pending, waiting, unknown)
		if last < current {
			same = 0
		} else if last == current {
			same++
		} else if current < last {
			Failf("Number of running pods dropped from %d to %d", last, current)
		}
		if same >= failCount {
			glog.Infof("No pods started for the last %d checks", failCount)
		}
		last = current
	}
	Expect(current).To(Equal(replicas))
}

// This test suite can take a long time to run, so by default it is added to
// the ginkgo.skip list (see driver.go).
// To run this suite you must explicitly ask for it by setting the
// -t/--test flag or ginkgo.focus flag.
var _ = Describe("Density", func() {
	var c *client.Client
	var minionCount int
	var RCName string
	var ns string

	BeforeEach(func() {
		var err error
		c, err = loadClient()
		expectNoError(err)
		minions, err := c.Nodes().List()
		expectNoError(err)
		minionCount = len(minions.Items)
		Expect(minionCount).NotTo(BeZero())
		ns = api.NamespaceDefault
	})

	AfterEach(func() {
		// Remove any remaining pods from this test if the
		// replication controller still exists and the replica count
		// isn't 0.  This means the controller wasn't cleaned up
		// during the test so clean it up here
		rc, err := c.ReplicationControllers(ns).Get(RCName)
		if err == nil && rc.Spec.Replicas != 0 {
			DeleteRC(c, ns, RCName)
		}
	})

	// Tests with "Skipped" substring in their name will be skipped when running
	// e2e test suite without --ginkgo.focus & --ginkgo.skip flags.

	for _, count := range []int{30, 50, 100} {
		name := fmt.Sprintf("should allow starting %d pods per node", count)
		// TODO(wojtek-t): Don't skip 30 pods per node test once #6059 if fixed.
		if count > 0 {
			name = "[Skipped] " + name
		}
		It(name, func() {
			RCName = "my-hostname-density" + strconv.Itoa(count) + "-" + string(util.NewUUID())
			RunRC(c, RCName, ns, "kubernetes/pause:go", count*minionCount)
		})
	}

	It("[Skipped] should have master components that can handle many short-lived pods", func() {
		threads := 5
		var wg sync.WaitGroup
		wg.Add(threads)
		for i := 0; i < threads; i++ {
			go func() {
				defer wg.Done()
				for i := 0; i < 10; i++ {
					name := "my-hostname-thrash-" + string(util.NewUUID())
					RunRC(c, name, ns, "kubernetes/pause:go", 10*minionCount)
				}
			}()
		}
		wg.Wait()
	})
})
<|endoftext|>


<commit_before>// Copyright 2016 CoreOS, Inc.
//
// 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 misc

import (
	"fmt"
	"strings"

	"github.com/coreos/mantle/kola/cluster"
	"github.com/coreos/mantle/kola/register"
	"github.com/coreos/mantle/platform"
)

func init() {
	register.Register(&register.Test{
		Run:         SUIDFiles,
		ClusterSize: 1,
		Name:        "coreos.filesystem.suid",
		UserData:    `#cloud-config`,
	})
	register.Register(&register.Test{
		Run:         SGIDFiles,
		ClusterSize: 1,
		Name:        "coreos.filesystem.sgid",
		UserData:    `#cloud-config`,
	})
	register.Register(&register.Test{
		Run:         WritableFiles,
		ClusterSize: 1,
		Name:        "coreos.filesystem.writablefiles",
		UserData:    `#cloud-config`,
	})
	register.Register(&register.Test{
		Run:         WritableDirs,
		ClusterSize: 1,
		Name:        "coreos.filesystem.writabledirs",
		UserData:    `#cloud-config`,
	})
}

func sugidFiles(m platform.Machine, validfiles []string, mode string) error {
	badfiles := make([]string, 0, 0)

	command := fmt.Sprintf("sudo find / -path /sys -prune -o -path /proc -prune -o -type f -perm -%v -print", mode)

	output, err := m.SSH(command)
	if err != nil {
		return fmt.Errorf("Failed to run find: output %s, status: %v", output, err)
	}

	if string(output) == "" {
		return nil
	}

	files := strings.Split(string(output), "\n")
	for _, file := range files {
		var valid bool

		for _, validfile := range validfiles {
			if file == validfile {
				valid = true
			}
		}
		if valid != true {
			badfiles = append(badfiles, file)
		}
	}

	if len(badfiles) != 0 {
		return fmt.Errorf("Unknown SUID or SGID files found: %v", badfiles)
	}

	return nil
}

func SUIDFiles(c cluster.TestCluster) error {
	m := c.Machines()[0]

	validfiles := []string{
		"/usr/bin/chage",
		"/usr/bin/chfn",
		"/usr/bin/chsh",
		"/usr/bin/expiry",
		"/usr/bin/gpasswd",
		"/usr/bin/ksu",
		"/usr/bin/man",
		"/usr/bin/mandb",
		"/usr/bin/mount",
		"/usr/bin/newgrp",
		"/usr/bin/passwd",
		"/usr/bin/pkexec",
		"/usr/bin/umount",
		"/usr/bin/su",
		"/usr/bin/sudo",
		"/usr/lib64/polkit-1/polkit-agent-helper-1",
		"/usr/libexec/dbus-daemon-launch-helper",
		"/usr/sbin/mount.nfs",
		"/usr/sbin/unix_chkpwd",
	}

	return sugidFiles(m, validfiles, "4000")
}

func SGIDFiles(c cluster.TestCluster) error {
	m := c.Machines()[0]

	validfiles := []string{}

	return sugidFiles(m, validfiles, "2000")
}

func WritableFiles(c cluster.TestCluster) error {
	m := c.Machines()[0]

	output, err := m.SSH("sudo find / -regextype posix-extended -regex \"/(sys|proc)\" -prune -o -type f -perm -0002 -print")
	if err != nil {
		return fmt.Errorf("Failed to run find: output %s, status: %v", output, err)
	}

	if string(output) != "" {
		return fmt.Errorf("Unknown writable files found: %v", output)
	}

	return nil
}

func WritableDirs(c cluster.TestCluster) error {
	m := c.Machines()[0]

	output, err := m.SSH("sudo find / -regextype posix-extended -regex \"/(sys|proc)\" -prune -o -type d -perm -0002 -a ! -perm -1000 -print")
	if err != nil {
		return fmt.Errorf("Failed to run find: output %s, status: %v", output, err)
	}

	if string(output) != "" {
		return fmt.Errorf("Unknown writable directories found: %v", output)
	}

	return nil
}
<commit_msg>kola/tests: fix suid and sgid tests<commit_after>// Copyright 2016 CoreOS, Inc.
//
// 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 misc

import (
	"fmt"
	"strings"

	"github.com/coreos/mantle/kola/cluster"
	"github.com/coreos/mantle/kola/register"
	"github.com/coreos/mantle/platform"
)

func init() {
	register.Register(&register.Test{
		Run:         SUIDFiles,
		ClusterSize: 1,
		Name:        "coreos.filesystem.suid",
		UserData:    `#cloud-config`,
	})
	register.Register(&register.Test{
		Run:         SGIDFiles,
		ClusterSize: 1,
		Name:        "coreos.filesystem.sgid",
		UserData:    `#cloud-config`,
	})
	register.Register(&register.Test{
		Run:         WritableFiles,
		ClusterSize: 1,
		Name:        "coreos.filesystem.writablefiles",
		UserData:    `#cloud-config`,
	})
	register.Register(&register.Test{
		Run:         WritableDirs,
		ClusterSize: 1,
		Name:        "coreos.filesystem.writabledirs",
		UserData:    `#cloud-config`,
	})
}

func sugidFiles(m platform.Machine, validfiles []string, mode string) error {
	badfiles := make([]string, 0, 0)

	command := fmt.Sprintf("sudo find / -path /sys -prune -o -path /proc -prune -o -path /var/lib/rkt -prune -o -type f -perm -%v -print", mode)

	output, err := m.SSH(command)
	if err != nil {
		return fmt.Errorf("Failed to run find: output %s, status: %v", output, err)
	}

	if string(output) == "" {
		return nil
	}

	files := strings.Split(string(output), "\n")
	for _, file := range files {
		var valid bool

		for _, validfile := range validfiles {
			if file == validfile {
				valid = true
			}
		}
		if valid != true {
			badfiles = append(badfiles, file)
		}
	}

	if len(badfiles) != 0 {
		return fmt.Errorf("Unknown SUID or SGID files found: %v", badfiles)
	}

	return nil
}

func SUIDFiles(c cluster.TestCluster) error {
	m := c.Machines()[0]

	validfiles := []string{
		"/usr/bin/chage",
		"/usr/bin/chfn",
		"/usr/bin/chsh",
		"/usr/bin/expiry",
		"/usr/bin/gpasswd",
		"/usr/bin/ksu",
		"/usr/bin/man",
		"/usr/bin/mandb",
		"/usr/bin/mount",
		"/usr/bin/newgrp",
		"/usr/bin/passwd",
		"/usr/bin/pkexec",
		"/usr/bin/umount",
		"/usr/bin/su",
		"/usr/bin/sudo",
		"/usr/lib64/polkit-1/polkit-agent-helper-1",
		"/usr/libexec/dbus-daemon-launch-helper",
		"/usr/sbin/mount.nfs",
		"/usr/sbin/unix_chkpwd",
	}

	return sugidFiles(m, validfiles, "4000")
}

func SGIDFiles(c cluster.TestCluster) error {
	m := c.Machines()[0]

	validfiles := []string{}

	return sugidFiles(m, validfiles, "2000")
}

func WritableFiles(c cluster.TestCluster) error {
	m := c.Machines()[0]

	output, err := m.SSH("sudo find / -regextype posix-extended -regex \"/(sys|proc)\" -prune -o -type f -perm -0002 -print")
	if err != nil {
		return fmt.Errorf("Failed to run find: output %s, status: %v", output, err)
	}

	if string(output) != "" {
		return fmt.Errorf("Unknown writable files found: %v", output)
	}

	return nil
}

func WritableDirs(c cluster.TestCluster) error {
	m := c.Machines()[0]

	output, err := m.SSH("sudo find / -regextype posix-extended -regex \"/(sys|proc)\" -prune -o -type d -perm -0002 -a ! -perm -1000 -print")
	if err != nil {
		return fmt.Errorf("Failed to run find: output %s, status: %v", output, err)
	}

	if string(output) != "" {
		return fmt.Errorf("Unknown writable directories found: %v", output)
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2014 The Azul3D 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 wav

import (
	"encoding/binary"
	"errors"
	"io"
	"sync"

	"azul3d.org/audio.v1"
)

const (
	// Data format codes

	// PCM
	wave_FORMAT_PCM = 0x0001

	// IEEE float
	wave_FORMAT_IEEE_FLOAT = 0x0003

	// 8-bit ITU-T G.711 A-law
	wave_FORMAT_ALAW = 0x0006

	// 8-bit ITU-T G.711 µ-law
	wave_FORMAT_MULAW = 0x0007

	// Determined by SubFormat
	wave_FORMAT_EXTENSIBLE = 0xFFFE
)

type decoder struct {
	access sync.RWMutex

	format, bitsPerSample   uint16
	chunkSize, currentCount uint32
	dataChunkBegin          int32

	r      interface{}
	rd     io.Reader
	config *audio.Config
}

// advance advances the byte counter by sz. If the chunk size is known and
// after advancement the byte counter is larger than the chunk size, then
// audio.EOS is returned.
//
// If the chunk size is not known, the data chunk marker is extended by sz as
// well.
func (d *decoder) advance(sz int) error {
	d.currentCount += uint32(sz)
	if d.chunkSize > 0 {
		if d.currentCount > d.chunkSize {
			return audio.EOS
		}
	} else {
		d.dataChunkBegin += int32(sz)
	}
	return nil
}

func (d *decoder) bRead(data interface{}, sz int) error {
	err := d.advance(sz)
	if err != nil {
		return err
	}
	return binary.Read(d.rd, binary.LittleEndian, data)
}

// Reads and returns the next RIFF chunk, note that always len(ident) == 4
// E.g.
//
//  "fmt " (notice space).
//
// Length is length of chunk data.
//
// Returns any read errors.
func (d *decoder) nextChunk() (ident string, length uint32, err error) {
	// Read chunk identity, like "RIFF" or "fmt "
	var chunkIdent [4]byte
	err = d.bRead(&chunkIdent, binary.Size(chunkIdent))
	if err != nil {
		return "", 0, err
	}
	ident = string(chunkIdent[:])

	// Read chunk length
	err = d.bRead(&length, binary.Size(length))
	if err != nil {
		return "", 0, err
	}
	return
}

func (d *decoder) Seek(sample uint64) error {
	rs, ok := d.r.(io.ReadSeeker)
	if ok {
		offset := int64(sample * (uint64(d.bitsPerSample) / 8))
		_, err := rs.Seek(int64(d.dataChunkBegin)+offset, 0)
		if err != nil {
			return err
		}
	}
	return nil
}

func (d *decoder) readPCM8(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM8Samples)

	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		var sample audio.PCM8

		err = d.bRead(&sample, 1) // 1 == binary.Size(sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = sample
		} else {
			f64 := audio.PCM8ToF64(sample)
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readPCM16(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM16Samples)

	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		var sample audio.PCM16

		err = d.bRead(&sample, 2) // 2 == binary.Size(sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = sample
		} else {
			f64 := audio.PCM16ToF64(sample)
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readPCM24(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM32Samples)

	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		var sample [3]uint8

		err = d.bRead(&sample, 3) // 3 == binary.Size(sample)
		if err != nil {
			return
		}

		var ss audio.PCM32
		ss = audio.PCM32(sample[0]) | audio.PCM32(sample[1])<<8 | audio.PCM32(sample[2])<<16
		if (ss & 0x800000) > 0 {
			ss |= ^0xffffff
		}

		if bbOk {
			bb[read] = ss
		} else {
			f64 := audio.PCM32ToF64(ss)
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readPCM32(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM32Samples)

	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		var sample audio.PCM32

		err = d.bRead(&sample, 4) // 4 == binary.Size(sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = sample
		} else {
			f64 := audio.PCM32ToF64(sample)
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readF32(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.F32Samples)

	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		var sample audio.F32

		err = d.bRead(&sample, 4) // 4 == binary.Size(sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = sample
		} else {
			b.Set(read, audio.F64(sample))
		}
	}

	return
}

func (d *decoder) readF64(b audio.Slice) (read int, err error) {
	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		var sample audio.F64

		err = d.bRead(&sample, 8) // 8 == binary.Size(sample))
		if err != nil {
			return
		}

		b.Set(read, sample)
	}

	return
}

func (d *decoder) readMuLaw(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.MuLawSamples)

	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		var sample audio.MuLaw

		err = d.bRead(&sample, 1) // 1 == binary.Size(sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = sample
		} else {
			p16 := audio.MuLawToPCM16(sample)
			b.Set(read, audio.PCM16ToF64(p16))
		}
	}

	return
}

func (d *decoder) readALaw(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.ALawSamples)

	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		var sample audio.ALaw

		err = d.bRead(&sample, 1) // 1 == binary.Size(sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = sample
		} else {
			p16 := audio.ALawToPCM16(sample)
			b.Set(read, audio.PCM16ToF64(p16))
		}
	}

	return
}

func (d *decoder) Read(b audio.Slice) (read int, err error) {
	if b.Len() == 0 {
		return
	}

	d.access.Lock()
	defer d.access.Unlock()

	switch d.format {
	case wave_FORMAT_PCM:
		switch d.bitsPerSample {
		case 8:
			return d.readPCM8(b)
		case 16:
			return d.readPCM16(b)
		case 24:
			return d.readPCM24(b)
		case 32:
			return d.readPCM32(b)
		}

	case wave_FORMAT_IEEE_FLOAT:
		switch d.bitsPerSample {
		case 32:
			return d.readF32(b)
		case 64:
			return d.readF64(b)
		}

	case wave_FORMAT_MULAW:
		return d.readMuLaw(b)

	case wave_FORMAT_ALAW:
		return d.readALaw(b)
	}
	return
}

func (d *decoder) Config() audio.Config {
	d.access.RLock()
	defer d.access.RUnlock()

	return *d.config
}

// ErrUnsupported defines an error for decoding wav data that is valid (by the
// wave specification) but not supported by the decoder in this package.
//
// This error only happens for audio files containing extensible wav data.
var ErrUnsupported = errors.New("wav: data format is valid but not supported by decoder")

// NewDecoder returns a new initialized audio decoder for the io.Reader or
// io.ReadSeeker, r.
func newDecoder(r interface{}) (audio.Decoder, error) {
	d := new(decoder)
	d.r = r

	switch t := r.(type) {
	case io.Reader:
		d.rd = t
	case io.ReadSeeker:
		d.rd = io.Reader(t)
	default:
		panic("NewDecoder(): Invalid reader type; must be io.Reader or io.ReadSeeker!")
	}

	var (
		complete bool

		c16 fmtChunk16
		c18 fmtChunk18
		c40 fmtChunk40
	)
	for !complete {
		ident, length, err := d.nextChunk()
		if err != nil {
			return nil, err
		}

		switch ident {
		case "RIFF":
			var format [4]byte
			err = d.bRead(&format, binary.Size(format))
			if string(format[:]) != "WAVE" {
				return nil, audio.ErrInvalidData
			}

		case "fmt ":
			// Always contains the 16-byte chunk
			err = d.bRead(&c16, binary.Size(c16))
			if err != nil {
				return nil, err
			}
			d.bitsPerSample = c16.BitsPerSample

			// Sometimes contains extensive 18/40 total byte chunks
			switch length {
			case 18:
				err = d.bRead(&c18, binary.Size(c18))
				if err != nil {
					return nil, err
				}
			case 40:
				err = d.bRead(&c40, binary.Size(c40))
				if err != nil {
					return nil, err
				}
			}

			// Verify format tag
			ft := c16.FormatTag
			switch {
			case ft == wave_FORMAT_PCM && (d.bitsPerSample == 8 || d.bitsPerSample == 16 || d.bitsPerSample == 24 || d.bitsPerSample == 32):
				break
			case ft == wave_FORMAT_IEEE_FLOAT && (d.bitsPerSample == 32 || d.bitsPerSample == 64):
				break
			case ft == wave_FORMAT_ALAW && d.bitsPerSample == 8:
				break
			case ft == wave_FORMAT_MULAW && d.bitsPerSample == 8:
				break
			// We don't support extensible wav files
			//case wave_FORMAT_EXTENSIBLE:
			//	break
			default:
				return nil, ErrUnsupported
			}

			// Assign format tag for later (See Read() method)
			d.format = c16.FormatTag

			// We now have enough information to build the audio configuration
			d.config = &audio.Config{
				Channels:   int(c16.Channels),
				SampleRate: int(c16.SamplesPerSec),
			}

		case "fact":
			// We need to scan fact chunk first.
			var fact factChunk
			err = d.bRead(&fact, binary.Size(fact))
			if err != nil {
				return nil, err
			}

		case "data":
			// Read the data chunk header now
			d.chunkSize = length
			complete = true
		}
	}

	return d, nil
}

func init() {
	audio.RegisterFormat("wav", "RIFF", newDecoder)
}
<commit_msg>Improve decoder performance by 9-11%. See azul3d/audio#5<commit_after>// Copyright 2014 The Azul3D 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 wav

import (
	"encoding/binary"
	"errors"
	"io"
	"sync"

	"azul3d.org/audio.v1"
)

const (
	// Data format codes

	// PCM
	wave_FORMAT_PCM = 0x0001

	// IEEE float
	wave_FORMAT_IEEE_FLOAT = 0x0003

	// 8-bit ITU-T G.711 A-law
	wave_FORMAT_ALAW = 0x0006

	// 8-bit ITU-T G.711 µ-law
	wave_FORMAT_MULAW = 0x0007

	// Determined by SubFormat
	wave_FORMAT_EXTENSIBLE = 0xFFFE
)

type decoder struct {
	access sync.RWMutex

	format, bitsPerSample   uint16
	chunkSize, currentCount uint32
	dataChunkBegin          int32

	r      interface{}
	rd     io.Reader
	config *audio.Config
}

// advance advances the byte counter by sz. If the chunk size is known and
// after advancement the byte counter is larger than the chunk size, then
// audio.EOS is returned.
//
// If the chunk size is not known, the data chunk marker is extended by sz as
// well.
func (d *decoder) advance(sz int) error {
	d.currentCount += uint32(sz)
	if d.chunkSize > 0 {
		if d.currentCount > d.chunkSize {
			return audio.EOS
		}
	} else {
		d.dataChunkBegin += int32(sz)
	}
	return nil
}

func (d *decoder) bRead(data interface{}, sz int) error {
	err := d.advance(sz)
	if err != nil {
		return err
	}
	return binary.Read(d.rd, binary.LittleEndian, data)
}

// Reads and returns the next RIFF chunk, note that always len(ident) == 4
// E.g.
//
//  "fmt " (notice space).
//
// Length is length of chunk data.
//
// Returns any read errors.
func (d *decoder) nextChunk() (ident string, length uint32, err error) {
	// Read chunk identity, like "RIFF" or "fmt "
	var chunkIdent [4]byte
	err = d.bRead(&chunkIdent, binary.Size(chunkIdent))
	if err != nil {
		return "", 0, err
	}
	ident = string(chunkIdent[:])

	// Read chunk length
	err = d.bRead(&length, binary.Size(length))
	if err != nil {
		return "", 0, err
	}
	return
}

func (d *decoder) Seek(sample uint64) error {
	rs, ok := d.r.(io.ReadSeeker)
	if ok {
		offset := int64(sample * (uint64(d.bitsPerSample) / 8))
		_, err := rs.Seek(int64(d.dataChunkBegin)+offset, 0)
		if err != nil {
			return err
		}
	}
	return nil
}

func (d *decoder) readPCM8(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM8Samples)

	var sample audio.PCM8
	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		err = d.bRead(&sample, 1) // 1 == binary.Size(sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = sample
		} else {
			f64 := audio.PCM8ToF64(sample)
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readPCM16(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM16Samples)

	var sample audio.PCM16
	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		err = d.bRead(&sample, 2) // 2 == binary.Size(sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = sample
		} else {
			f64 := audio.PCM16ToF64(sample)
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readPCM24(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM32Samples)

	var sample [3]uint8
	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		err = d.bRead(&sample, 3) // 3 == binary.Size(sample)
		if err != nil {
			return
		}

		var ss audio.PCM32
		ss = audio.PCM32(sample[0]) | audio.PCM32(sample[1])<<8 | audio.PCM32(sample[2])<<16
		if (ss & 0x800000) > 0 {
			ss |= ^0xffffff
		}

		if bbOk {
			bb[read] = ss
		} else {
			f64 := audio.PCM32ToF64(ss)
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readPCM32(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.PCM32Samples)

	var sample audio.PCM32
	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		err = d.bRead(&sample, 4) // 4 == binary.Size(sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = sample
		} else {
			f64 := audio.PCM32ToF64(sample)
			b.Set(read, f64)
		}
	}

	return
}

func (d *decoder) readF32(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.F32Samples)

	var sample audio.F32
	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		err = d.bRead(&sample, 4) // 4 == binary.Size(sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = sample
		} else {
			b.Set(read, audio.F64(sample))
		}
	}

	return
}

func (d *decoder) readF64(b audio.Slice) (read int, err error) {
	var sample audio.F64
	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		err = d.bRead(&sample, 8) // 8 == binary.Size(sample))
		if err != nil {
			return
		}

		b.Set(read, sample)
	}

	return
}

func (d *decoder) readMuLaw(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.MuLawSamples)

	var sample audio.MuLaw
	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		err = d.bRead(&sample, 1) // 1 == binary.Size(sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = sample
		} else {
			p16 := audio.MuLawToPCM16(sample)
			b.Set(read, audio.PCM16ToF64(p16))
		}
	}

	return
}

func (d *decoder) readALaw(b audio.Slice) (read int, err error) {
	bb, bbOk := b.(audio.ALawSamples)

	var sample audio.ALaw
	for read = 0; read < b.Len(); read++ {
		// Pull one sample from the data stream
		err = d.bRead(&sample, 1) // 1 == binary.Size(sample)
		if err != nil {
			return
		}

		if bbOk {
			bb[read] = sample
		} else {
			p16 := audio.ALawToPCM16(sample)
			b.Set(read, audio.PCM16ToF64(p16))
		}
	}

	return
}

func (d *decoder) Read(b audio.Slice) (read int, err error) {
	if b.Len() == 0 {
		return
	}

	d.access.Lock()
	defer d.access.Unlock()

	switch d.format {
	case wave_FORMAT_PCM:
		switch d.bitsPerSample {
		case 8:
			return d.readPCM8(b)
		case 16:
			return d.readPCM16(b)
		case 24:
			return d.readPCM24(b)
		case 32:
			return d.readPCM32(b)
		}

	case wave_FORMAT_IEEE_FLOAT:
		switch d.bitsPerSample {
		case 32:
			return d.readF32(b)
		case 64:
			return d.readF64(b)
		}

	case wave_FORMAT_MULAW:
		return d.readMuLaw(b)

	case wave_FORMAT_ALAW:
		return d.readALaw(b)
	}
	return
}

func (d *decoder) Config() audio.Config {
	d.access.RLock()
	defer d.access.RUnlock()

	return *d.config
}

// ErrUnsupported defines an error for decoding wav data that is valid (by the
// wave specification) but not supported by the decoder in this package.
//
// This error only happens for audio files containing extensible wav data.
var ErrUnsupported = errors.New("wav: data format is valid but not supported by decoder")

// NewDecoder returns a new initialized audio decoder for the io.Reader or
// io.ReadSeeker, r.
func newDecoder(r interface{}) (audio.Decoder, error) {
	d := new(decoder)
	d.r = r

	switch t := r.(type) {
	case io.Reader:
		d.rd = t
	case io.ReadSeeker:
		d.rd = io.Reader(t)
	default:
		panic("NewDecoder(): Invalid reader type; must be io.Reader or io.ReadSeeker!")
	}

	var (
		complete bool

		c16 fmtChunk16
		c18 fmtChunk18
		c40 fmtChunk40
	)
	for !complete {
		ident, length, err := d.nextChunk()
		if err != nil {
			return nil, err
		}

		switch ident {
		case "RIFF":
			var format [4]byte
			err = d.bRead(&format, binary.Size(format))
			if string(format[:]) != "WAVE" {
				return nil, audio.ErrInvalidData
			}

		case "fmt ":
			// Always contains the 16-byte chunk
			err = d.bRead(&c16, binary.Size(c16))
			if err != nil {
				return nil, err
			}
			d.bitsPerSample = c16.BitsPerSample

			// Sometimes contains extensive 18/40 total byte chunks
			switch length {
			case 18:
				err = d.bRead(&c18, binary.Size(c18))
				if err != nil {
					return nil, err
				}
			case 40:
				err = d.bRead(&c40, binary.Size(c40))
				if err != nil {
					return nil, err
				}
			}

			// Verify format tag
			ft := c16.FormatTag
			switch {
			case ft == wave_FORMAT_PCM && (d.bitsPerSample == 8 || d.bitsPerSample == 16 || d.bitsPerSample == 24 || d.bitsPerSample == 32):
				break
			case ft == wave_FORMAT_IEEE_FLOAT && (d.bitsPerSample == 32 || d.bitsPerSample == 64):
				break
			case ft == wave_FORMAT_ALAW && d.bitsPerSample == 8:
				break
			case ft == wave_FORMAT_MULAW && d.bitsPerSample == 8:
				break
			// We don't support extensible wav files
			//case wave_FORMAT_EXTENSIBLE:
			//	break
			default:
				return nil, ErrUnsupported
			}

			// Assign format tag for later (See Read() method)
			d.format = c16.FormatTag

			// We now have enough information to build the audio configuration
			d.config = &audio.Config{
				Channels:   int(c16.Channels),
				SampleRate: int(c16.SamplesPerSec),
			}

		case "fact":
			// We need to scan fact chunk first.
			var fact factChunk
			err = d.bRead(&fact, binary.Size(fact))
			if err != nil {
				return nil, err
			}

		case "data":
			// Read the data chunk header now
			d.chunkSize = length
			complete = true
		}
	}

	return d, nil
}

func init() {
	audio.RegisterFormat("wav", "RIFF", newDecoder)
}
<|endoftext|>


<commit_before>package wellington

import (
	"bytes"
	"encoding/json"
	"errors"
	"log"
	"net/http"
	"path/filepath"
	"time"

	libsass "github.com/wellington/go-libsass"
	"github.com/wellington/wellington/version"
)

// FileHandler starts a file server serving files out of the specified
// build directory.
func FileHandler(gen string) http.Handler {
	abs, err := filepath.Abs(gen)
	if err != nil {
		log.Fatalf("Can not resolve relative path: %s", gen)
	}

	return http.StripPrefix("/build/",
		http.FileServer(http.Dir(abs)),
	)
}

// Response is the object returned on HTTP responses from wellington
type Response struct {
	Contents string    `json:"contents"`
	Start    time.Time `json:"start"`
	Elapsed  string    `json:"elapsed"`
	Error    string    `json:"error"`
	Version  string    `json:"version"`
}

func setDefaultHeaders(w http.ResponseWriter, r *http.Request) {
	// Set headers
	if origin := r.Header.Get("Origin"); origin != "" {
		w.Header().Set("Access-Control-Allow-Origin", origin)
	}
	w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token")
	w.Header().Set("Access-Control-Allow-Credentials", "true")
}

// HTTPHandler starts a CORS enabled web server that takes as input
// Sass and outputs CSS.
func HTTPHandler(gba *BuildArgs, httpPath string) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		setDefaultHeaders(w, r)
		start := time.Now()
		resp := Response{
			Start:   start,
			Version: version.Version,
		}
		var (
			err  error
			pout bytes.Buffer
		)
		enc := json.NewEncoder(w)
		defer func() {
			resp.Contents = pout.String()
			resp.Elapsed = time.Since(start).String()
			if err != nil {
				resp.Error = err.Error()
			}
			enc.Encode(resp)
		}()
		if r.Body == nil {
			err = errors.New("request is empty")
			return
		}
		defer r.Body.Close()

		comp, err := FromBuildArgs(&pout, r.Body, gba)
		if err != nil {
			resp.Contents = ""
			return
		}
		comp.Options(libsass.HTTPPath(httpPath))
		err = comp.Run()
	}
}
<commit_msg>renamed Options<commit_after>package wellington

import (
	"bytes"
	"encoding/json"
	"errors"
	"log"
	"net/http"
	"path/filepath"
	"time"

	libsass "github.com/wellington/go-libsass"
	"github.com/wellington/wellington/version"
)

// FileHandler starts a file server serving files out of the specified
// build directory.
func FileHandler(gen string) http.Handler {
	abs, err := filepath.Abs(gen)
	if err != nil {
		log.Fatalf("Can not resolve relative path: %s", gen)
	}

	return http.StripPrefix("/build/",
		http.FileServer(http.Dir(abs)),
	)
}

// Response is the object returned on HTTP responses from wellington
type Response struct {
	Contents string    `json:"contents"`
	Start    time.Time `json:"start"`
	Elapsed  string    `json:"elapsed"`
	Error    string    `json:"error"`
	Version  string    `json:"version"`
}

func setDefaultHeaders(w http.ResponseWriter, r *http.Request) {
	// Set headers
	if origin := r.Header.Get("Origin"); origin != "" {
		w.Header().Set("Access-Control-Allow-Origin", origin)
	}
	w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token")
	w.Header().Set("Access-Control-Allow-Credentials", "true")
}

// HTTPHandler starts a CORS enabled web server that takes as input
// Sass and outputs CSS.
func HTTPHandler(gba *BuildArgs, httpPath string) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		setDefaultHeaders(w, r)
		start := time.Now()
		resp := Response{
			Start:   start,
			Version: version.Version,
		}
		var (
			err  error
			pout bytes.Buffer
		)
		enc := json.NewEncoder(w)
		defer func() {
			resp.Contents = pout.String()
			resp.Elapsed = time.Since(start).String()
			if err != nil {
				resp.Error = err.Error()
			}
			enc.Encode(resp)
		}()
		if r.Body == nil {
			err = errors.New("request is empty")
			return
		}
		defer r.Body.Close()

		comp, err := FromBuildArgs(&pout, r.Body, gba)
		if err != nil {
			resp.Contents = ""
			return
		}
		comp.Option(libsass.HTTPPath(httpPath))
		err = comp.Run()
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 The Cockroach 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. See the AUTHORS file
// for names of contributors.
//
// Author: Marc Berhault (marc@cockroachlabs.com)

package docker

import (
	"fmt"
	"os"
	"os/exec"
	"strings"

	"github.com/cockroachdb/cockroach-prod/drivers"
	"github.com/cockroachdb/cockroach/util"
	"github.com/cockroachdb/cockroach/util/log"
)

const (
	dockerVersionStringPrefix = "Docker version "
)

// CheckDocker verifies that docker-machine is installed and runnable.
func CheckDocker() error {
	cmd := exec.Command("docker", "-v")
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	out, err := cmd.Output()
	if err != nil {
		return err
	}
	if !strings.HasPrefix(string(out), dockerVersionStringPrefix) {
		return util.Errorf("bad output %s for docker -v, expected string prefix %q",
			out, dockerVersionStringPrefix)
	}
	return nil
}

// RunDockerInit initializes the first node.
func RunDockerInit(driver drivers.Driver, nodeName string, settings *drivers.HostConfig) error {
	dockerArgs, err := GetDockerFlags(nodeName)
	if err != nil {
		return err
	}
	args := dockerArgs
	args = append(args,
		"run",
		"--rm",
		"-v", fmt.Sprintf("%s:/data", settings.Driver.DataDir()),
		"cockroachdb/cockroach",
		"init",
		"--stores=ssd=/data",
	)
	log.Infof("running: docker %s", strings.Join(args, " "))
	cmd := exec.Command("docker", args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

// RunDockerStart starts the cockroach binary.
func RunDockerStart(driver drivers.Driver, nodeName string, settings *drivers.HostConfig) error {
	dockerArgs, err := GetDockerFlags(nodeName)
	if err != nil {
		return err
	}
	port := driver.Context().Port
	args := dockerArgs
	args = append(args,
		"run",
		"-d",
		"-v", fmt.Sprintf("%s:/data", settings.Driver.DataDir()),
		"-p", fmt.Sprintf("%d:%d", port, port),
		"--net", "host",
		"cockroachdb/cockroach",
		"start",
		"--insecure",
		"--stores=ssd=/data",
		// TODO(marc): we may need ip:port for TLS. Use settings.Driver.IPAddress()
		// For now, it causes problems with GCE's network forwarding, so skip it.
		fmt.Sprintf("--addr=:%d", port),
		fmt.Sprintf("--gossip=%s:%d", settings.Driver.GossipAddress(), port),
	)
	log.Infof("running: docker %s", strings.Join(args, " "))
	cmd := exec.Command("docker", args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}
<commit_msg>Use http-lb gossip spec<commit_after>// Copyright 2015 The Cockroach 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. See the AUTHORS file
// for names of contributors.
//
// Author: Marc Berhault (marc@cockroachlabs.com)

package docker

import (
	"fmt"
	"os"
	"os/exec"
	"strings"

	"github.com/cockroachdb/cockroach-prod/drivers"
	"github.com/cockroachdb/cockroach/util"
	"github.com/cockroachdb/cockroach/util/log"
)

const (
	dockerVersionStringPrefix = "Docker version "
)

// CheckDocker verifies that docker-machine is installed and runnable.
func CheckDocker() error {
	cmd := exec.Command("docker", "-v")
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	out, err := cmd.Output()
	if err != nil {
		return err
	}
	if !strings.HasPrefix(string(out), dockerVersionStringPrefix) {
		return util.Errorf("bad output %s for docker -v, expected string prefix %q",
			out, dockerVersionStringPrefix)
	}
	return nil
}

// RunDockerInit initializes the first node.
func RunDockerInit(driver drivers.Driver, nodeName string, settings *drivers.HostConfig) error {
	dockerArgs, err := GetDockerFlags(nodeName)
	if err != nil {
		return err
	}
	args := dockerArgs
	args = append(args,
		"run",
		"--rm",
		"-v", fmt.Sprintf("%s:/data", settings.Driver.DataDir()),
		"cockroachdb/cockroach",
		"init",
		"--stores=ssd=/data",
	)
	log.Infof("running: docker %s", strings.Join(args, " "))
	cmd := exec.Command("docker", args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

// RunDockerStart starts the cockroach binary.
func RunDockerStart(driver drivers.Driver, nodeName string, settings *drivers.HostConfig) error {
	dockerArgs, err := GetDockerFlags(nodeName)
	if err != nil {
		return err
	}
	port := driver.Context().Port
	args := dockerArgs
	args = append(args,
		"run",
		"-d",
		"-v", fmt.Sprintf("%s:/data", settings.Driver.DataDir()),
		"-p", fmt.Sprintf("%d:%d", port, port),
		"--net", "host",
		"cockroachdb/cockroach",
		"start",
		"--insecure",
		"--stores=ssd=/data",
		// TODO(marc): we may need ip:port for TLS. Use settings.Driver.IPAddress()
		// For now, it causes problems with GCE's network forwarding, so skip it.
		fmt.Sprintf("--addr=:%d", port),
		// TODO(marc): remove localhost once we serve /_status/ before
		// joining the gossip network.
		fmt.Sprintf("--gossip=localhost:%d,http-lb=%s:%d", port, settings.Driver.GossipAddress(), port),
	)
	log.Infof("running: docker %s", strings.Join(args, " "))
	cmd := exec.Command("docker", args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}
<|endoftext|>


<commit_before>package gncp

import (
	"errors"
	"fmt"
	"net"
	"sync"
	"time"
)

type ConnPool interface {
	Get() (net.Conn, error)
	GetWithTimeout(timeout time.Duration) (net.Conn, error)
	Close() error
	Remove(conn net.Conn) error
}

type GncpPool struct {
	lock         sync.Mutex
	conns        chan net.Conn
	minConnNum   int
	maxConnNum   int
	totalConnNum int
	closed       bool
	connCreator  func() (net.Conn, error)
}

var (
	PoolIsCloseError = errors.New("Connection pool has been closed.")
	TimeOutError     = errors.New("Get Connection timeout.")
)

// NewPool return new ConnPool. It base on channel. It will init minConn connections in channel first.
// When Get()/GetWithTimeout called, if channel still has connection it will get connection from channel.
// Otherwise GncpPool will check number of connection already created,if the number less than maxConn,
// it use connCreator function to create new connection.
func NewPool(minConn, maxConn int, connCreator func() (net.Conn, error)) (*GncpPool, error) {
	if minConn > maxConn || minConn < 0 || maxConn <= 0 {
		return nil, errors.New("Number of connection bound error.")
	}

	pool := &GncpPool{}
	pool.minConnNum = minConn
	pool.maxConnNum = maxConn
	pool.connCreator = connCreator
	pool.conns = make(chan net.Conn, maxConn)
	pool.closed = false
	pool.totalConnNum = 0
	err := pool.init()
	if err != nil {
		return nil, err
	}
	return pool, nil
}

func (p *GncpPool) init() error {
	for i := 0; i < p.minConnNum; i++ {
		conn, err := p.createConn()
		if err != nil {
			return err
		}
		p.conns <- conn
	}
	return nil
}

// Get get connection from connection pool. If connection poll is empty and alreay created connection number less than Max number of connection
// it will create new one. Otherwise it wil wait someone put connection back.
func (p *GncpPool) Get() (net.Conn, error) {
	if p.isClosed() == true {
		return nil, PoolIsCloseError
	}
	go func() {
		conn, err := p.createConn()
		if err != nil {
			return
		}
		p.conns <- conn
	}()
	select {
	case conn := <-p.conns:
		return p.packConn(conn), nil
	}
}

// GetWithTimeout can let you get connection wait for a time duration. If cannot get connection in this time.
// It will return TimeOutError.
func (p *GncpPool) GetWithTimeout(timeout time.Duration) (net.Conn, error) {
	if p.isClosed() == true {
		return nil, PoolIsCloseError
	}
	go func() {
		conn, err := p.createConn()
		if err != nil {
			return
		}
		p.conns <- conn
	}()
	select {
	case conn := <-p.conns:
		return p.packConn(conn), nil
	case <-time.After(timeout):
		return nil, TimeOutError
	}
}

// Close close the connection pool. When close the connection pool it also close all connection already in connection pool.
// If connection not put back in connection it will not close. But it will close when it put back.
func (p *GncpPool) Close() error {
	if p.isClosed() == true {
		return PoolIsCloseError
	}
	p.lock.Lock()
	defer p.lock.Unlock()
	p.closed = true
	close(p.conns)
	for conn := range p.conns {
		conn.Close()
	}
	return nil
}

// Put can put connection back in connection pool. If connection has been closed, the conneciton will be close too.
func (p *GncpPool) Put(conn net.Conn) error {
	if p.isClosed() == true {
		return PoolIsCloseError
	}
	if conn == nil {
		p.lock.Lock()
		p.totalConnNum = p.totalConnNum - 1
		p.lock.Unlock()
		return errors.New("Cannot put nil to connection pool.")
	}

	select {
	case p.conns <- conn:
		return nil
	default:
		return conn.Close()
	}
}

func (p *GncpPool) isClosed() bool {
	p.lock.Lock()
	ret := p.closed
	p.lock.Unlock()
	return ret
}

// RemoveConn let connection not belong connection pool.And it will close connection.
func (p *GncpPool) Remove(conn net.Conn) error {
	if p.isClosed() == true {
		return PoolIsCloseError
	}

	p.lock.Lock()
	p.totalConnNum = p.totalConnNum - 1
	p.lock.Unlock()
	switch conn.(type) {
	case *CpConn:
		return conn.(*CpConn).Destroy()
	default:
		return conn.Close()
	}
	return nil
}

// createConn will create one connection from connCreator. And increase connection counter.
func (p *GncpPool) createConn() (net.Conn, error) {
	p.lock.Lock()
	defer p.lock.Unlock()
	if p.totalConnNum >= p.maxConnNum {
		return nil, fmt.Errorf("Connot Create new connection. Now has %d.Max is %d", p.totalConnNum, p.maxConnNum)
	}
	conn, err := p.connCreator()
	if err != nil {
		return nil, fmt.Errorf("Cannot create new connection.%s", err)
	}
	p.totalConnNum = p.totalConnNum + 1
	return conn, nil
}

func (p *GncpPool) packConn(conn net.Conn) net.Conn {
	ret := &CpConn{pool: p}
	ret.Conn = conn
	return ret
}
<commit_msg>Update some comment.<commit_after>package gncp

import (
	"errors"
	"fmt"
	"net"
	"sync"
	"time"
)

type ConnPool interface {
	Get() (net.Conn, error)
	GetWithTimeout(timeout time.Duration) (net.Conn, error)
	Close() error
	Remove(conn net.Conn) error
}

// GncpPool implements ConnPool interface. Use channel buffer connections.
type GncpPool struct {
	lock         sync.Mutex
	conns        chan net.Conn
	minConnNum   int
	maxConnNum   int
	totalConnNum int
	closed       bool
	connCreator  func() (net.Conn, error)
}

var (
	PoolIsCloseError = errors.New("Connection pool has been closed.")
	// Error for get connection time out.
	TimeOutError = errors.New("Get Connection timeout.")
)

// NewPool return new ConnPool. It base on channel. It will init minConn connections in channel first.
// When Get()/GetWithTimeout called, if channel still has connection it will get connection from channel.
// Otherwise GncpPool will check number of connection already created,if the number less than maxConn,
// it use connCreator function to create new connection.
func NewPool(minConn, maxConn int, connCreator func() (net.Conn, error)) (*GncpPool, error) {
	if minConn > maxConn || minConn < 0 || maxConn <= 0 {
		return nil, errors.New("Number of connection bound error.")
	}

	pool := &GncpPool{}
	pool.minConnNum = minConn
	pool.maxConnNum = maxConn
	pool.connCreator = connCreator
	pool.conns = make(chan net.Conn, maxConn)
	pool.closed = false
	pool.totalConnNum = 0
	err := pool.init()
	if err != nil {
		return nil, err
	}
	return pool, nil
}

func (p *GncpPool) init() error {
	for i := 0; i < p.minConnNum; i++ {
		conn, err := p.createConn()
		if err != nil {
			return err
		}
		p.conns <- conn
	}
	return nil
}

// Get get connection from connection pool. If connection poll is empty and alreay created connection number less than Max number of connection
// it will create new one. Otherwise it wil wait someone put connection back.
func (p *GncpPool) Get() (net.Conn, error) {
	if p.isClosed() == true {
		return nil, PoolIsCloseError
	}
	go func() {
		conn, err := p.createConn()
		if err != nil {
			return
		}
		p.conns <- conn
	}()
	select {
	case conn := <-p.conns:
		return p.packConn(conn), nil
	}
}

// GetWithTimeout can let you get connection wait for a time duration. If cannot get connection in this time.
// It will return TimeOutError.
func (p *GncpPool) GetWithTimeout(timeout time.Duration) (net.Conn, error) {
	if p.isClosed() == true {
		return nil, PoolIsCloseError
	}
	go func() {
		conn, err := p.createConn()
		if err != nil {
			return
		}
		p.conns <- conn
	}()
	select {
	case conn := <-p.conns:
		return p.packConn(conn), nil
	case <-time.After(timeout):
		return nil, TimeOutError
	}
}

// Close close the connection pool. When close the connection pool it also close all connection already in connection pool.
// If connection not put back in connection it will not close. But it will close when it put back.
func (p *GncpPool) Close() error {
	if p.isClosed() == true {
		return PoolIsCloseError
	}
	p.lock.Lock()
	defer p.lock.Unlock()
	p.closed = true
	close(p.conns)
	for conn := range p.conns {
		conn.Close()
	}
	return nil
}

// Put can put connection back in connection pool. If connection has been closed, the conneciton will be close too.
func (p *GncpPool) Put(conn net.Conn) error {
	if p.isClosed() == true {
		return PoolIsCloseError
	}
	if conn == nil {
		p.lock.Lock()
		p.totalConnNum = p.totalConnNum - 1
		p.lock.Unlock()
		return errors.New("Cannot put nil to connection pool.")
	}

	select {
	case p.conns <- conn:
		return nil
	default:
		return conn.Close()
	}
}

func (p *GncpPool) isClosed() bool {
	p.lock.Lock()
	ret := p.closed
	p.lock.Unlock()
	return ret
}

// RemoveConn let connection not belong connection pool.And it will close connection.
func (p *GncpPool) Remove(conn net.Conn) error {
	if p.isClosed() == true {
		return PoolIsCloseError
	}

	p.lock.Lock()
	p.totalConnNum = p.totalConnNum - 1
	p.lock.Unlock()
	switch conn.(type) {
	case *CpConn:
		return conn.(*CpConn).Destroy()
	default:
		return conn.Close()
	}
	return nil
}

// createConn will create one connection from connCreator. And increase connection counter.
func (p *GncpPool) createConn() (net.Conn, error) {
	p.lock.Lock()
	defer p.lock.Unlock()
	if p.totalConnNum >= p.maxConnNum {
		return nil, fmt.Errorf("Connot Create new connection. Now has %d.Max is %d", p.totalConnNum, p.maxConnNum)
	}
	conn, err := p.connCreator()
	if err != nil {
		return nil, fmt.Errorf("Cannot create new connection.%s", err)
	}
	p.totalConnNum = p.totalConnNum + 1
	return conn, nil
}

func (p *GncpPool) packConn(conn net.Conn) net.Conn {
	ret := &CpConn{pool: p}
	ret.Conn = conn
	return ret
}
<|endoftext|>