<commit_before>// +build !solaris

package logparser

import (
	"fmt"
	"log"
	"reflect"
	"strings"
	"sync"

	"github.com/influxdata/tail"

	"github.com/influxdata/telegraf"
	"github.com/influxdata/telegraf/internal/globpath"
	"github.com/influxdata/telegraf/plugins/inputs"

	// Parsers
	"github.com/influxdata/telegraf/plugins/inputs/logparser/grok"
)

const (
	defaultWatchMethod = "inotify"
)

// LogParser in the primary interface for the plugin
type LogParser interface {
	ParseLine(line string) (telegraf.Metric, error)
	Compile() error
}

type logEntry struct {
	path string
	line string
}

// LogParserPlugin is the primary struct to implement the interface for logparser plugin
type LogParserPlugin struct {
	Files         []string
	FromBeginning bool
	WatchMethod   string

	tailers map[string]*tail.Tail
	lines   chan logEntry
	done    chan struct{}
	wg      sync.WaitGroup
	acc     telegraf.Accumulator
	parsers []LogParser

	sync.Mutex

	GrokParser *grok.Parser `toml:"grok"`
}

const sampleConfig = `
  ## Log files to parse.
  ## These accept standard unix glob matching rules, but with the addition of
  ## ** as a "super asterisk". ie:
  ##   /var/log/**.log     -> recursively find all .log files in /var/log
  ##   /var/log/*/*.log    -> find all .log files with a parent dir in /var/log
  ##   /var/log/apache.log -> only tail the apache log file
  files = ["/var/log/apache/access.log"]

  ## Read files that currently exist from the beginning. Files that are created
  ## while telegraf is running (and that match the "files" globs) will always
  ## be read from the beginning.
  from_beginning = false

  ## Method used to watch for file updates.  Can be either "inotify" or "poll".
  # watch_method = "inotify"

  ## Parse logstash-style "grok" patterns:
  ##   Telegraf built-in parsing patterns: https://goo.gl/dkay10
  [inputs.logparser.grok]
    ## This is a list of patterns to check the given log file(s) for.
    ## Note that adding patterns here increases processing time. The most
    ## efficient configuration is to have one pattern per logparser.
    ## Other common built-in patterns are:
    ##   %{COMMON_LOG_FORMAT}   (plain apache & nginx access logs)
    ##   %{COMBINED_LOG_FORMAT} (access logs + referrer & agent)
    patterns = ["%{COMBINED_LOG_FORMAT}"]

    ## Name of the outputted measurement name.
    measurement = "apache_access_log"

    ## Full path(s) to custom pattern files.
    custom_pattern_files = []

    ## Custom patterns can also be defined here. Put one pattern per line.
    custom_patterns = '''

    ## Timezone allows you to provide an override for timestamps that
    ## don't already include an offset
    ## e.g. 04/06/2016 12:41:45 data one two 5.43µs
    ##
    ## Default: "" which renders UTC
    ## Options are as follows:
    ##   1. Local             -- interpret based on machine localtime
    ##   2. "Canada/Eastern"  -- Unix TZ values like those found in https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
    ##   3. UTC               -- or blank/unspecified, will return timestamp in UTC
    timezone = "Canada/Eastern"
    '''
`

// SampleConfig returns the sample configuration for the plugin
func (l *LogParserPlugin) SampleConfig() string {
	return sampleConfig
}

// Description returns the human readable description for the plugin
func (l *LogParserPlugin) Description() string {
	return "Stream and parse log file(s)."
}

// Gather is the primary function to collect the metrics for the plugin
func (l *LogParserPlugin) Gather(acc telegraf.Accumulator) error {
	l.Lock()
	defer l.Unlock()

	// always start from the beginning of files that appear while we're running
	return l.tailNewfiles(true)
}

// Start kicks off collection of stats for the plugin
func (l *LogParserPlugin) Start(acc telegraf.Accumulator) error {
	l.Lock()
	defer l.Unlock()

	l.acc = acc
	l.lines = make(chan logEntry, 1000)
	l.done = make(chan struct{})
	l.tailers = make(map[string]*tail.Tail)

	// Looks for fields which implement LogParser interface
	l.parsers = []LogParser{}
	s := reflect.ValueOf(l).Elem()
	for i := 0; i < s.NumField(); i++ {
		f := s.Field(i)

		if !f.CanInterface() {
			continue
		}

		if lpPlugin, ok := f.Interface().(LogParser); ok {
			if reflect.ValueOf(lpPlugin).IsNil() {
				continue
			}
			l.parsers = append(l.parsers, lpPlugin)
		}
	}

	if len(l.parsers) == 0 {
		return fmt.Errorf("logparser input plugin: no parser defined")
	}

	// compile log parser patterns:
	for _, parser := range l.parsers {
		if err := parser.Compile(); err != nil {
			return err
		}
	}

	l.wg.Add(1)
	go l.parser()

	return l.tailNewfiles(l.FromBeginning)
}

// check the globs against files on disk, and start tailing any new files.
// Assumes l's lock is held!
func (l *LogParserPlugin) tailNewfiles(fromBeginning bool) error {
	var seek tail.SeekInfo
	if !fromBeginning {
		seek.Whence = 2
		seek.Offset = 0
	}

	var poll bool
	if l.WatchMethod == "poll" {
		poll = true
	}

	// Create a "tailer" for each file
	for _, filepath := range l.Files {
		g, err := globpath.Compile(filepath)
		if err != nil {
			log.Printf("E! Error Glob %s failed to compile, %s", filepath, err)
			continue
		}
		files := g.Match()

		for file := range files {
			if _, ok := l.tailers[file]; ok {
				// we're already tailing this file
				continue
			}

			tailer, err := tail.TailFile(file,
				tail.Config{
					ReOpen:    true,
					Follow:    true,
					Location:  &seek,
					MustExist: true,
					Poll:      poll,
					Logger:    tail.DiscardingLogger,
				})
			if err != nil {
				l.acc.AddError(err)
				continue
			}

			// create a goroutine for each "tailer"
			l.wg.Add(1)
			go l.receiver(tailer)
			l.tailers[file] = tailer
		}
	}

	return nil
}

// receiver is launched as a goroutine to continuously watch a tailed logfile
// for changes and send any log lines down the l.lines channel.
func (l *LogParserPlugin) receiver(tailer *tail.Tail) {
	defer l.wg.Done()

	var line *tail.Line
	for line = range tailer.Lines {

		if line.Err != nil {
			log.Printf("E! Error tailing file %s, Error: %s\n",
				tailer.Filename, line.Err)
			continue
		}

		// Fix up files with Windows line endings.
		text := strings.TrimRight(line.Text, "\r")

		entry := logEntry{
			path: tailer.Filename,
			line: text,
		}

		select {
		case <-l.done:
		case l.lines <- entry:
		}
	}
}

// parser is launched as a goroutine to watch the l.lines channel.
// when a line is available, parser parses it and adds the metric(s) to the
// accumulator.
func (l *LogParserPlugin) parser() {
	defer l.wg.Done()

	var m telegraf.Metric
	var err error
	var entry logEntry
	for {
		select {
		case <-l.done:
			return
		case entry = <-l.lines:
			if entry.line == "" || entry.line == "\n" {
				continue
			}
		}
		for _, parser := range l.parsers {
			m, err = parser.ParseLine(entry.line)
			if err == nil {
				if m != nil {
					tags := m.Tags()
					tags["path"] = entry.path
					l.acc.AddFields(m.Name(), m.Fields(), tags, m.Time())
				}
			} else {
				log.Println("E! Error parsing log line: " + err.Error())
			}
		}
	}
}

// Stop will end the metrics collection process on file tailers
func (l *LogParserPlugin) Stop() {
	l.Lock()
	defer l.Unlock()

	for _, t := range l.tailers {
		err := t.Stop()
		if err != nil {
			log.Printf("E! Error stopping tail on file %s\n", t.Filename)
		}
		t.Cleanup()
	}
	close(l.done)
	l.wg.Wait()
}

func init() {
	inputs.Add("logparser", func() telegraf.Input {
		return &LogParserPlugin{
			WatchMethod: defaultWatchMethod,
		}
	})
}
<commit_msg>Remove dead link from logparser sample config<commit_after>// +build !solaris

package logparser

import (
	"fmt"
	"log"
	"reflect"
	"strings"
	"sync"

	"github.com/influxdata/tail"

	"github.com/influxdata/telegraf"
	"github.com/influxdata/telegraf/internal/globpath"
	"github.com/influxdata/telegraf/plugins/inputs"

	// Parsers
	"github.com/influxdata/telegraf/plugins/inputs/logparser/grok"
)

const (
	defaultWatchMethod = "inotify"
)

// LogParser in the primary interface for the plugin
type LogParser interface {
	ParseLine(line string) (telegraf.Metric, error)
	Compile() error
}

type logEntry struct {
	path string
	line string
}

// LogParserPlugin is the primary struct to implement the interface for logparser plugin
type LogParserPlugin struct {
	Files         []string
	FromBeginning bool
	WatchMethod   string

	tailers map[string]*tail.Tail
	lines   chan logEntry
	done    chan struct{}
	wg      sync.WaitGroup
	acc     telegraf.Accumulator
	parsers []LogParser

	sync.Mutex

	GrokParser *grok.Parser `toml:"grok"`
}

const sampleConfig = `
  ## Log files to parse.
  ## These accept standard unix glob matching rules, but with the addition of
  ## ** as a "super asterisk". ie:
  ##   /var/log/**.log     -> recursively find all .log files in /var/log
  ##   /var/log/*/*.log    -> find all .log files with a parent dir in /var/log
  ##   /var/log/apache.log -> only tail the apache log file
  files = ["/var/log/apache/access.log"]

  ## Read files that currently exist from the beginning. Files that are created
  ## while telegraf is running (and that match the "files" globs) will always
  ## be read from the beginning.
  from_beginning = false

  ## Method used to watch for file updates.  Can be either "inotify" or "poll".
  # watch_method = "inotify"

  ## Parse logstash-style "grok" patterns:
  [inputs.logparser.grok]
    ## This is a list of patterns to check the given log file(s) for.
    ## Note that adding patterns here increases processing time. The most
    ## efficient configuration is to have one pattern per logparser.
    ## Other common built-in patterns are:
    ##   %{COMMON_LOG_FORMAT}   (plain apache & nginx access logs)
    ##   %{COMBINED_LOG_FORMAT} (access logs + referrer & agent)
    patterns = ["%{COMBINED_LOG_FORMAT}"]

    ## Name of the outputted measurement name.
    measurement = "apache_access_log"

    ## Full path(s) to custom pattern files.
    custom_pattern_files = []

    ## Custom patterns can also be defined here. Put one pattern per line.
    custom_patterns = '''

    ## Timezone allows you to provide an override for timestamps that
    ## don't already include an offset
    ## e.g. 04/06/2016 12:41:45 data one two 5.43µs
    ##
    ## Default: "" which renders UTC
    ## Options are as follows:
    ##   1. Local             -- interpret based on machine localtime
    ##   2. "Canada/Eastern"  -- Unix TZ values like those found in https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
    ##   3. UTC               -- or blank/unspecified, will return timestamp in UTC
    timezone = "Canada/Eastern"
    '''
`

// SampleConfig returns the sample configuration for the plugin
func (l *LogParserPlugin) SampleConfig() string {
	return sampleConfig
}

// Description returns the human readable description for the plugin
func (l *LogParserPlugin) Description() string {
	return "Stream and parse log file(s)."
}

// Gather is the primary function to collect the metrics for the plugin
func (l *LogParserPlugin) Gather(acc telegraf.Accumulator) error {
	l.Lock()
	defer l.Unlock()

	// always start from the beginning of files that appear while we're running
	return l.tailNewfiles(true)
}

// Start kicks off collection of stats for the plugin
func (l *LogParserPlugin) Start(acc telegraf.Accumulator) error {
	l.Lock()
	defer l.Unlock()

	l.acc = acc
	l.lines = make(chan logEntry, 1000)
	l.done = make(chan struct{})
	l.tailers = make(map[string]*tail.Tail)

	// Looks for fields which implement LogParser interface
	l.parsers = []LogParser{}
	s := reflect.ValueOf(l).Elem()
	for i := 0; i < s.NumField(); i++ {
		f := s.Field(i)

		if !f.CanInterface() {
			continue
		}

		if lpPlugin, ok := f.Interface().(LogParser); ok {
			if reflect.ValueOf(lpPlugin).IsNil() {
				continue
			}
			l.parsers = append(l.parsers, lpPlugin)
		}
	}

	if len(l.parsers) == 0 {
		return fmt.Errorf("logparser input plugin: no parser defined")
	}

	// compile log parser patterns:
	for _, parser := range l.parsers {
		if err := parser.Compile(); err != nil {
			return err
		}
	}

	l.wg.Add(1)
	go l.parser()

	return l.tailNewfiles(l.FromBeginning)
}

// check the globs against files on disk, and start tailing any new files.
// Assumes l's lock is held!
func (l *LogParserPlugin) tailNewfiles(fromBeginning bool) error {
	var seek tail.SeekInfo
	if !fromBeginning {
		seek.Whence = 2
		seek.Offset = 0
	}

	var poll bool
	if l.WatchMethod == "poll" {
		poll = true
	}

	// Create a "tailer" for each file
	for _, filepath := range l.Files {
		g, err := globpath.Compile(filepath)
		if err != nil {
			log.Printf("E! Error Glob %s failed to compile, %s", filepath, err)
			continue
		}
		files := g.Match()

		for file := range files {
			if _, ok := l.tailers[file]; ok {
				// we're already tailing this file
				continue
			}

			tailer, err := tail.TailFile(file,
				tail.Config{
					ReOpen:    true,
					Follow:    true,
					Location:  &seek,
					MustExist: true,
					Poll:      poll,
					Logger:    tail.DiscardingLogger,
				})
			if err != nil {
				l.acc.AddError(err)
				continue
			}

			// create a goroutine for each "tailer"
			l.wg.Add(1)
			go l.receiver(tailer)
			l.tailers[file] = tailer
		}
	}

	return nil
}

// receiver is launched as a goroutine to continuously watch a tailed logfile
// for changes and send any log lines down the l.lines channel.
func (l *LogParserPlugin) receiver(tailer *tail.Tail) {
	defer l.wg.Done()

	var line *tail.Line
	for line = range tailer.Lines {

		if line.Err != nil {
			log.Printf("E! Error tailing file %s, Error: %s\n",
				tailer.Filename, line.Err)
			continue
		}

		// Fix up files with Windows line endings.
		text := strings.TrimRight(line.Text, "\r")

		entry := logEntry{
			path: tailer.Filename,
			line: text,
		}

		select {
		case <-l.done:
		case l.lines <- entry:
		}
	}
}

// parser is launched as a goroutine to watch the l.lines channel.
// when a line is available, parser parses it and adds the metric(s) to the
// accumulator.
func (l *LogParserPlugin) parser() {
	defer l.wg.Done()

	var m telegraf.Metric
	var err error
	var entry logEntry
	for {
		select {
		case <-l.done:
			return
		case entry = <-l.lines:
			if entry.line == "" || entry.line == "\n" {
				continue
			}
		}
		for _, parser := range l.parsers {
			m, err = parser.ParseLine(entry.line)
			if err == nil {
				if m != nil {
					tags := m.Tags()
					tags["path"] = entry.path
					l.acc.AddFields(m.Name(), m.Fields(), tags, m.Time())
				}
			} else {
				log.Println("E! Error parsing log line: " + err.Error())
			}
		}
	}
}

// Stop will end the metrics collection process on file tailers
func (l *LogParserPlugin) Stop() {
	l.Lock()
	defer l.Unlock()

	for _, t := range l.tailers {
		err := t.Stop()
		if err != nil {
			log.Printf("E! Error stopping tail on file %s\n", t.Filename)
		}
		t.Cleanup()
	}
	close(l.done)
	l.wg.Wait()
}

func init() {
	inputs.Add("logparser", func() telegraf.Input {
		return &LogParserPlugin{
			WatchMethod: defaultWatchMethod,
		}
	})
}
<|endoftext|>


<commit_before>package tftp

import (
	"net"
)

func (s *Server) singlePortProcessRequests() error {
	var (
		localAddr net.IP
		cnt       int
		srcAddr   net.Addr
		err       error
		buf       []byte
	)
	defer func() {
		if r := recover(); r != nil {
			// We've received a new connection on the same IP+Port tuple
			// as a previous connection before garbage collection has occured
			s.handlers[srcAddr.String()] = make(chan []byte)
			go func(localAddr net.IP, remoteAddr *net.UDPAddr, buffer []byte, n, maxBlockLen int, listener chan []byte) {
				err := s.handlePacket(localAddr, remoteAddr, buffer, n, maxBlockLen, listener)
				if err != nil && s.hook != nil {
					s.hook.OnFailure(TransferStats{
						SenderAnticipateEnabled: s.sendAEnable,
					}, err)
				}

			}(localAddr, srcAddr.(*net.UDPAddr), buf, cnt, blockLength, s.handlers[srcAddr.String()])
			s.singlePortProcessRequests()
		}
	}()
	for {
		select {
		case q := <-s.quit:
			q <- struct{}{}
			return nil
		case handlersToFree := <-s.runGC:
			for _, handler := range handlersToFree {
				delete(s.handlers, handler)
			}
		default:
			buf = s.bufPool.Get().([]byte)
			cnt, localAddr, srcAddr, err = s.getPacket(buf)
			if err != nil || cnt == 0 {
				if s.hook != nil {
					s.hook.OnFailure(TransferStats{
						SenderAnticipateEnabled: s.sendAEnable,
					}, err)
				}
				s.bufPool.Put(buf)
				continue
			}
			if receiverChannel, ok := s.handlers[srcAddr.String()]; ok {
				select {
				case receiverChannel <- buf[:cnt]:
				default:
					// We don't want to block the main loop if a channel is full
				}
			} else {
				s.handlers[srcAddr.String()] = make(chan []byte, datagramLength)
				go func(localAddr net.IP, remoteAddr *net.UDPAddr, buffer []byte, n, maxBlockLen int, listener chan []byte) {
					err := s.handlePacket(localAddr, remoteAddr, buffer, n, maxBlockLen, listener)
					if err != nil && s.hook != nil {
						s.hook.OnFailure(TransferStats{
							SenderAnticipateEnabled: s.sendAEnable,
						}, err)
					}

				}(localAddr, srcAddr.(*net.UDPAddr), buf, cnt, blockLength, s.handlers[srcAddr.String()])
			}
		}
	}
}

func (s *Server) getPacket(buf []byte) (int, net.IP, *net.UDPAddr, error) {
	if s.conn6 != nil {
		cnt, control, srcAddr, err := s.conn6.ReadFrom(buf)
		if err != nil || cnt == 0 {
			return 0, nil, nil, err
		}
		var localAddr net.IP
		if control != nil {
			localAddr = control.Dst
		}
		return cnt, localAddr, srcAddr.(*net.UDPAddr), nil
	} else if s.conn4 != nil {
		cnt, control, srcAddr, err := s.conn4.ReadFrom(buf)
		if err != nil || cnt == 0 {
			return 0, nil, nil, err
		}
		var localAddr net.IP
		if control != nil {
			localAddr = control.Dst
		}
		return cnt, localAddr, srcAddr.(*net.UDPAddr), nil
	} else {
		cnt, srcAddr, err := s.conn.ReadFromUDP(buf)
		if err != nil {
			return 0, nil, nil, err
		}
		return cnt, nil, srcAddr, nil
	}
}

// internalGC collects all the finished signals from each connection's goroutine
// The main loop is sent the key to be nil'ed after the gcInterval has passed
func (s *Server) internalGC() {
	var completedHandlers []string
	for {
		select {
		case newHandler := <-s.gcCollect:
			completedHandlers = append(completedHandlers, newHandler)
			if len(completedHandlers) > s.gcThreshold {
				s.runGC <- completedHandlers
				completedHandlers = nil
			}
		}
	}
}
<commit_msg>Support variable blocksize in single port mode<commit_after>package tftp

import (
	"net"
)

func (s *Server) singlePortProcessRequests() error {
	var (
		localAddr  net.IP
		cnt, maxSz int
		srcAddr    net.Addr
		err        error
		buf        []byte
	)
	defer func() {
		if r := recover(); r != nil {
			// We've received a new connection on the same IP+Port tuple
			// as a previous connection before garbage collection has occured
			s.handlers[srcAddr.String()] = make(chan []byte, 1)
			go func(localAddr net.IP, remoteAddr *net.UDPAddr, buffer []byte, n, maxBlockLen int, listener chan []byte) {
				err := s.handlePacket(localAddr, remoteAddr, buffer, n, maxBlockLen, listener)
				if err != nil && s.hook != nil {
					s.hook.OnFailure(TransferStats{
						SenderAnticipateEnabled: s.sendAEnable,
					}, err)
				}

			}(localAddr, srcAddr.(*net.UDPAddr), buf, cnt, maxSz, s.handlers[srcAddr.String()])
			s.singlePortProcessRequests()
		}
	}()
	for {
		select {
		case q := <-s.quit:
			q <- struct{}{}
			return nil
		case handlersToFree := <-s.runGC:
			for _, handler := range handlersToFree {
				delete(s.handlers, handler)
			}
		default:
			buf = s.bufPool.Get().([]byte)
			cnt, localAddr, srcAddr, maxSz, err = s.getPacket(buf)
			if err != nil || cnt == 0 {
				if s.hook != nil {
					s.hook.OnFailure(TransferStats{
						SenderAnticipateEnabled: s.sendAEnable,
					}, err)
				}
				s.bufPool.Put(buf)
				continue
			}
			if receiverChannel, ok := s.handlers[srcAddr.String()]; ok {
				select {
				case receiverChannel <- buf[:cnt]:
				default:
					// We don't want to block the main loop if a channel is full
				}
			} else {
				s.handlers[srcAddr.String()] = make(chan []byte, 1)
				go func(localAddr net.IP, remoteAddr *net.UDPAddr, buffer []byte, n, maxBlockLen int, listener chan []byte) {
					err := s.handlePacket(localAddr, remoteAddr, buffer, n, maxBlockLen, listener)
					if err != nil && s.hook != nil {
						s.hook.OnFailure(TransferStats{
							SenderAnticipateEnabled: s.sendAEnable,
						}, err)
					}

				}(localAddr, srcAddr.(*net.UDPAddr), buf, cnt, maxSz, s.handlers[srcAddr.String()])
			}
		}
	}
}

func (s *Server) getPacket(buf []byte) (int, net.IP, *net.UDPAddr, int, error) {
	if s.conn6 != nil {
		cnt, control, srcAddr, err := s.conn6.ReadFrom(buf)
		if err != nil || cnt == 0 {
			return 0, nil, nil, 0, err
		}
		var localAddr net.IP
		maxSz := blockLength
		if control != nil {
			localAddr = control.Dst
			if intf, err := net.InterfaceByIndex(control.IfIndex); err == nil {
				// mtu - ipv4 overhead - udp overhead
				maxSz = intf.MTU - 28
			}
		}
		return cnt, localAddr, srcAddr.(*net.UDPAddr), maxSz, nil
	} else if s.conn4 != nil {
		cnt, control, srcAddr, err := s.conn4.ReadFrom(buf)
		if err != nil || cnt == 0 {
			return 0, nil, nil, 0, err
		}
		var localAddr net.IP
		maxSz := blockLength
		if control != nil {
			localAddr = control.Dst
			if intf, err := net.InterfaceByIndex(control.IfIndex); err == nil {
				// mtu - ipv6 overhead - udp overhead
				maxSz = intf.MTU - 48
			}
		}
		return cnt, localAddr, srcAddr.(*net.UDPAddr), maxSz, nil
	} else {
		cnt, srcAddr, err := s.conn.ReadFromUDP(buf)
		if err != nil {
			return 0, nil, nil, 0, err
		}
		return cnt, nil, srcAddr, blockLength, nil
	}
}

// internalGC collects all the finished signals from each connection's goroutine
// The main loop is sent the key to be nil'ed after the gcInterval has passed
func (s *Server) internalGC() {
	var completedHandlers []string
	for {
		select {
		case newHandler := <-s.gcCollect:
			completedHandlers = append(completedHandlers, newHandler)
			if len(completedHandlers) > s.gcThreshold {
				s.runGC <- completedHandlers
				completedHandlers = nil
			}
		}
	}
}
<|endoftext|>


<commit_before>package lifecycle_test

import (
	"fmt"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gexec"

	"os"

	"github.com/cloudfoundry-incubator/cf-mysql-acceptance-tests/helpers"
	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	"github.com/cloudfoundry-incubator/cf-test-helpers/workflowhelpers"
)

var _ = Describe("P-MySQL Lifecycle Tests", func() {
	var sinatraPath = "../../assets/sinatra_app"
	var springPath = "../../assets/cipher_finder"

	var enableServiceAccessToOrg func(string, string)
	var createBindAndStartApp func(string, string, string, string, helpers.Pinger)
	var cleanupServiceInstance func(string, string)

	It("Lists all public plans in cf marketplace", func() {
		marketplaceCmd := cf.Cf("m").Wait(helpers.TestContext.LongTimeout())
		Expect(marketplaceCmd).To(Exit(0))

		marketplaceOutput := marketplaceCmd.Out.Contents()
		for _, plan := range helpers.TestConfig.Plans {
			if plan.Private == false {
				Expect(marketplaceOutput).To(MatchRegexp("%v.*%v", helpers.TestConfig.ServiceName, plan.Name))
			}
		}
	})

	It("Does not list any private plans in cf marketplace", func() {
		if helpers.TestConfig.CFConfig.UseExistingOrganization {
			Skip("Skipping private plan test due to use of existing org")
		}

		marketplaceCmd := cf.Cf("m").Wait(helpers.TestContext.LongTimeout())
		Expect(marketplaceCmd).To(Exit(0))

		marketplaceOutput := marketplaceCmd.Out.Contents()
		for _, plan := range helpers.TestConfig.Plans {
			if plan.Private == true {
				Expect(marketplaceOutput).ToNot(MatchRegexp("%v.*%v", helpers.TestConfig.ServiceName, plan.Name))
			}
		}
	})

	Describe("When pushing an app", func() {
		var appName, serviceInstanceName string
		var plan helpers.Plan
		var sinatraAppClient helpers.SinatraAppClient
		var cipherFinderAppClient helpers.CipherFinderClient

		BeforeEach(func() {
			appName = generator.PrefixedRandomName("lifecycle", "")
			serviceInstanceName = generator.PrefixedRandomName("lifecycle", "")

			if len(helpers.TestConfig.Plans) > 0 {
				plan = helpers.TestConfig.Plans[0]
			} else {
				Skip("Skipping due to lack of plans.")
			}

			enableServiceAccessToOrg(helpers.TestConfig.ServiceName, helpers.TestContext.RegularUserContext().Org)
			sinatraAppClient = helpers.NewSinatraAppClient(helpers.TestConfig.AppURI(appName), serviceInstanceName, helpers.TestConfig.CFConfig.SkipSSLValidation)
			cipherFinderAppClient = helpers.NewCipherFinderClient(helpers.TestConfig.AppURI(appName), helpers.TestConfig.CFConfig.SkipSSLValidation)
		})

		AfterEach(func() {
			cleanupServiceInstance(appName, serviceInstanceName)
		})

		It("Allows users to create, bind, write to, read from, unbind, and destroy a service instance for the each plan", func() {
			Expect(cf.Cf("push", appName, "-m", "256M", "-p", sinatraPath, "-b", "ruby_buildpack", "-d", helpers.TestConfig.CFConfig.AppsDomain, "-no-start").
				Wait(helpers.TestContext.LongTimeout())).
				To(Exit(0))

			createBindAndStartApp(helpers.TestConfig.ServiceName, plan.Name, serviceInstanceName, appName, sinatraAppClient)

			fmt.Printf("\n*** Posting to app\n")
			msg, err := sinatraAppClient.Set("mykey", "myvalue")
			Expect(msg).To(ContainSubstring("myvalue"))
			Expect(err).NotTo(HaveOccurred())

			fmt.Printf("\n*** Curling app\n")
			msg, err = sinatraAppClient.Get("mykey")
			Expect(msg).To(ContainSubstring("myvalue"))
			Expect(err).NotTo(HaveOccurred())
		})

		It("Guarantees a TLS connection to a simple Spring app", func() {
			if !helpers.TestConfig.EnableTlsTests {
				Skip("Skipping TLS tests as TLS is not enabled.")
			}

			os.MkdirAll(fmt.Sprintf("%s/build/libs/", springPath), 0700)
			os.Link("/var/vcap/packages/acceptance-tests/cipher_finder/cipher_finder.jar", fmt.Sprintf("%s/build/libs/cipher_finder.jar", springPath))

			// cf push cipher-finder -no-start
			Expect(cf.Cf("push", appName, "-m", "1G", "-f", fmt.Sprintf("%s/manifest.yml", springPath), "-d", helpers.TestConfig.CFConfig.AppsDomain, "-no-start").
				Wait(helpers.TestContext.LongTimeout())).
				To(Exit(0))

			// create-service & bind-service & start & assertAppIsRunning
			createBindAndStartApp(helpers.TestConfig.ServiceName, plan.Name, serviceInstanceName, appName, cipherFinderAppClient)

			fmt.Printf("\n*** GET curl to url\n")
			cipher, err := cipherFinderAppClient.Ciphers()
			Expect(err).NotTo(HaveOccurred())
			Expect(cipher).NotTo(BeEmpty())
		})

		enableServiceAccessToOrg = func(serviceName string, org string) {
			workflowhelpers.AsUser(helpers.TestContext.AdminUserContext(), helpers.TestContext.ShortTimeout(), func() {
				cf.Cf("enable-service-access", serviceName, "-o", org).Wait(helpers.TestContext.ShortTimeout())
			})
		}

		createBindAndStartApp = func(serviceName string, planName string, serviceInstanceName string, appName string, appClient helpers.Pinger) {
			Expect(cf.Cf("create-service", serviceName, planName, serviceInstanceName).Wait(helpers.TestContext.LongTimeout())).To(Exit(0))
			Expect(cf.Cf("bind-service", appName, serviceInstanceName).Wait(helpers.TestContext.LongTimeout())).To(Exit(0))
			Expect(cf.Cf("start", appName).Wait(helpers.TestContext.LongTimeout())).To(Exit(0))
			err := appClient.Ping()
			Expect(err).NotTo(HaveOccurred())
		}

		cleanupServiceInstance = func(appName string, serviceInstanceName string) {
			cf.Cf("unbind-service", appName, serviceInstanceName).Wait(helpers.TestContext.LongTimeout())
			cf.Cf("delete-service", "-f", serviceInstanceName).Wait(helpers.TestContext.LongTimeout())

			cf.Cf("delete", appName, "-f").Wait(helpers.TestContext.LongTimeout())
		}
	})
})
<commit_msg>Change TLS test to check for TLSv1.2 cipher [#151525786]<commit_after>package lifecycle_test

import (
	"fmt"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gexec"

	"os"

	"github.com/cloudfoundry-incubator/cf-mysql-acceptance-tests/helpers"
	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	"github.com/cloudfoundry-incubator/cf-test-helpers/workflowhelpers"
)

var _ = Describe("P-MySQL Lifecycle Tests", func() {
	var sinatraPath = "../../assets/sinatra_app"
	var springPath = "../../assets/cipher_finder"

	var enableServiceAccessToOrg func(string, string)
	var createBindAndStartApp func(string, string, string, string, helpers.Pinger)
	var cleanupServiceInstance func(string, string)

	It("Lists all public plans in cf marketplace", func() {
		marketplaceCmd := cf.Cf("m").Wait(helpers.TestContext.LongTimeout())
		Expect(marketplaceCmd).To(Exit(0))

		marketplaceOutput := marketplaceCmd.Out.Contents()
		for _, plan := range helpers.TestConfig.Plans {
			if plan.Private == false {
				Expect(marketplaceOutput).To(MatchRegexp("%v.*%v", helpers.TestConfig.ServiceName, plan.Name))
			}
		}
	})

	It("Does not list any private plans in cf marketplace", func() {
		if helpers.TestConfig.CFConfig.UseExistingOrganization {
			Skip("Skipping private plan test due to use of existing org")
		}

		marketplaceCmd := cf.Cf("m").Wait(helpers.TestContext.LongTimeout())
		Expect(marketplaceCmd).To(Exit(0))

		marketplaceOutput := marketplaceCmd.Out.Contents()
		for _, plan := range helpers.TestConfig.Plans {
			if plan.Private == true {
				Expect(marketplaceOutput).ToNot(MatchRegexp("%v.*%v", helpers.TestConfig.ServiceName, plan.Name))
			}
		}
	})

	Describe("When pushing an app", func() {
		var appName, serviceInstanceName string
		var plan helpers.Plan
		var sinatraAppClient helpers.SinatraAppClient
		var cipherFinderAppClient helpers.CipherFinderClient

		BeforeEach(func() {
			appName = generator.PrefixedRandomName("lifecycle", "")
			serviceInstanceName = generator.PrefixedRandomName("lifecycle", "")

			if len(helpers.TestConfig.Plans) > 0 {
				plan = helpers.TestConfig.Plans[0]
			} else {
				Skip("Skipping due to lack of plans.")
			}

			enableServiceAccessToOrg(helpers.TestConfig.ServiceName, helpers.TestContext.RegularUserContext().Org)
			sinatraAppClient = helpers.NewSinatraAppClient(helpers.TestConfig.AppURI(appName), serviceInstanceName, helpers.TestConfig.CFConfig.SkipSSLValidation)
			cipherFinderAppClient = helpers.NewCipherFinderClient(helpers.TestConfig.AppURI(appName), helpers.TestConfig.CFConfig.SkipSSLValidation)
		})

		AfterEach(func() {
			cleanupServiceInstance(appName, serviceInstanceName)
		})

		It("Allows users to create, bind, write to, read from, unbind, and destroy a service instance for the each plan", func() {
			Expect(cf.Cf("push", appName, "-m", "256M", "-p", sinatraPath, "-b", "ruby_buildpack", "-d", helpers.TestConfig.CFConfig.AppsDomain, "-no-start").
				Wait(helpers.TestContext.LongTimeout())).
				To(Exit(0))

			createBindAndStartApp(helpers.TestConfig.ServiceName, plan.Name, serviceInstanceName, appName, sinatraAppClient)

			fmt.Printf("\n*** Posting to app\n")
			msg, err := sinatraAppClient.Set("mykey", "myvalue")
			Expect(msg).To(ContainSubstring("myvalue"))
			Expect(err).NotTo(HaveOccurred())

			fmt.Printf("\n*** Curling app\n")
			msg, err = sinatraAppClient.Get("mykey")
			Expect(msg).To(ContainSubstring("myvalue"))
			Expect(err).NotTo(HaveOccurred())
		})

		It("Guarantees a TLS connection to a simple Spring app", func() {
			if !helpers.TestConfig.EnableTlsTests {
				Skip("Skipping TLS tests as TLS is not enabled.")
			}

			os.MkdirAll(fmt.Sprintf("%s/build/libs/", springPath), 0700)
			os.Link("/var/vcap/packages/acceptance-tests/cipher_finder/cipher_finder.jar", fmt.Sprintf("%s/build/libs/cipher_finder.jar", springPath))

			// cf push cipher-finder -no-start
			Expect(cf.Cf("push", appName, "-m", "1G", "-f", fmt.Sprintf("%s/manifest.yml", springPath), "-d", helpers.TestConfig.CFConfig.AppsDomain, "-no-start").
				Wait(helpers.TestContext.LongTimeout())).
				To(Exit(0))

			// create-service & bind-service & start & assertAppIsRunning
			createBindAndStartApp(helpers.TestConfig.ServiceName, plan.Name, serviceInstanceName, appName, cipherFinderAppClient)

			fmt.Printf("\n*** GET curl to url\n")
			cipher, err := cipherFinderAppClient.Ciphers()
			Expect(err).NotTo(HaveOccurred())
			Expect(cipher).To(Equal("AES256-SHA256"))
		})

		enableServiceAccessToOrg = func(serviceName string, org string) {
			workflowhelpers.AsUser(helpers.TestContext.AdminUserContext(), helpers.TestContext.ShortTimeout(), func() {
				cf.Cf("enable-service-access", serviceName, "-o", org).Wait(helpers.TestContext.ShortTimeout())
			})
		}

		createBindAndStartApp = func(serviceName string, planName string, serviceInstanceName string, appName string, appClient helpers.Pinger) {
			Expect(cf.Cf("create-service", serviceName, planName, serviceInstanceName).Wait(helpers.TestContext.LongTimeout())).To(Exit(0))
			Expect(cf.Cf("bind-service", appName, serviceInstanceName).Wait(helpers.TestContext.LongTimeout())).To(Exit(0))
			Expect(cf.Cf("start", appName).Wait(helpers.TestContext.LongTimeout())).To(Exit(0))
			err := appClient.Ping()
			Expect(err).NotTo(HaveOccurred())
		}

		cleanupServiceInstance = func(appName string, serviceInstanceName string) {
			cf.Cf("unbind-service", appName, serviceInstanceName).Wait(helpers.TestContext.LongTimeout())
			cf.Cf("delete-service", "-f", serviceInstanceName).Wait(helpers.TestContext.LongTimeout())

			cf.Cf("delete", appName, "-f").Wait(helpers.TestContext.LongTimeout())
		}
	})
})
<|endoftext|>


<commit_before>package site

import (
	"errors"
	"fmt"
	"html/template"
	"net/http"
	"strconv"
	"time"

	"github.com/0x7fffffff/colloquium_presentation_website/persist"
	"github.com/0x7fffffff/colloquium_presentation_website/websocket"
	"github.com/gorilla/mux"
	"github.com/nu7hatch/gouuid"
)

var currentQuestion = 0
var totalQuestions int
var currentSessionHeaderName string
var over = false

func init() {
	questions, err := persist.GetAllQuestions()
	if err != nil {
		totalQuestions = 0
	} else {
		totalQuestions = len(questions)
	}

	uuid, err := uuid.NewV4()
	if err != nil {
		currentSessionHeaderName = "session"
	} else {
		currentSessionHeaderName = "session-" + uuid.String()
	}
}

func templateOnBase(path string) *template.Template {
	funcMap := template.FuncMap{
		"percentage": func(x, y int) float64 {
			return float64(x) / float64(y) * 100.0
		},
	}

	return template.Must(template.New("_base.html").Funcs(funcMap).ParseFiles(
		"templates/_base.html",
		path,
	))
}

// creates the base params that will be passed to all templates when
// they are rendered.
func templateParamsOnBase(new map[string]interface{}, request *http.Request) map[string]interface{} {
	base := map[string]interface{}{
		"SocketURL":   			"ws://" + request.Host + "/socket",
		"CurrentQuestionIndex": currentQuestion,
		"TotalQuestions":		totalQuestions,
	}

	for k, v := range base {
		new[k] = v
	}

	return new
}

func win() {
	fmt.Println("over. about to sleep")
	time.Sleep(5 * time.Second)
	fmt.Println("done sleeping")

	sessions, err := persist.FindWinners(1)
	if err != nil {
		return
	}
	fmt.Println(sessions)
	websocket.SocketMessage{
		Payload: map[string]interface{}{
			"winners": map[string]interface{}{
				"sessions": sessions,
			},
		},
	}.Send()
}

func handleControlPage(router *mux.Router) {
	router.HandleFunc("/control", func(writer http.ResponseWriter, request *http.Request) {
		controlTemplate := templateOnBase("templates/_control.html")
		data := map[string]interface{}{}
		if err := controlTemplate.Execute(writer, templateParamsOnBase(data, request)); err != nil {
			serverError(writer, err)
		}
	}).Methods("GET")

	router.HandleFunc("/control/next", func(writer http.ResponseWriter, request *http.Request) {
		if over {
			writer.WriteHeader(http.StatusOK)
			return
		}

		currentQuestion++

		websocket.SocketMessage{
			Payload: map[string]interface{}{
				"next": map[string]interface{}{
					"question_number": currentQuestion,
				},
			},
		}.Send()

		if currentQuestion >= totalQuestions {
			over = true
			go win()
		}

		writer.WriteHeader(http.StatusOK)
	}).Methods("POST")

	router.HandleFunc("/control/show", func(writer http.ResponseWriter, request *http.Request) {
		websocket.SocketMessage{
			Payload: map[string]interface{}{
				"show": map[string]interface{}{},
			},
		}.Send()

		writer.WriteHeader(http.StatusOK)
	}).Methods("POST")
}

func handleQuizPage(router *mux.Router) {
	router.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
		session, err := store.Get(request, currentSessionHeaderName)
		if err != nil {
			clientError(writer, errors.New("couldn't get session"))
			return
		}

		if session.IsNew {
			uuid, err := uuid.NewV4()
			if err != nil {
				serverError(writer, errors.New("Couldn't generate user key"))
				return
			}

			session.Values["token"] = uuid.String()

			if err = session.Save(request, writer); err != nil {
				clientError(writer, errors.New("couldn't update session"))
				return
			}
		}

		path := fmt.Sprintf("/question/%v", currentQuestion)
		http.Redirect(writer, request, path, http.StatusSeeOther)
	}).Methods("GET")

	router.HandleFunc("/question/{question_id:[0-9]+}", func(writer http.ResponseWriter, request *http.Request) {
		quizTemplate := templateOnBase("templates/_quiz.html")

		id := identifierFromRequest("question_id", request)
		if id == nil {
			clientError(writer, errors.New("Missing question identifier"))
			return
		}

		if *id > totalQuestions - 1 {
			http.Redirect(writer, request, "/score", http.StatusSeeOther)
			return
		}

		if *id < 0 {
			clientError(writer, errors.New("Invalid question id"))
			return
		}

		if *id != currentQuestion {
			path := fmt.Sprintf("/question/%v", currentQuestion)
			http.Redirect(writer, request, path, http.StatusSeeOther)
			return
		}

		question, err := persist.GetQuestion(*id)
		if err != nil {
			clientError(writer, errors.New("Invalid question id"))
			return
		}

		answers, err := persist.GetAnswersForQuestion(*question)
		if err != nil {
			clientError(writer, errors.New("Invalid question id"))
			return
		}

		data := map[string]interface{}{
			"Question": *question,
			"Answers": answers,
		}

		if err := quizTemplate.Execute(writer, templateParamsOnBase(data, request)); err != nil {
			serverError(writer, err)
		}
	}).Methods("GET")

	router.HandleFunc("/score", func(writer http.ResponseWriter, request *http.Request) {
		scoreTemplate := templateOnBase("templates/_score.html")

		session, err := store.Get(request, currentSessionHeaderName)
		if err != nil {
			clientError(writer, errors.New("couldn't get session"))
			return
		}

		count, err := persist.CorrectCountForSessionId(session.Values["token"].(string))
		if err != nil {
			serverError(writer, errors.New("I don't even know"))
			return
		}

		data := map[string]interface{}{
			"Percentage": float64(count) / float64(totalQuestions) * 100.0,
			"Session": session.Values["token"].(string),
		}

		if err := scoreTemplate.Execute(writer, templateParamsOnBase(data, request)); err != nil {
			serverError(writer, err)
		}
	}).Methods("GET")

	router.HandleFunc("/question/{question_id:[0-9]+}/answer/{answer_index:[0-9]+}", func(writer http.ResponseWriter, request *http.Request) {
		questionId := identifierFromRequest("question_id", request)
		if questionId == nil {
			clientError(writer, errors.New("Missing question identifier"))
			return
		}

		answerIndex := identifierFromRequest("answer_index", request)
		if answerIndex == nil {
			clientError(writer, errors.New("Missing answer index"))
			return
		}

		session, err := store.Get(request, currentSessionHeaderName)
		if err != nil {
			clientError(writer, errors.New("couldn't get session"))
			return
		}

		fmt.Println(session.Values["token"])
		persist.AnswerQuestion(*questionId + 1, *answerIndex, session.Values["token"].(string))

		writer.WriteHeader(http.StatusOK)
	}).Methods("POST")
}
// adds all the routes to the router.
func addRoutes() *mux.Router {
	router := mux.NewRouter()

	handleControlPage(router)
	handleQuizPage(router)

	serveStaticFolder("/css/", router)
	serveStaticFolder("/js/", router)
	serveStaticFolder("/fonts/", router)

	websocket.Start(router)

	return router
}

// used to server static files, like CSS/JavaScript/fonts/etc.
func serveStaticFolder(folder string, router *mux.Router) {
	static := "static" + folder
	fileServer := http.FileServer(http.Dir(static))
	router.PathPrefix(folder).Handler(http.StripPrefix(folder, fileServer))
}

func clientError(writer http.ResponseWriter, err error) {
	http.Error(writer, err.Error(), http.StatusBadRequest)
}

func serverError(writer http.ResponseWriter, err error) {
	http.Error(writer, err.Error(), http.StatusInternalServerError)
}

// parses the given identifier out of the request path.
func identifierFromRequest(identifier string, request *http.Request) *int {
	vars := mux.Vars(request)
	idString := vars[identifier]

	if idString == "" {
		return nil
	}

	id, err := strconv.Atoi(idString)
	if err != nil {
		return nil
	}

	return &id
}
<commit_msg>3 winners<commit_after>package site

import (
	"errors"
	"fmt"
	"html/template"
	"net/http"
	"strconv"
	"time"

	"github.com/0x7fffffff/colloquium_presentation_website/persist"
	"github.com/0x7fffffff/colloquium_presentation_website/websocket"
	"github.com/gorilla/mux"
	"github.com/nu7hatch/gouuid"
)

var currentQuestion = 0
var totalQuestions int
var currentSessionHeaderName string
var over = false

func init() {
	questions, err := persist.GetAllQuestions()
	if err != nil {
		totalQuestions = 0
	} else {
		totalQuestions = len(questions)
	}

	uuid, err := uuid.NewV4()
	if err != nil {
		currentSessionHeaderName = "session"
	} else {
		currentSessionHeaderName = "session-" + uuid.String()
	}
}

func templateOnBase(path string) *template.Template {
	funcMap := template.FuncMap{
		"percentage": func(x, y int) float64 {
			return float64(x) / float64(y) * 100.0
		},
	}

	return template.Must(template.New("_base.html").Funcs(funcMap).ParseFiles(
		"templates/_base.html",
		path,
	))
}

// creates the base params that will be passed to all templates when
// they are rendered.
func templateParamsOnBase(new map[string]interface{}, request *http.Request) map[string]interface{} {
	base := map[string]interface{}{
		"SocketURL":   			"ws://" + request.Host + "/socket",
		"CurrentQuestionIndex": currentQuestion,
		"TotalQuestions":		totalQuestions,
	}

	for k, v := range base {
		new[k] = v
	}

	return new
}

func win() {
	fmt.Println("over. about to sleep")
	time.Sleep(5 * time.Second)
	fmt.Println("done sleeping")

	sessions, err := persist.FindWinners(3)
	if err != nil {
		return
	}
	fmt.Println(sessions)
	websocket.SocketMessage{
		Payload: map[string]interface{}{
			"winners": map[string]interface{}{
				"sessions": sessions,
			},
		},
	}.Send()
}

func handleControlPage(router *mux.Router) {
	router.HandleFunc("/control", func(writer http.ResponseWriter, request *http.Request) {
		controlTemplate := templateOnBase("templates/_control.html")
		data := map[string]interface{}{}
		if err := controlTemplate.Execute(writer, templateParamsOnBase(data, request)); err != nil {
			serverError(writer, err)
		}
	}).Methods("GET")

	router.HandleFunc("/control/next", func(writer http.ResponseWriter, request *http.Request) {
		if over {
			writer.WriteHeader(http.StatusOK)
			return
		}

		currentQuestion++

		websocket.SocketMessage{
			Payload: map[string]interface{}{
				"next": map[string]interface{}{
					"question_number": currentQuestion,
				},
			},
		}.Send()

		if currentQuestion >= totalQuestions {
			over = true
			go win()
		}

		writer.WriteHeader(http.StatusOK)
	}).Methods("POST")

	router.HandleFunc("/control/show", func(writer http.ResponseWriter, request *http.Request) {
		websocket.SocketMessage{
			Payload: map[string]interface{}{
				"show": map[string]interface{}{},
			},
		}.Send()

		writer.WriteHeader(http.StatusOK)
	}).Methods("POST")
}

func handleQuizPage(router *mux.Router) {
	router.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
		session, err := store.Get(request, currentSessionHeaderName)
		if err != nil {
			clientError(writer, errors.New("couldn't get session"))
			return
		}

		if session.IsNew {
			uuid, err := uuid.NewV4()
			if err != nil {
				serverError(writer, errors.New("Couldn't generate user key"))
				return
			}

			session.Values["token"] = uuid.String()

			if err = session.Save(request, writer); err != nil {
				clientError(writer, errors.New("couldn't update session"))
				return
			}
		}

		path := fmt.Sprintf("/question/%v", currentQuestion)
		http.Redirect(writer, request, path, http.StatusSeeOther)
	}).Methods("GET")

	router.HandleFunc("/question/{question_id:[0-9]+}", func(writer http.ResponseWriter, request *http.Request) {
		quizTemplate := templateOnBase("templates/_quiz.html")

		id := identifierFromRequest("question_id", request)
		if id == nil {
			clientError(writer, errors.New("Missing question identifier"))
			return
		}

		if *id > totalQuestions - 1 {
			http.Redirect(writer, request, "/score", http.StatusSeeOther)
			return
		}

		if *id < 0 {
			clientError(writer, errors.New("Invalid question id"))
			return
		}

		if *id != currentQuestion {
			path := fmt.Sprintf("/question/%v", currentQuestion)
			http.Redirect(writer, request, path, http.StatusSeeOther)
			return
		}

		question, err := persist.GetQuestion(*id)
		if err != nil {
			clientError(writer, errors.New("Invalid question id"))
			return
		}

		answers, err := persist.GetAnswersForQuestion(*question)
		if err != nil {
			clientError(writer, errors.New("Invalid question id"))
			return
		}

		data := map[string]interface{}{
			"Question": *question,
			"Answers": answers,
		}

		if err := quizTemplate.Execute(writer, templateParamsOnBase(data, request)); err != nil {
			serverError(writer, err)
		}
	}).Methods("GET")

	router.HandleFunc("/score", func(writer http.ResponseWriter, request *http.Request) {
		scoreTemplate := templateOnBase("templates/_score.html")

		session, err := store.Get(request, currentSessionHeaderName)
		if err != nil {
			clientError(writer, errors.New("couldn't get session"))
			return
		}

		count, err := persist.CorrectCountForSessionId(session.Values["token"].(string))
		if err != nil {
			serverError(writer, errors.New("I don't even know"))
			return
		}

		data := map[string]interface{}{
			"Percentage": float64(count) / float64(totalQuestions) * 100.0,
			"Session": session.Values["token"].(string),
		}

		if err := scoreTemplate.Execute(writer, templateParamsOnBase(data, request)); err != nil {
			serverError(writer, err)
		}
	}).Methods("GET")

	router.HandleFunc("/question/{question_id:[0-9]+}/answer/{answer_index:[0-9]+}", func(writer http.ResponseWriter, request *http.Request) {
		questionId := identifierFromRequest("question_id", request)
		if questionId == nil {
			clientError(writer, errors.New("Missing question identifier"))
			return
		}

		answerIndex := identifierFromRequest("answer_index", request)
		if answerIndex == nil {
			clientError(writer, errors.New("Missing answer index"))
			return
		}

		session, err := store.Get(request, currentSessionHeaderName)
		if err != nil {
			clientError(writer, errors.New("couldn't get session"))
			return
		}

		fmt.Println(session.Values["token"])
		persist.AnswerQuestion(*questionId + 1, *answerIndex, session.Values["token"].(string))

		writer.WriteHeader(http.StatusOK)
	}).Methods("POST")
}
// adds all the routes to the router.
func addRoutes() *mux.Router {
	router := mux.NewRouter()

	handleControlPage(router)
	handleQuizPage(router)

	serveStaticFolder("/css/", router)
	serveStaticFolder("/js/", router)
	serveStaticFolder("/fonts/", router)

	websocket.Start(router)

	return router
}

// used to server static files, like CSS/JavaScript/fonts/etc.
func serveStaticFolder(folder string, router *mux.Router) {
	static := "static" + folder
	fileServer := http.FileServer(http.Dir(static))
	router.PathPrefix(folder).Handler(http.StripPrefix(folder, fileServer))
}

func clientError(writer http.ResponseWriter, err error) {
	http.Error(writer, err.Error(), http.StatusBadRequest)
}

func serverError(writer http.ResponseWriter, err error) {
	http.Error(writer, err.Error(), http.StatusInternalServerError)
}

// parses the given identifier out of the request path.
func identifierFromRequest(identifier string, request *http.Request) *int {
	vars := mux.Vars(request)
	idString := vars[identifier]

	if idString == "" {
		return nil
	}

	id, err := strconv.Atoi(idString)
	if err != nil {
		return nil
	}

	return &id
}
<|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 siv

import (
	"fmt"
)

// Given a key and plaintext, encrypt the plaintext using the SIV mode of AES,
// as defined by RFC 5297, and return the result (including both the synthetic
// initialization vector and the ciphertext). The output can later be fed to
// Decrypt to recover the plaintext.
//
// In addition to confidentiality, this function also offers authenticity. That
// is, without the secret key, and attacker is unable to construct a byte
// string that Decrypt will accept.
//
// The supplied key must be 32, 48, or 64 bytes long.
//
// The supplied associated data, up to 126 strings, may also be authenticated,
// though it is not included in the ciphertext. The user must supply the same
// associated data to Decrypt in order for the latter to succeed. If no
// associated data is desired, pass nil or an empty slice.
//
// If the same key, plaintext, and associated data are supplied to this
// function multiple times, the output is guaranteed to be identical. As per
// RFC 5297 section 3, you may use this function for nonce-based authenticated
// encryption by passing a nonce as the last associated data element.
func Encrypt(key, plaintext []byte, associated [][]byte) ([]byte, error) {
	keyLen := len(key)
	associatedLen := len(associated)

	// Make sure the key length is legal.
	switch keyLen {
	case 32, 48, 64:
	default:
		return nil, fmt.Errorf("SIV requires a 32-, 48-, or 64-byte key.")
	}

	// Make sure the number of associated data is legal, per RFC 5297 section 7.
	if associatedLen > 126 {
		return nil, fmt.Errorf("len(associated) may be no more than 126.")
	}

	return nil, fmt.Errorf("TODO")
}

<commit_msg>Created a broken implementation.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 siv

import (
	"crypto/aes"
	"crypto/cipher"
	"fmt"
)

func dup(d []byte) []byte {
	result := make([]byte, len(d))
	copy(result, d)
	return result
}

// Given a key and plaintext, encrypt the plaintext using the SIV mode of AES,
// as defined by RFC 5297, and return the result (including both the synthetic
// initialization vector and the ciphertext). The output can later be fed to
// Decrypt to recover the plaintext.
//
// In addition to confidentiality, this function also offers authenticity. That
// is, without the secret key, and attacker is unable to construct a byte
// string that Decrypt will accept.
//
// The supplied key must be 32, 48, or 64 bytes long.
//
// The supplied associated data, up to 126 strings, may also be authenticated,
// though it is not included in the ciphertext. The user must supply the same
// associated data to Decrypt in order for the latter to succeed. If no
// associated data is desired, pass nil or an empty slice.
//
// If the same key, plaintext, and associated data are supplied to this
// function multiple times, the output is guaranteed to be identical. As per
// RFC 5297 section 3, you may use this function for nonce-based authenticated
// encryption by passing a nonce as the last associated data element.
func Encrypt(key, plaintext []byte, associated [][]byte) ([]byte, error) {
	keyLen := len(key)
	associatedLen := len(associated)

	// Make sure the key length is legal.
	switch keyLen {
	case 32, 48, 64:
	default:
		return nil, fmt.Errorf("SIV requires a 32-, 48-, or 64-byte key.")
	}

	// Make sure the number of associated data is legal, per RFC 5297 section 7.
	if associatedLen > 126 {
		return nil, fmt.Errorf("len(associated) may be no more than 126.")
	}

	// Derive subkeys.
	k1 := key[:keyLen/2]
	k2 := key[keyLen/2:]

	// Call S2V to derive the synthetic initialization vector.
	v := s2v(k1, append(associated, plaintext))
	if len(v) != aes.BlockSize {
		panic(fmt.Sprintf("Unexpected vector: %v", v))
	}

	// Create a CTR cipher using a version of v with the 31st and 63rd bits
	// zeroed out.
	q := dup(v)
	q[aes.BlockSize-1] &= 0x7f
	q[aes.BlockSize-2] &= 0x7f

	ciph, err := aes.NewCipher(k2)
	if err != nil {
		return nil, fmt.Errorf("aes.NewCipher: %v", err)
	}

	ctrCiph := cipher.NewCTR(ciph, q)

	// Create a result buffer large enough to hold the SIV and the ciphertext.
	// Copy in the SIV then fill in the ciphertext.
	result := make([]byte, len(v) + len(plaintext))
	copy(result, v)
	ctrCiph.XORKeyStream(result[len(v):], plaintext)

	return result, nil
}

<|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 gcstesting

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"net/http"

	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/oauthutil"
	storagev1 "google.golang.org/api/storage/v1"
)

var fKeyFile = flag.String(
	"key_file", "",
	"Path to a JSON key for a service account created on the Developers Console.")

var fBucket = flag.String(
	"bucket", "",
	"Empty bucket to use for storage.")

// Return an HTTP client configured according to the --key_file flag defined by
// this package. For use in integration tests that use GCS.
func IntegrationTestHTTPClient() (client *http.Client, err error) {
	if *fKeyFile == "" {
		err = errors.New("You must set --key_file.")
		return
	}

	const scope = storagev1.DevstorageFull_controlScope
	client, err = oauthutil.NewJWTHttpClient(*fKeyFile, []string{scope})
	if err != nil {
		err = fmt.Errorf("oauthutil.NewJWTHttpClient: %v", err)
		return
	}

	return
}

func bucketName() (name string, err error) {
	name = *fBucket
	if name == "" {
		err = errors.New("You must set --bucket.")
		return
	}

	return
}

// Return a bucket configured according to the --bucket and --key_file flags
// defined by this package. For use in integration tests that use GCS.
func IntegrationTestBucket() (b gcs.Bucket, err error) {
	// Grab the bucket name.
	name, err := bucketName()
	if err != nil {
		return
	}

	// Grab the HTTP client.
	client, err := IntegrationTestHTTPClient()
	if err != nil {
		return
	}

	// Set up a GCS connection.
	cfg := &gcs.ConnConfig{
		HTTPClient: client,
	}

	conn, err := gcs.NewConn(cfg)
	if err != nil {
		err = fmt.Errorf("gcs.NewConn: %v", err)
		return
	}

	// Open the bucket.
	b = conn.GetBucket(name)

	return
}

// Like IntegrationTestBucket, but exits the process on failure.
func IntegrationTestBucketOrDie() (b gcs.Bucket) {
	b, err := IntegrationTestBucket()
	if err != nil {
		log.Fatalln("IntegrationTestBucket:", err)
	}

	return
}
<commit_msg>Fixed a flag description.<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 gcstesting

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"net/http"

	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/oauthutil"
	storagev1 "google.golang.org/api/storage/v1"
)

var fKeyFile = flag.String(
	"key_file", "",
	"Path to a JSON key for a service account created on the Developers Console.")

var fBucket = flag.String(
	"bucket", "",
	"Bucket to use for testing.")

// Return an HTTP client configured according to the --key_file flag defined by
// this package. For use in integration tests that use GCS.
func IntegrationTestHTTPClient() (client *http.Client, err error) {
	if *fKeyFile == "" {
		err = errors.New("You must set --key_file.")
		return
	}

	const scope = storagev1.DevstorageFull_controlScope
	client, err = oauthutil.NewJWTHttpClient(*fKeyFile, []string{scope})
	if err != nil {
		err = fmt.Errorf("oauthutil.NewJWTHttpClient: %v", err)
		return
	}

	return
}

func bucketName() (name string, err error) {
	name = *fBucket
	if name == "" {
		err = errors.New("You must set --bucket.")
		return
	}

	return
}

// Return a bucket configured according to the --bucket and --key_file flags
// defined by this package. For use in integration tests that use GCS.
func IntegrationTestBucket() (b gcs.Bucket, err error) {
	// Grab the bucket name.
	name, err := bucketName()
	if err != nil {
		return
	}

	// Grab the HTTP client.
	client, err := IntegrationTestHTTPClient()
	if err != nil {
		return
	}

	// Set up a GCS connection.
	cfg := &gcs.ConnConfig{
		HTTPClient: client,
	}

	conn, err := gcs.NewConn(cfg)
	if err != nil {
		err = fmt.Errorf("gcs.NewConn: %v", err)
		return
	}

	// Open the bucket.
	b = conn.GetBucket(name)

	return
}

// Like IntegrationTestBucket, but exits the process on failure.
func IntegrationTestBucketOrDie() (b gcs.Bucket) {
	b, err := IntegrationTestBucket()
	if err != nil {
		log.Fatalln("IntegrationTestBucket:", err)
	}

	return
}
<|endoftext|>


<commit_before>package auction_cell_rep

import (
	"strconv"

	"github.com/cloudfoundry-incubator/auction/auctiontypes"
	"github.com/cloudfoundry-incubator/executor"
	"github.com/cloudfoundry-incubator/rep"
	"github.com/cloudfoundry-incubator/rep/evacuation"
	Bbs "github.com/cloudfoundry-incubator/runtime-schema/bbs"
	"github.com/cloudfoundry-incubator/runtime-schema/models"
	"github.com/pivotal-golang/lager"
)

type AuctionCellRep struct {
	cellID                string
	stack                 string
	zone                  string
	generateContainerGuid func() (string, error)
	bbs                   Bbs.RepBBS
	client                executor.Client
	evacuationContext     evacuation.EvacuationContext
	logger                lager.Logger
}

func New(
	cellID string,
	stack string,
	zone string,
	generateContainerGuid func() (string, error),
	bbs Bbs.RepBBS,
	client executor.Client,
	evacuationContext evacuation.EvacuationContext,
	logger lager.Logger,
) *AuctionCellRep {
	return &AuctionCellRep{
		cellID: cellID,
		stack:  stack,
		zone:   zone,
		generateContainerGuid: generateContainerGuid,
		bbs:               bbs,
		client:            client,
		evacuationContext: evacuationContext,
		logger:            logger.Session("auction-delegate"),
	}
}

func (a *AuctionCellRep) State() (auctiontypes.CellState, error) {
	logger := a.logger.Session("auction-state")
	logger.Info("providing")

	totalResources, err := a.fetchResourcesVia(a.client.TotalResources)
	if err != nil {
		logger.Error("failed-to-get-total-resources", err)
		return auctiontypes.CellState{}, err
	}

	availableResources, err := a.fetchResourcesVia(a.client.RemainingResources)
	if err != nil {
		logger.Error("failed-to-get-remaining-resource", err)
		return auctiontypes.CellState{}, err
	}

	lrpContainers, err := a.client.ListContainers(executor.Tags{
		rep.LifecycleTag: rep.LRPLifecycle,
	})

	if err != nil {
		logger.Error("failed-to-fetch-containers", err)
		return auctiontypes.CellState{}, err
	}

	lrps := []auctiontypes.LRP{}

	for _, container := range lrpContainers {
		index, _ := strconv.Atoi(container.Tags[rep.ProcessIndexTag])
		lrp := auctiontypes.LRP{
			ProcessGuid: container.Tags[rep.ProcessGuidTag],
			Index:       index,
			MemoryMB:    container.MemoryMB,
			DiskMB:      container.DiskMB,
		}
		lrps = append(lrps, lrp)
	}

	state := auctiontypes.CellState{
		Stack:              a.stack,
		AvailableResources: availableResources,
		TotalResources:     totalResources,
		LRPs:               lrps,
		Zone:               a.zone,
		Evacuating:         a.evacuationContext.Evacuating(),
	}

	a.logger.Session("provided", lager.Data{"state": state})

	return state, nil
}

func (a *AuctionCellRep) Perform(work auctiontypes.Work) (auctiontypes.Work, error) {
	var failedWork = auctiontypes.Work{}

	logger := a.logger.Session("auction-work", lager.Data{
		"lrp-starts": len(work.LRPs),
		"tasks":      len(work.Tasks),
	})

	if a.evacuationContext.Evacuating() {
		return work, nil
	}

	if len(work.LRPs) > 0 {
		lrpLogger := logger.Session("lrp-allocate-instances")
		lrpLogger.Info("allocating")
		containers, lrpAuctionMap, err := a.lrpsToContainers(work.LRPs)
		if err != nil {
			failedWork.LRPs = work.LRPs
			lrpLogger.Info("failed-to-allocate")
		} else {
			errMessageMap, err := a.client.AllocateContainers(containers)
			if err != nil {
				failedWork.LRPs = work.LRPs
			} else {
				for guid, lrpStart := range lrpAuctionMap {
					if _, found := errMessageMap[guid]; found {
						failedWork.LRPs = append(failedWork.LRPs, lrpStart)
					}
				}
				lrpLogger.Info("allocated")
			}
		}
	}

	if len(work.Tasks) > 0 {
		taskLogger := logger.Session("task-allocate-instances")
		taskLogger.Info("allocating")
		containers := a.tasksToContainers(work.Tasks)
		errMessageMap, err := a.client.AllocateContainers(containers)
		if err != nil {
			failedWork.Tasks = work.Tasks
			taskLogger.Info("failed-to-allocate")
		} else {
			for _, task := range work.Tasks {
				if _, found := errMessageMap[task.TaskGuid]; found {
					failedWork.Tasks = append(failedWork.Tasks, task)
				}
			}
			taskLogger.Info("allocated")
		}
	}
	return failedWork, nil
}

func (a *AuctionCellRep) lrpsToContainers(lrps []auctiontypes.LRPAuction) ([]executor.Container, map[string]auctiontypes.LRPAuction, error) {
	containers := make([]executor.Container, 0, len(lrps))
	lrpAuctionMap := map[string]auctiontypes.LRPAuction{}

	for _, lrpStart := range lrps {
		lrpStart := lrpStart
		containerGuidString, err := a.generateContainerGuid()
		if err != nil {
			return nil, nil, err
		}
		lrpAuctionMap[containerGuidString] = lrpStart

		container := executor.Container{
			Guid: containerGuidString,

			Tags: executor.Tags{
				rep.LifecycleTag:    rep.LRPLifecycle,
				rep.DomainTag:       lrpStart.DesiredLRP.Domain,
				rep.ProcessGuidTag:  lrpStart.DesiredLRP.ProcessGuid,
				rep.ProcessIndexTag: strconv.Itoa(lrpStart.Index),
			},

			MemoryMB:     lrpStart.DesiredLRP.MemoryMB,
			DiskMB:       lrpStart.DesiredLRP.DiskMB,
			CPUWeight:    lrpStart.DesiredLRP.CPUWeight,
			RootFSPath:   lrpStart.DesiredLRP.RootFSPath,
			Privileged:   lrpStart.DesiredLRP.Privileged,
			Ports:        a.convertPortMappings(lrpStart.DesiredLRP.Ports),
			StartTimeout: lrpStart.DesiredLRP.StartTimeout,

			Log: executor.LogConfig{
				Guid:       lrpStart.DesiredLRP.LogGuid,
				SourceName: lrpStart.DesiredLRP.LogSource,
				Index:      &lrpStart.Index,
			},

			Setup:   lrpStart.DesiredLRP.Setup,
			Action:  lrpStart.DesiredLRP.Action,
			Monitor: lrpStart.DesiredLRP.Monitor,

			Env: append([]executor.EnvironmentVariable{
				{Name: "INSTANCE_GUID", Value: containerGuidString},
				{Name: "INSTANCE_INDEX", Value: strconv.Itoa(lrpStart.Index)},
			}, executor.EnvironmentVariablesFromModel(lrpStart.DesiredLRP.EnvironmentVariables)...),
			EgressRules: lrpStart.DesiredLRP.EgressRules,
		}
		containers = append(containers, container)
	}

	return containers, lrpAuctionMap, nil
}

func (a *AuctionCellRep) tasksToContainers(tasks []models.Task) []executor.Container {
	containers := make([]executor.Container, 0, len(tasks))

	for _, task := range tasks {
		container := executor.Container{
			Guid: task.TaskGuid,

			DiskMB:     task.DiskMB,
			MemoryMB:   task.MemoryMB,
			CPUWeight:  task.CPUWeight,
			RootFSPath: task.RootFSPath,
			Privileged: task.Privileged,
			Log: executor.LogConfig{
				Guid:       task.LogGuid,
				SourceName: task.LogSource,
			},
			Tags: executor.Tags{
				rep.LifecycleTag:  rep.TaskLifecycle,
				rep.DomainTag:     task.Domain,
				rep.ResultFileTag: task.ResultFile,
			},

			Action: task.Action,

			Env:         executor.EnvironmentVariablesFromModel(task.EnvironmentVariables),
			EgressRules: task.EgressRules,
		}
		containers = append(containers, container)
	}

	return containers
}

func (a *AuctionCellRep) convertPortMappings(containerPorts []uint32) []executor.PortMapping {
	out := []executor.PortMapping{}
	for _, port := range containerPorts {
		out = append(out, executor.PortMapping{
			ContainerPort: port,
		})
	}

	return out
}

func (a *AuctionCellRep) fetchResourcesVia(fetcher func() (executor.ExecutorResources, error)) (auctiontypes.Resources, error) {
	resources, err := fetcher()
	if err != nil {
		return auctiontypes.Resources{}, err
	}
	return auctiontypes.Resources{
		MemoryMB:   resources.MemoryMB,
		DiskMB:     resources.DiskMB,
		Containers: resources.Containers,
	}, nil
}
<commit_msg>Replace logger.Session with logger.Info<commit_after>package auction_cell_rep

import (
	"strconv"

	"github.com/cloudfoundry-incubator/auction/auctiontypes"
	"github.com/cloudfoundry-incubator/executor"
	"github.com/cloudfoundry-incubator/rep"
	"github.com/cloudfoundry-incubator/rep/evacuation"
	Bbs "github.com/cloudfoundry-incubator/runtime-schema/bbs"
	"github.com/cloudfoundry-incubator/runtime-schema/models"
	"github.com/pivotal-golang/lager"
)

type AuctionCellRep struct {
	cellID                string
	stack                 string
	zone                  string
	generateContainerGuid func() (string, error)
	bbs                   Bbs.RepBBS
	client                executor.Client
	evacuationContext     evacuation.EvacuationContext
	logger                lager.Logger
}

func New(
	cellID string,
	stack string,
	zone string,
	generateContainerGuid func() (string, error),
	bbs Bbs.RepBBS,
	client executor.Client,
	evacuationContext evacuation.EvacuationContext,
	logger lager.Logger,
) *AuctionCellRep {
	return &AuctionCellRep{
		cellID: cellID,
		stack:  stack,
		zone:   zone,
		generateContainerGuid: generateContainerGuid,
		bbs:               bbs,
		client:            client,
		evacuationContext: evacuationContext,
		logger:            logger.Session("auction-delegate"),
	}
}

func (a *AuctionCellRep) State() (auctiontypes.CellState, error) {
	logger := a.logger.Session("auction-state")
	logger.Info("providing")

	totalResources, err := a.fetchResourcesVia(a.client.TotalResources)
	if err != nil {
		logger.Error("failed-to-get-total-resources", err)
		return auctiontypes.CellState{}, err
	}

	availableResources, err := a.fetchResourcesVia(a.client.RemainingResources)
	if err != nil {
		logger.Error("failed-to-get-remaining-resource", err)
		return auctiontypes.CellState{}, err
	}

	lrpContainers, err := a.client.ListContainers(executor.Tags{
		rep.LifecycleTag: rep.LRPLifecycle,
	})

	if err != nil {
		logger.Error("failed-to-fetch-containers", err)
		return auctiontypes.CellState{}, err
	}

	lrps := []auctiontypes.LRP{}

	for _, container := range lrpContainers {
		index, _ := strconv.Atoi(container.Tags[rep.ProcessIndexTag])
		lrp := auctiontypes.LRP{
			ProcessGuid: container.Tags[rep.ProcessGuidTag],
			Index:       index,
			MemoryMB:    container.MemoryMB,
			DiskMB:      container.DiskMB,
		}
		lrps = append(lrps, lrp)
	}

	state := auctiontypes.CellState{
		Stack:              a.stack,
		AvailableResources: availableResources,
		TotalResources:     totalResources,
		LRPs:               lrps,
		Zone:               a.zone,
		Evacuating:         a.evacuationContext.Evacuating(),
	}

	a.logger.Info("provided", lager.Data{"state": state})

	return state, nil
}

func (a *AuctionCellRep) Perform(work auctiontypes.Work) (auctiontypes.Work, error) {
	var failedWork = auctiontypes.Work{}

	logger := a.logger.Session("auction-work", lager.Data{
		"lrp-starts": len(work.LRPs),
		"tasks":      len(work.Tasks),
	})

	if a.evacuationContext.Evacuating() {
		return work, nil
	}

	if len(work.LRPs) > 0 {
		lrpLogger := logger.Session("lrp-allocate-instances")
		lrpLogger.Info("allocating")
		containers, lrpAuctionMap, err := a.lrpsToContainers(work.LRPs)
		if err != nil {
			failedWork.LRPs = work.LRPs
			lrpLogger.Info("failed-to-allocate")
		} else {
			errMessageMap, err := a.client.AllocateContainers(containers)
			if err != nil {
				failedWork.LRPs = work.LRPs
			} else {
				for guid, lrpStart := range lrpAuctionMap {
					if _, found := errMessageMap[guid]; found {
						failedWork.LRPs = append(failedWork.LRPs, lrpStart)
					}
				}
				lrpLogger.Info("allocated")
			}
		}
	}

	if len(work.Tasks) > 0 {
		taskLogger := logger.Session("task-allocate-instances")
		taskLogger.Info("allocating")
		containers := a.tasksToContainers(work.Tasks)
		errMessageMap, err := a.client.AllocateContainers(containers)
		if err != nil {
			failedWork.Tasks = work.Tasks
			taskLogger.Info("failed-to-allocate")
		} else {
			for _, task := range work.Tasks {
				if _, found := errMessageMap[task.TaskGuid]; found {
					failedWork.Tasks = append(failedWork.Tasks, task)
				}
			}
			taskLogger.Info("allocated")
		}
	}
	return failedWork, nil
}

func (a *AuctionCellRep) lrpsToContainers(lrps []auctiontypes.LRPAuction) ([]executor.Container, map[string]auctiontypes.LRPAuction, error) {
	containers := make([]executor.Container, 0, len(lrps))
	lrpAuctionMap := map[string]auctiontypes.LRPAuction{}

	for _, lrpStart := range lrps {
		lrpStart := lrpStart
		containerGuidString, err := a.generateContainerGuid()
		if err != nil {
			return nil, nil, err
		}
		lrpAuctionMap[containerGuidString] = lrpStart

		container := executor.Container{
			Guid: containerGuidString,

			Tags: executor.Tags{
				rep.LifecycleTag:    rep.LRPLifecycle,
				rep.DomainTag:       lrpStart.DesiredLRP.Domain,
				rep.ProcessGuidTag:  lrpStart.DesiredLRP.ProcessGuid,
				rep.ProcessIndexTag: strconv.Itoa(lrpStart.Index),
			},

			MemoryMB:     lrpStart.DesiredLRP.MemoryMB,
			DiskMB:       lrpStart.DesiredLRP.DiskMB,
			CPUWeight:    lrpStart.DesiredLRP.CPUWeight,
			RootFSPath:   lrpStart.DesiredLRP.RootFSPath,
			Privileged:   lrpStart.DesiredLRP.Privileged,
			Ports:        a.convertPortMappings(lrpStart.DesiredLRP.Ports),
			StartTimeout: lrpStart.DesiredLRP.StartTimeout,

			Log: executor.LogConfig{
				Guid:       lrpStart.DesiredLRP.LogGuid,
				SourceName: lrpStart.DesiredLRP.LogSource,
				Index:      &lrpStart.Index,
			},

			Setup:   lrpStart.DesiredLRP.Setup,
			Action:  lrpStart.DesiredLRP.Action,
			Monitor: lrpStart.DesiredLRP.Monitor,

			Env: append([]executor.EnvironmentVariable{
				{Name: "INSTANCE_GUID", Value: containerGuidString},
				{Name: "INSTANCE_INDEX", Value: strconv.Itoa(lrpStart.Index)},
			}, executor.EnvironmentVariablesFromModel(lrpStart.DesiredLRP.EnvironmentVariables)...),
			EgressRules: lrpStart.DesiredLRP.EgressRules,
		}
		containers = append(containers, container)
	}

	return containers, lrpAuctionMap, nil
}

func (a *AuctionCellRep) tasksToContainers(tasks []models.Task) []executor.Container {
	containers := make([]executor.Container, 0, len(tasks))

	for _, task := range tasks {
		container := executor.Container{
			Guid: task.TaskGuid,

			DiskMB:     task.DiskMB,
			MemoryMB:   task.MemoryMB,
			CPUWeight:  task.CPUWeight,
			RootFSPath: task.RootFSPath,
			Privileged: task.Privileged,
			Log: executor.LogConfig{
				Guid:       task.LogGuid,
				SourceName: task.LogSource,
			},
			Tags: executor.Tags{
				rep.LifecycleTag:  rep.TaskLifecycle,
				rep.DomainTag:     task.Domain,
				rep.ResultFileTag: task.ResultFile,
			},

			Action: task.Action,

			Env:         executor.EnvironmentVariablesFromModel(task.EnvironmentVariables),
			EgressRules: task.EgressRules,
		}
		containers = append(containers, container)
	}

	return containers
}

func (a *AuctionCellRep) convertPortMappings(containerPorts []uint32) []executor.PortMapping {
	out := []executor.PortMapping{}
	for _, port := range containerPorts {
		out = append(out, executor.PortMapping{
			ContainerPort: port,
		})
	}

	return out
}

func (a *AuctionCellRep) fetchResourcesVia(fetcher func() (executor.ExecutorResources, error)) (auctiontypes.Resources, error) {
	resources, err := fetcher()
	if err != nil {
		return auctiontypes.Resources{}, err
	}
	return auctiontypes.Resources{
		MemoryMB:   resources.MemoryMB,
		DiskMB:     resources.DiskMB,
		Containers: resources.Containers,
	}, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"time"

	"github.com/dustin/go-humanize"
)

func main() {
	if len(os.Args) != 2 {
		usageError()
	}

	count, err := humanize.ParseBytes(os.Args[1])
	if err != nil {
		usageError()
	}

	time.Sleep(time.Duration(count) * time.Millisecond)
}

func usageError() {
	fmt.Fprintf(os.Stderr, "Usage: %s <count>\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "Sleep for <count> milliseconds.")
	os.Exit(-1)
}
<commit_msg>use time.ParseDuration()<commit_after>package main

import (
	"fmt"
	"os"
	"time"
)

func main() {
	if len(os.Args) != 2 {
		usageError()
	}
	d, err := time.ParseDuration(os.Args[1])
	if err != nil {
		fmt.Fprintf(os.Stderr, "could not parse duration: %s\n", err)
		usageError()
	}

	time.Sleep(d)
}

func usageError() {
	fmt.Fprintf(os.Stderr, "Usage: %s <duration>\n", os.Args[0])
	fmt.Fprintln(os.Stderr, `Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".`)
	fmt.Fprintf(os.Stderr, "See https://godoc.org/time#ParseDuration for more.")
	os.Exit(-1)
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"strconv"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/ec2"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsCustomerGateway() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsCustomerGatewayCreate,
		Read:   resourceAwsCustomerGatewayRead,
		Update: resourceAwsCustomerGatewayUpdate,
		Delete: resourceAwsCustomerGatewayDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"bgp_asn": {
				Type:     schema.TypeInt,
				Required: true,
				ForceNew: true,
			},

			"ip_address": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"type": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceAwsCustomerGatewayCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	ipAddress := d.Get("ip_address").(string)
	vpnType := d.Get("type").(string)
	bgpAsn := d.Get("bgp_asn").(int)

	alreadyExists, err := resourceAwsCustomerGatewayExists(vpnType, ipAddress, bgpAsn, conn)
	if err != nil {
		return err
	}

	if alreadyExists {
		return fmt.Errorf("An existing customer gateway for IpAddress: %s, VpnType: %s, BGP ASN: %d has been found", ipAddress, vpnType, bgpAsn)
	}

	createOpts := &ec2.CreateCustomerGatewayInput{
		BgpAsn:   aws.Int64(int64(bgpAsn)),
		PublicIp: aws.String(ipAddress),
		Type:     aws.String(vpnType),
	}

	// Create the Customer Gateway.
	log.Printf("[DEBUG] Creating customer gateway")
	resp, err := conn.CreateCustomerGateway(createOpts)
	if err != nil {
		return fmt.Errorf("Error creating customer gateway: %s", err)
	}

	// Store the ID
	customerGateway := resp.CustomerGateway
	d.SetId(*customerGateway.CustomerGatewayId)
	log.Printf("[INFO] Customer gateway ID: %s", *customerGateway.CustomerGatewayId)

	// Wait for the CustomerGateway to be available.
	stateConf := &resource.StateChangeConf{
		Pending:    []string{"pending"},
		Target:     []string{"available"},
		Refresh:    customerGatewayRefreshFunc(conn, *customerGateway.CustomerGatewayId),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, stateErr := stateConf.WaitForState()
	if stateErr != nil {
		return fmt.Errorf(
			"Error waiting for customer gateway (%s) to become ready: %s",
			*customerGateway.CustomerGatewayId, err)
	}

	// Create tags.
	if err := setTags(conn, d); err != nil {
		return err
	}

	return nil
}

func customerGatewayRefreshFunc(conn *ec2.EC2, gatewayId string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		gatewayFilter := &ec2.Filter{
			Name:   aws.String("customer-gateway-id"),
			Values: []*string{aws.String(gatewayId)},
		}

		resp, err := conn.DescribeCustomerGateways(&ec2.DescribeCustomerGatewaysInput{
			Filters: []*ec2.Filter{gatewayFilter},
		})
		if err != nil {
			if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidCustomerGatewayID.NotFound" {
				resp = nil
			} else {
				log.Printf("Error on CustomerGatewayRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil || len(resp.CustomerGateways) == 0 {
			// handle consistency issues
			return nil, "", nil
		}

		gateway := resp.CustomerGateways[0]
		return gateway, *gateway.State, nil
	}
}

func resourceAwsCustomerGatewayExists(vpnType, ipAddress string, bgpAsn int, conn *ec2.EC2) (bool, error) {
	ipAddressFilter := &ec2.Filter{
		Name:   aws.String("ip-address"),
		Values: []*string{aws.String(ipAddress)},
	}

	typeFilter := &ec2.Filter{
		Name:   aws.String("type"),
		Values: []*string{aws.String(vpnType)},
	}

	bgp := strconv.Itoa(bgpAsn)
	bgpAsnFilter := &ec2.Filter{
		Name:   aws.String("bgp-asn"),
		Values: []*string{aws.String(bgp)},
	}

	resp, err := conn.DescribeCustomerGateways(&ec2.DescribeCustomerGatewaysInput{
		Filters: []*ec2.Filter{ipAddressFilter, typeFilter, bgpAsnFilter},
	})
	if err != nil {
		return false, err
	}

	if len(resp.CustomerGateways) > 0 && *resp.CustomerGateways[0].State != "deleted" {
		return true, nil
	}

	return false, nil
}

func resourceAwsCustomerGatewayRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	gatewayFilter := &ec2.Filter{
		Name:   aws.String("customer-gateway-id"),
		Values: []*string{aws.String(d.Id())},
	}

	resp, err := conn.DescribeCustomerGateways(&ec2.DescribeCustomerGatewaysInput{
		Filters: []*ec2.Filter{gatewayFilter},
	})
	if err != nil {
		if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidCustomerGatewayID.NotFound" {
			d.SetId("")
			return nil
		} else {
			log.Printf("[ERROR] Error finding CustomerGateway: %s", err)
			return err
		}
	}

	if len(resp.CustomerGateways) != 1 {
		return fmt.Errorf("Error finding CustomerGateway: %s", d.Id())
	}

	if *resp.CustomerGateways[0].State == "deleted" {
		log.Printf("[INFO] Customer Gateway is in `deleted` state: %s", d.Id())
		d.SetId("")
		return nil
	}

	customerGateway := resp.CustomerGateways[0]
	d.Set("ip_address", customerGateway.IpAddress)
	d.Set("type", customerGateway.Type)
	d.Set("tags", tagsToMap(customerGateway.Tags))

	if *customerGateway.BgpAsn != "" {
		val, err := strconv.ParseInt(*customerGateway.BgpAsn, 0, 0)
		if err != nil {
			return fmt.Errorf("error parsing bgp_asn: %s", err)
		}

		d.Set("bgp_asn", int(val))
	}

	return nil
}

func resourceAwsCustomerGatewayUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	// Update tags if required.
	if err := setTags(conn, d); err != nil {
		return err
	}

	d.SetPartial("tags")

	return resourceAwsCustomerGatewayRead(d, meta)
}

func resourceAwsCustomerGatewayDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	_, err := conn.DeleteCustomerGateway(&ec2.DeleteCustomerGatewayInput{
		CustomerGatewayId: aws.String(d.Id()),
	})
	if err != nil {
		if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidCustomerGatewayID.NotFound" {
			return nil
		} else {
			log.Printf("[ERROR] Error deleting CustomerGateway: %s", err)
			return err
		}
	}

	gatewayFilter := &ec2.Filter{
		Name:   aws.String("customer-gateway-id"),
		Values: []*string{aws.String(d.Id())},
	}

	err = resource.Retry(5*time.Minute, func() *resource.RetryError {
		resp, err := conn.DescribeCustomerGateways(&ec2.DescribeCustomerGatewaysInput{
			Filters: []*ec2.Filter{gatewayFilter},
		})

		if err != nil {
			if awserr, ok := err.(awserr.Error); ok && awserr.Code() == "InvalidCustomerGatewayID.NotFound" {
				return nil
			}
			return resource.NonRetryableError(err)
		}

		if len(resp.CustomerGateways) != 1 {
			return resource.RetryableError(fmt.Errorf("Error finding CustomerGateway for delete: %s", d.Id()))
		}

		switch *resp.CustomerGateways[0].State {
		case "pending", "available", "deleting":
			return resource.RetryableError(fmt.Errorf("Gateway (%s) in state (%s), retrying", d.Id(), *resp.CustomerGateways[0].State))
		case "deleted":
			return nil
		default:
			return resource.RetryableError(fmt.Errorf("Unrecognized state (%s) for Customer Gateway delete on (%s)", *resp.CustomerGateways[0].State, d.Id()))
		}
	})

	return err
}
<commit_msg>Final retry after timeout deleting customer gateway<commit_after>package aws

import (
	"fmt"
	"log"
	"strconv"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/ec2"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsCustomerGateway() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsCustomerGatewayCreate,
		Read:   resourceAwsCustomerGatewayRead,
		Update: resourceAwsCustomerGatewayUpdate,
		Delete: resourceAwsCustomerGatewayDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"bgp_asn": {
				Type:     schema.TypeInt,
				Required: true,
				ForceNew: true,
			},

			"ip_address": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"type": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceAwsCustomerGatewayCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	ipAddress := d.Get("ip_address").(string)
	vpnType := d.Get("type").(string)
	bgpAsn := d.Get("bgp_asn").(int)

	alreadyExists, err := resourceAwsCustomerGatewayExists(vpnType, ipAddress, bgpAsn, conn)
	if err != nil {
		return err
	}

	if alreadyExists {
		return fmt.Errorf("An existing customer gateway for IpAddress: %s, VpnType: %s, BGP ASN: %d has been found", ipAddress, vpnType, bgpAsn)
	}

	createOpts := &ec2.CreateCustomerGatewayInput{
		BgpAsn:   aws.Int64(int64(bgpAsn)),
		PublicIp: aws.String(ipAddress),
		Type:     aws.String(vpnType),
	}

	// Create the Customer Gateway.
	log.Printf("[DEBUG] Creating customer gateway")
	resp, err := conn.CreateCustomerGateway(createOpts)
	if err != nil {
		return fmt.Errorf("Error creating customer gateway: %s", err)
	}

	// Store the ID
	customerGateway := resp.CustomerGateway
	d.SetId(*customerGateway.CustomerGatewayId)
	log.Printf("[INFO] Customer gateway ID: %s", *customerGateway.CustomerGatewayId)

	// Wait for the CustomerGateway to be available.
	stateConf := &resource.StateChangeConf{
		Pending:    []string{"pending"},
		Target:     []string{"available"},
		Refresh:    customerGatewayRefreshFunc(conn, *customerGateway.CustomerGatewayId),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, stateErr := stateConf.WaitForState()
	if stateErr != nil {
		return fmt.Errorf(
			"Error waiting for customer gateway (%s) to become ready: %s",
			*customerGateway.CustomerGatewayId, err)
	}

	// Create tags.
	if err := setTags(conn, d); err != nil {
		return err
	}

	return nil
}

func customerGatewayRefreshFunc(conn *ec2.EC2, gatewayId string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		gatewayFilter := &ec2.Filter{
			Name:   aws.String("customer-gateway-id"),
			Values: []*string{aws.String(gatewayId)},
		}

		resp, err := conn.DescribeCustomerGateways(&ec2.DescribeCustomerGatewaysInput{
			Filters: []*ec2.Filter{gatewayFilter},
		})
		if err != nil {
			if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidCustomerGatewayID.NotFound" {
				resp = nil
			} else {
				log.Printf("Error on CustomerGatewayRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil || len(resp.CustomerGateways) == 0 {
			// handle consistency issues
			return nil, "", nil
		}

		gateway := resp.CustomerGateways[0]
		return gateway, *gateway.State, nil
	}
}

func resourceAwsCustomerGatewayExists(vpnType, ipAddress string, bgpAsn int, conn *ec2.EC2) (bool, error) {
	ipAddressFilter := &ec2.Filter{
		Name:   aws.String("ip-address"),
		Values: []*string{aws.String(ipAddress)},
	}

	typeFilter := &ec2.Filter{
		Name:   aws.String("type"),
		Values: []*string{aws.String(vpnType)},
	}

	bgp := strconv.Itoa(bgpAsn)
	bgpAsnFilter := &ec2.Filter{
		Name:   aws.String("bgp-asn"),
		Values: []*string{aws.String(bgp)},
	}

	resp, err := conn.DescribeCustomerGateways(&ec2.DescribeCustomerGatewaysInput{
		Filters: []*ec2.Filter{ipAddressFilter, typeFilter, bgpAsnFilter},
	})
	if err != nil {
		return false, err
	}

	if len(resp.CustomerGateways) > 0 && *resp.CustomerGateways[0].State != "deleted" {
		return true, nil
	}

	return false, nil
}

func resourceAwsCustomerGatewayRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	gatewayFilter := &ec2.Filter{
		Name:   aws.String("customer-gateway-id"),
		Values: []*string{aws.String(d.Id())},
	}

	resp, err := conn.DescribeCustomerGateways(&ec2.DescribeCustomerGatewaysInput{
		Filters: []*ec2.Filter{gatewayFilter},
	})
	if err != nil {
		if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidCustomerGatewayID.NotFound" {
			d.SetId("")
			return nil
		} else {
			log.Printf("[ERROR] Error finding CustomerGateway: %s", err)
			return err
		}
	}

	if len(resp.CustomerGateways) != 1 {
		return fmt.Errorf("Error finding CustomerGateway: %s", d.Id())
	}

	if *resp.CustomerGateways[0].State == "deleted" {
		log.Printf("[INFO] Customer Gateway is in `deleted` state: %s", d.Id())
		d.SetId("")
		return nil
	}

	customerGateway := resp.CustomerGateways[0]
	d.Set("ip_address", customerGateway.IpAddress)
	d.Set("type", customerGateway.Type)
	d.Set("tags", tagsToMap(customerGateway.Tags))

	if *customerGateway.BgpAsn != "" {
		val, err := strconv.ParseInt(*customerGateway.BgpAsn, 0, 0)
		if err != nil {
			return fmt.Errorf("error parsing bgp_asn: %s", err)
		}

		d.Set("bgp_asn", int(val))
	}

	return nil
}

func resourceAwsCustomerGatewayUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	// Update tags if required.
	if err := setTags(conn, d); err != nil {
		return err
	}

	d.SetPartial("tags")

	return resourceAwsCustomerGatewayRead(d, meta)
}

func resourceAwsCustomerGatewayDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	_, err := conn.DeleteCustomerGateway(&ec2.DeleteCustomerGatewayInput{
		CustomerGatewayId: aws.String(d.Id()),
	})
	if err != nil {
		if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidCustomerGatewayID.NotFound" {
			return nil
		} else {
			return fmt.Errorf("[ERROR] Error deleting CustomerGateway: %s", err)
		}
	}

	gatewayFilter := &ec2.Filter{
		Name:   aws.String("customer-gateway-id"),
		Values: []*string{aws.String(d.Id())},
	}

	input := &ec2.DescribeCustomerGatewaysInput{
		Filters: []*ec2.Filter{gatewayFilter},
	}
	err = resource.Retry(5*time.Minute, func() *resource.RetryError {
		resp, err := conn.DescribeCustomerGateways(input)

		if err != nil {
			if isAWSErr(err, "InvalidCustomerGatewayID.NotFound", "") {
				return nil
			}
			return resource.NonRetryableError(err)
		}

		err = checkGatewayDeleteResponse(resp, d.Id())
		if err != nil {
			return resource.RetryableError(err)
		}
		return nil
	})

	if isResourceTimeoutError(err) {
		var resp *ec2.DescribeCustomerGatewaysOutput
		resp, err = conn.DescribeCustomerGateways(input)

		if err != nil {
			return checkGatewayDeleteResponse(resp, d.Id())
		}
	}

	if err != nil {
		return fmt.Errorf("Error deleting customer gateway: %s", err)
	}
	return nil

}

func checkGatewayDeleteResponse(resp *ec2.DescribeCustomerGatewaysOutput, id string) error {
	if len(resp.CustomerGateways) != 1 {
		return fmt.Errorf("Error finding CustomerGateway for delete: %s", id)
	}

	switch *resp.CustomerGateways[0].State {
	case "pending", "available", "deleting":
		return fmt.Errorf("Gateway (%s) in state (%s), retrying", id, *resp.CustomerGateways[0].State)
	case "deleted":
		return nil
	default:
		return fmt.Errorf("Unrecognized state (%s) for Customer Gateway delete on (%s)", *resp.CustomerGateways[0].State, id)
	}
}
<|endoftext|>