<commit_before>package sarama

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"reflect"
	"strconv"
	"sync"
	"time"

	"github.com/davecgh/go-spew/spew"
)

type requestHandlerFunc func(req *request) (res encoder)

// RequestNotifierFunc is invoked when a mock broker processes a request successfully
// and will provides the number of bytes read and written.
type RequestNotifierFunc func(bytesRead, bytesWritten int)

// MockBroker is a mock Kafka broker that is used in unit tests. It is exposed
// to facilitate testing of higher level or specialized consumers and producers
// built on top of Sarama. Note that it does not 'mimic' the Kafka API protocol,
// but rather provides a facility to do that. It takes care of the TCP
// transport, request unmarshaling, response marshaling, and makes it the test
// writer responsibility to program correct according to the Kafka API protocol
// MockBroker behaviour.
//
// MockBroker is implemented as a TCP server listening on a kernel-selected
// localhost port that can accept many connections. It reads Kafka requests
// from that connection and returns responses programmed by the SetHandlerByMap
// function. If a MockBroker receives a request that it has no programmed
// response for, then it returns nothing and the request times out.
//
// A set of MockRequest builders to define mappings used by MockBroker is
// provided by Sarama. But users can develop MockRequests of their own and use
// them along with or instead of the standard ones.
//
// When running tests with MockBroker it is strongly recommended to specify
// a timeout to `go test` so that if the broker hangs waiting for a response,
// the test panics.
//
// It is not necessary to prefix message length or correlation ID to your
// response bytes, the server does that automatically as a convenience.
type MockBroker struct {
	brokerID           int32
	port               int32
	closing            chan none
	stopper            chan none
	expectations       chan encoder
	listener           net.Listener
	t                  TestReporter
	latency            time.Duration
	handler            requestHandlerFunc
	notifier           RequestNotifierFunc
	history            []RequestResponse
	lock               sync.Mutex
	expectationTimeout time.Duration
}

// RequestResponse represents a Request/Response pair processed by MockBroker.
type RequestResponse struct {
	Request  protocolBody
	Response encoder
}

// SetLatency makes broker pause for the specified period every time before
// replying.
func (b *MockBroker) SetLatency(latency time.Duration) {
	b.latency = latency
}

// SetHandlerByMap defines mapping of Request types to MockResponses. When a
// request is received by the broker, it looks up the request type in the map
// and uses the found MockResponse instance to generate an appropriate reply.
// If the request type is not found in the map default request handler is used
func (b *MockBroker) SetHandlerByMap(handlerMap map[string]MockResponse) {
	b.setHandler(func(req *request) (res encoder) {
		reqTypeName := reflect.TypeOf(req.body).Elem().Name()
		mockResponse := handlerMap[reqTypeName]
		if mockResponse == nil {
			return b.defaultRequestHandler(req)
		}
		return mockResponse.For(req.body)
	})
}

// SetNotifier set a function that will get invoked whenever a request has been
// processed successfully and will provide the number of bytes read and written
func (b *MockBroker) SetNotifier(notifier RequestNotifierFunc) {
	b.lock.Lock()
	b.notifier = notifier
	b.lock.Unlock()
}

// BrokerID returns broker ID assigned to the broker.
func (b *MockBroker) BrokerID() int32 {
	return b.brokerID
}

// History returns a slice of RequestResponse pairs in the order they were
// processed by the broker. Note that in case of multiple connections to the
// broker the order expected by a test can be different from the order recorded
// in the history, unless some synchronization is implemented in the test.
func (b *MockBroker) History() []RequestResponse {
	b.lock.Lock()
	history := make([]RequestResponse, len(b.history))
	copy(history, b.history)
	b.lock.Unlock()
	return history
}

// Port returns the TCP port number the broker is listening for requests on.
func (b *MockBroker) Port() int32 {
	return b.port
}

// Addr returns the broker connection string in the form "<address>:<port>".
func (b *MockBroker) Addr() string {
	return b.listener.Addr().String()
}

// Close terminates the broker blocking until it stops internal goroutines and
// releases all resources.
func (b *MockBroker) Close() {
	close(b.expectations)
	if len(b.expectations) > 0 {
		buf := bytes.NewBufferString(fmt.Sprintf("mockbroker/%d: not all expectations were satisfied! Still waiting on:\n", b.BrokerID()))
		for e := range b.expectations {
			_, _ = buf.WriteString(spew.Sdump(e))
		}
		b.t.Error(buf.String())
	}
	close(b.closing)
	<-b.stopper
}

// setHandler sets the specified function as the request handler. Whenever
// a mock broker reads a request from the wire it passes the request to the
// function and sends back whatever the handler function returns.
func (b *MockBroker) setHandler(handler requestHandlerFunc) {
	b.lock.Lock()
	b.handler = handler
	b.lock.Unlock()
}

func (b *MockBroker) serverLoop() {
	defer close(b.stopper)
	var err error
	var conn net.Conn

	go func() {
		<-b.closing
		err := b.listener.Close()
		if err != nil {
			b.t.Error(err)
		}
	}()

	wg := &sync.WaitGroup{}
	i := 0
	for conn, err = b.listener.Accept(); err == nil; conn, err = b.listener.Accept() {
		wg.Add(1)
		go b.handleRequests(conn, i, wg)
		i++
	}
	wg.Wait()
	Logger.Printf("*** mockbroker/%d: listener closed, err=%v", b.BrokerID(), err)
}

func (b *MockBroker) handleRequests(conn net.Conn, idx int, wg *sync.WaitGroup) {
	defer wg.Done()
	defer func() {
		_ = conn.Close()
	}()
	Logger.Printf("*** mockbroker/%d/%d: connection opened", b.BrokerID(), idx)
	var err error

	abort := make(chan none)
	defer close(abort)
	go func() {
		select {
		case <-b.closing:
			_ = conn.Close()
		case <-abort:
		}
	}()

	resHeader := make([]byte, 8)
	for {
		req, bytesRead, err := decodeRequest(conn)
		if err != nil {
			Logger.Printf("*** mockbroker/%d/%d: invalid request: err=%+v, %+v", b.brokerID, idx, err, spew.Sdump(req))
			b.serverError(err)
			break
		}

		if b.latency > 0 {
			time.Sleep(b.latency)
		}

		b.lock.Lock()
		res := b.handler(req)
		b.history = append(b.history, RequestResponse{req.body, res})
		b.lock.Unlock()

		if res == nil {
			Logger.Printf("*** mockbroker/%d/%d: ignored %v", b.brokerID, idx, spew.Sdump(req))
			continue
		}
		Logger.Printf("*** mockbroker/%d/%d: served %v -> %v", b.brokerID, idx, req, res)

		encodedRes, err := encode(res, nil)
		if err != nil {
			b.serverError(err)
			break
		}
		if len(encodedRes) == 0 {
			b.lock.Lock()
			if b.notifier != nil {
				b.notifier(bytesRead, 0)
			}
			b.lock.Unlock()
			continue
		}

		binary.BigEndian.PutUint32(resHeader, uint32(len(encodedRes)+4))
		binary.BigEndian.PutUint32(resHeader[4:], uint32(req.correlationID))
		if _, err = conn.Write(resHeader); err != nil {
			b.serverError(err)
			break
		}
		if _, err = conn.Write(encodedRes); err != nil {
			b.serverError(err)
			break
		}

		b.lock.Lock()
		if b.notifier != nil {
			b.notifier(bytesRead, len(resHeader)+len(encodedRes))
		}
		b.lock.Unlock()
	}
	Logger.Printf("*** mockbroker/%d/%d: connection closed, err=%v", b.BrokerID(), idx, err)
}

func (b *MockBroker) getRequestType(req *request) int {
	switch req.body.(type) {
	case *ProduceRequest:
		return apiKeyProduce
	case *FetchRequest:
		return apiKeyFetch
	case *OffsetRequest:
		return apiKeyListOffsets
	case *MetadataRequest:
		return apiKeyMetadata
	case *OffsetCommitRequest:
		return apiKeyOffsetCommit
	case *OffsetFetchRequest:
		return apiKeyOffsetFetch
	case *ConsumerMetadataRequest:
		return apiKeyFindCoordinator
	case *JoinGroupRequest:
		return apiKeyJoinGroup
	case *HeartbeatRequest:
		return apiKeyHeartbeat
	case *LeaveGroupRequest:
		return apiKeyLeaveGroup
	case *SyncGroupRequest:
		return apiKeySyncGroup
	case *DescribeGroupsRequest:
		return apiKeyDescribeGroups
	case *ListGroupsRequest:
		return apiKeyListGroups
	case *SaslHandshakeRequest:
		return apiKeySaslHandshake
	case *ApiVersionsRequest:
		return apiKeyApiVersions
	default:
		b.t.Errorf("Unknown request %v", reflect.TypeOf(req.body).Elem().Name())
		return -1
	}
}

func (b *MockBroker) getResponseType(res encoder) int {
	switch res.(type) {
	case *ProduceResponse:
		return apiKeyProduce
	case *FetchResponse:
		return apiKeyFetch
	case *OffsetResponse:
		return apiKeyListOffsets
	case *MetadataResponse:
		return apiKeyMetadata
	case *OffsetCommitResponse:
		return apiKeyOffsetCommit
	case *OffsetFetchResponse:
		return apiKeyOffsetFetch
	case *ConsumerMetadataResponse:
		return apiKeyFindCoordinator
	case *JoinGroupResponse:
		return apiKeyJoinGroup
	case *HeartbeatResponse:
		return apiKeyHeartbeat
	case *SyncGroupResponse:
		return apiKeySyncGroup
	case *LeaveGroupResponse:
		return apiKeyLeaveGroup
	case *ListGroupsResponse:
		return apiKeyListGroups
	case *DescribeGroupsResponse:
		return apiKeyDescribeGroups
	case *ApiVersionsResponse:
		return apiKeyApiVersions
	default:
		return -1
	}
}

func (b *MockBroker) matchRequestAndResponse(req *request, res encoder) {
	reqType := b.getRequestType(req)
	resType := b.getResponseType(res)
	if resType == -1 {
		// Response is Unknown is OK
		return
	}

	if reqType != resType {
		b.t.Errorf("Request type %v does not match response %v",
			reflect.TypeOf(req.body).Elem().Name(),
			reflect.TypeOf(res).Elem().Name())
	}
}

func (b *MockBroker) defaultRequestHandler(req *request) (res encoder) {
	select {
	case res, ok := <-b.expectations:
		if !ok {
			return nil
		}
		b.matchRequestAndResponse(req, res)
		return res
	case <-time.After(b.expectationTimeout):
		fmt.Printf("Timeout when requesting %v from broker %v\n", reflect.TypeOf(req.body).Elem().Name(), b.BrokerID())
		return nil
	}
}

func (b *MockBroker) serverError(err error) {
	isConnectionClosedError := false
	if _, ok := err.(*net.OpError); ok {
		isConnectionClosedError = true
	} else if err == io.EOF {
		isConnectionClosedError = true
	} else if err.Error() == "use of closed network connection" {
		isConnectionClosedError = true
	}

	if isConnectionClosedError {
		return
	}

	b.t.Errorf(err.Error())
}

// NewMockBroker launches a fake Kafka broker. It takes a TestReporter as provided by the
// test framework and a channel of responses to use.  If an error occurs it is
// simply logged to the TestReporter and the broker exits.
func NewMockBroker(t TestReporter, brokerID int32) *MockBroker {
	return NewMockBrokerAddr(t, brokerID, "localhost:0")
}

// NewMockBrokerAddr behaves like newMockBroker but listens on the address you give
// it rather than just some ephemeral port.
func NewMockBrokerAddr(t TestReporter, brokerID int32, addr string) *MockBroker {
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		t.Fatal(err)
	}
	return NewMockBrokerListener(t, brokerID, listener)
}

// NewMockBrokerListener behaves like newMockBrokerAddr but accepts connections on the listener specified.
func NewMockBrokerListener(t TestReporter, brokerID int32, listener net.Listener) *MockBroker {
	var err error

	broker := &MockBroker{
		closing:  make(chan none),
		stopper:  make(chan none),
		t:        t,
		brokerID: brokerID,
		listener: listener,
		// TODO: remove remerge only expectations?
		expectations:       make(chan encoder, 512),
		expectationTimeout: 500 * time.Millisecond,
	}
	broker.handler = broker.defaultRequestHandler

	Logger.Printf("*** mockbroker/%d listening on %s\n", brokerID, broker.listener.Addr().String())
	_, portStr, err := net.SplitHostPort(broker.listener.Addr().String())
	if err != nil {
		t.Fatal(err)
	}
	tmp, err := strconv.ParseInt(portStr, 10, 32)
	if err != nil {
		t.Fatal(err)
	}
	broker.port = int32(tmp)

	go broker.serverLoop()

	return broker
}

func (b *MockBroker) Returns(e encoder) {
	b.expectations <- e
}
<commit_msg>fix wrongly named case in mock broker<commit_after>package sarama

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"reflect"
	"strconv"
	"sync"
	"time"

	"github.com/davecgh/go-spew/spew"
)

type requestHandlerFunc func(req *request) (res encoder)

// RequestNotifierFunc is invoked when a mock broker processes a request successfully
// and will provides the number of bytes read and written.
type RequestNotifierFunc func(bytesRead, bytesWritten int)

// MockBroker is a mock Kafka broker that is used in unit tests. It is exposed
// to facilitate testing of higher level or specialized consumers and producers
// built on top of Sarama. Note that it does not 'mimic' the Kafka API protocol,
// but rather provides a facility to do that. It takes care of the TCP
// transport, request unmarshaling, response marshaling, and makes it the test
// writer responsibility to program correct according to the Kafka API protocol
// MockBroker behaviour.
//
// MockBroker is implemented as a TCP server listening on a kernel-selected
// localhost port that can accept many connections. It reads Kafka requests
// from that connection and returns responses programmed by the SetHandlerByMap
// function. If a MockBroker receives a request that it has no programmed
// response for, then it returns nothing and the request times out.
//
// A set of MockRequest builders to define mappings used by MockBroker is
// provided by Sarama. But users can develop MockRequests of their own and use
// them along with or instead of the standard ones.
//
// When running tests with MockBroker it is strongly recommended to specify
// a timeout to `go test` so that if the broker hangs waiting for a response,
// the test panics.
//
// It is not necessary to prefix message length or correlation ID to your
// response bytes, the server does that automatically as a convenience.
type MockBroker struct {
	brokerID           int32
	port               int32
	closing            chan none
	stopper            chan none
	expectations       chan encoder
	listener           net.Listener
	t                  TestReporter
	latency            time.Duration
	handler            requestHandlerFunc
	notifier           RequestNotifierFunc
	history            []RequestResponse
	lock               sync.Mutex
	expectationTimeout time.Duration
}

// RequestResponse represents a Request/Response pair processed by MockBroker.
type RequestResponse struct {
	Request  protocolBody
	Response encoder
}

// SetLatency makes broker pause for the specified period every time before
// replying.
func (b *MockBroker) SetLatency(latency time.Duration) {
	b.latency = latency
}

// SetHandlerByMap defines mapping of Request types to MockResponses. When a
// request is received by the broker, it looks up the request type in the map
// and uses the found MockResponse instance to generate an appropriate reply.
// If the request type is not found in the map default request handler is used
func (b *MockBroker) SetHandlerByMap(handlerMap map[string]MockResponse) {
	b.setHandler(func(req *request) (res encoder) {
		reqTypeName := reflect.TypeOf(req.body).Elem().Name()
		mockResponse := handlerMap[reqTypeName]
		if mockResponse == nil {
			return b.defaultRequestHandler(req)
		}
		return mockResponse.For(req.body)
	})
}

// SetNotifier set a function that will get invoked whenever a request has been
// processed successfully and will provide the number of bytes read and written
func (b *MockBroker) SetNotifier(notifier RequestNotifierFunc) {
	b.lock.Lock()
	b.notifier = notifier
	b.lock.Unlock()
}

// BrokerID returns broker ID assigned to the broker.
func (b *MockBroker) BrokerID() int32 {
	return b.brokerID
}

// History returns a slice of RequestResponse pairs in the order they were
// processed by the broker. Note that in case of multiple connections to the
// broker the order expected by a test can be different from the order recorded
// in the history, unless some synchronization is implemented in the test.
func (b *MockBroker) History() []RequestResponse {
	b.lock.Lock()
	history := make([]RequestResponse, len(b.history))
	copy(history, b.history)
	b.lock.Unlock()
	return history
}

// Port returns the TCP port number the broker is listening for requests on.
func (b *MockBroker) Port() int32 {
	return b.port
}

// Addr returns the broker connection string in the form "<address>:<port>".
func (b *MockBroker) Addr() string {
	return b.listener.Addr().String()
}

// Close terminates the broker blocking until it stops internal goroutines and
// releases all resources.
func (b *MockBroker) Close() {
	close(b.expectations)
	if len(b.expectations) > 0 {
		buf := bytes.NewBufferString(fmt.Sprintf("mockbroker/%d: not all expectations were satisfied! Still waiting on:\n", b.BrokerID()))
		for e := range b.expectations {
			_, _ = buf.WriteString(spew.Sdump(e))
		}
		b.t.Error(buf.String())
	}
	close(b.closing)
	<-b.stopper
}

// setHandler sets the specified function as the request handler. Whenever
// a mock broker reads a request from the wire it passes the request to the
// function and sends back whatever the handler function returns.
func (b *MockBroker) setHandler(handler requestHandlerFunc) {
	b.lock.Lock()
	b.handler = handler
	b.lock.Unlock()
}

func (b *MockBroker) serverLoop() {
	defer close(b.stopper)
	var err error
	var conn net.Conn

	go func() {
		<-b.closing
		err := b.listener.Close()
		if err != nil {
			b.t.Error(err)
		}
	}()

	wg := &sync.WaitGroup{}
	i := 0
	for conn, err = b.listener.Accept(); err == nil; conn, err = b.listener.Accept() {
		wg.Add(1)
		go b.handleRequests(conn, i, wg)
		i++
	}
	wg.Wait()
	Logger.Printf("*** mockbroker/%d: listener closed, err=%v", b.BrokerID(), err)
}

func (b *MockBroker) handleRequests(conn net.Conn, idx int, wg *sync.WaitGroup) {
	defer wg.Done()
	defer func() {
		_ = conn.Close()
	}()
	Logger.Printf("*** mockbroker/%d/%d: connection opened", b.BrokerID(), idx)
	var err error

	abort := make(chan none)
	defer close(abort)
	go func() {
		select {
		case <-b.closing:
			_ = conn.Close()
		case <-abort:
		}
	}()

	resHeader := make([]byte, 8)
	for {
		req, bytesRead, err := decodeRequest(conn)
		if err != nil {
			Logger.Printf("*** mockbroker/%d/%d: invalid request: err=%+v, %+v", b.brokerID, idx, err, spew.Sdump(req))
			b.serverError(err)
			break
		}

		if b.latency > 0 {
			time.Sleep(b.latency)
		}

		b.lock.Lock()
		res := b.handler(req)
		b.history = append(b.history, RequestResponse{req.body, res})
		b.lock.Unlock()

		if res == nil {
			Logger.Printf("*** mockbroker/%d/%d: ignored %v", b.brokerID, idx, spew.Sdump(req))
			continue
		}
		Logger.Printf("*** mockbroker/%d/%d: served %v -> %v", b.brokerID, idx, req, res)

		encodedRes, err := encode(res, nil)
		if err != nil {
			b.serverError(err)
			break
		}
		if len(encodedRes) == 0 {
			b.lock.Lock()
			if b.notifier != nil {
				b.notifier(bytesRead, 0)
			}
			b.lock.Unlock()
			continue
		}

		binary.BigEndian.PutUint32(resHeader, uint32(len(encodedRes)+4))
		binary.BigEndian.PutUint32(resHeader[4:], uint32(req.correlationID))
		if _, err = conn.Write(resHeader); err != nil {
			b.serverError(err)
			break
		}
		if _, err = conn.Write(encodedRes); err != nil {
			b.serverError(err)
			break
		}

		b.lock.Lock()
		if b.notifier != nil {
			b.notifier(bytesRead, len(resHeader)+len(encodedRes))
		}
		b.lock.Unlock()
	}
	Logger.Printf("*** mockbroker/%d/%d: connection closed, err=%v", b.BrokerID(), idx, err)
}

func (b *MockBroker) getRequestType(req *request) int {
	switch req.body.(type) {
	case *ProduceRequest:
		return apiKeyProduce
	case *FetchRequest:
		return apiKeyFetch
	case *OffsetRequest:
		return apiKeyListOffsets
	case *MetadataRequest:
		return apiKeyMetadata
	case *OffsetCommitRequest:
		return apiKeyOffsetCommit
	case *OffsetFetchRequest:
		return apiKeyOffsetFetch
	case *FindCoordinatorRequest:
		return apiKeyFindCoordinator
	case *JoinGroupRequest:
		return apiKeyJoinGroup
	case *HeartbeatRequest:
		return apiKeyHeartbeat
	case *LeaveGroupRequest:
		return apiKeyLeaveGroup
	case *SyncGroupRequest:
		return apiKeySyncGroup
	case *DescribeGroupsRequest:
		return apiKeyDescribeGroups
	case *ListGroupsRequest:
		return apiKeyListGroups
	case *SaslHandshakeRequest:
		return apiKeySaslHandshake
	case *ApiVersionsRequest:
		return apiKeyApiVersions
	default:
		b.t.Errorf("Unknown request %v", reflect.TypeOf(req.body).Elem().Name())
		return -1
	}
}

func (b *MockBroker) getResponseType(res encoder) int {
	switch res.(type) {
	case *ProduceResponse:
		return apiKeyProduce
	case *FetchResponse:
		return apiKeyFetch
	case *OffsetResponse:
		return apiKeyListOffsets
	case *MetadataResponse:
		return apiKeyMetadata
	case *OffsetCommitResponse:
		return apiKeyOffsetCommit
	case *OffsetFetchResponse:
		return apiKeyOffsetFetch
	case *ConsumerMetadataResponse:
		return apiKeyFindCoordinator
	case *JoinGroupResponse:
		return apiKeyJoinGroup
	case *HeartbeatResponse:
		return apiKeyHeartbeat
	case *SyncGroupResponse:
		return apiKeySyncGroup
	case *LeaveGroupResponse:
		return apiKeyLeaveGroup
	case *ListGroupsResponse:
		return apiKeyListGroups
	case *DescribeGroupsResponse:
		return apiKeyDescribeGroups
	case *ApiVersionsResponse:
		return apiKeyApiVersions
	default:
		return -1
	}
}

func (b *MockBroker) matchRequestAndResponse(req *request, res encoder) {
	reqType := b.getRequestType(req)
	resType := b.getResponseType(res)
	if resType == -1 {
		// Response is Unknown is OK
		return
	}

	if reqType != resType {
		b.t.Errorf("Request type %v does not match response %v",
			reflect.TypeOf(req.body).Elem().Name(),
			reflect.TypeOf(res).Elem().Name())
	}
}

func (b *MockBroker) defaultRequestHandler(req *request) (res encoder) {
	select {
	case res, ok := <-b.expectations:
		if !ok {
			return nil
		}
		b.matchRequestAndResponse(req, res)
		return res
	case <-time.After(b.expectationTimeout):
		fmt.Printf("Timeout when requesting %v from broker %v\n", reflect.TypeOf(req.body).Elem().Name(), b.BrokerID())
		return nil
	}
}

func (b *MockBroker) serverError(err error) {
	isConnectionClosedError := false
	if _, ok := err.(*net.OpError); ok {
		isConnectionClosedError = true
	} else if err == io.EOF {
		isConnectionClosedError = true
	} else if err.Error() == "use of closed network connection" {
		isConnectionClosedError = true
	}

	if isConnectionClosedError {
		return
	}

	b.t.Errorf(err.Error())
}

// NewMockBroker launches a fake Kafka broker. It takes a TestReporter as provided by the
// test framework and a channel of responses to use.  If an error occurs it is
// simply logged to the TestReporter and the broker exits.
func NewMockBroker(t TestReporter, brokerID int32) *MockBroker {
	return NewMockBrokerAddr(t, brokerID, "localhost:0")
}

// NewMockBrokerAddr behaves like newMockBroker but listens on the address you give
// it rather than just some ephemeral port.
func NewMockBrokerAddr(t TestReporter, brokerID int32, addr string) *MockBroker {
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		t.Fatal(err)
	}
	return NewMockBrokerListener(t, brokerID, listener)
}

// NewMockBrokerListener behaves like newMockBrokerAddr but accepts connections on the listener specified.
func NewMockBrokerListener(t TestReporter, brokerID int32, listener net.Listener) *MockBroker {
	var err error

	broker := &MockBroker{
		closing:  make(chan none),
		stopper:  make(chan none),
		t:        t,
		brokerID: brokerID,
		listener: listener,
		// TODO: remove remerge only expectations?
		expectations:       make(chan encoder, 512),
		expectationTimeout: 500 * time.Millisecond,
	}
	broker.handler = broker.defaultRequestHandler

	Logger.Printf("*** mockbroker/%d listening on %s\n", brokerID, broker.listener.Addr().String())
	_, portStr, err := net.SplitHostPort(broker.listener.Addr().String())
	if err != nil {
		t.Fatal(err)
	}
	tmp, err := strconv.ParseInt(portStr, 10, 32)
	if err != nil {
		t.Fatal(err)
	}
	broker.port = int32(tmp)

	go broker.serverLoop()

	return broker
}

func (b *MockBroker) Returns(e encoder) {
	b.expectations <- e
}
<|endoftext|>


<commit_before>package net

import (
	"fmt"
	"strings"

	boshsettings "github.com/cloudfoundry/bosh-agent/settings"
	bosherr "github.com/cloudfoundry/bosh-utils/errors"
	boshlog "github.com/cloudfoundry/bosh-utils/logger"
	boshsys "github.com/cloudfoundry/bosh-utils/system"
)

type WindowsNetManager struct {
	psRunner boshsys.PSRunner

	logTag string
	logger boshlog.Logger
}

func NewWindowsNetManager(psRunner boshsys.PSRunner, logger boshlog.Logger) Manager {
	return WindowsNetManager{
		psRunner: psRunner,

		logTag: "WindowsNetManager",
		logger: logger,
	}
}

const (
	SetDNSTemplate = `
[array]$interfaces = Get-DNSClientServerAddress
$dns = @("%s")
foreach($interface in $interfaces) {
	Set-DnsClientServerAddress -InterfaceAlias $interface.InterfaceAlias -ServerAddresses ($dns -join ",")
}
`

	ResetDNSTemplate = `
[array]$interfaces = Get-DNSClientServerAddress
foreach($interface in $interfaces) {
	Set-DnsClientServerAddress -InterfaceAlias $interface.InterfaceAlias -ResetServerAddresses
}
`

	NicSettingsTemplate = `
$connectionName=(get-wmiobject win32_networkadapter | where-object {$_.MacAddress -eq '%s'}).netconnectionid
netsh interface ip set address $connectionName static %s %s %s
`
)

func (net WindowsNetManager) SetupNetworking(networks boshsettings.Networks, errCh chan error) error {

	nonVipNetworks := boshsettings.Networks{}

	for networkName, networkSettings := range networks {
		if networkSettings.IsVIP() {
			continue
		}
		nonVipNetworks[networkName] = networkSettings
	}

	err := net.setupInterfaces(nonVipNetworks)
	if err != nil {
		return err
	}

	dnsNetwork, _ := nonVipNetworks.DefaultNetworkFor("dns")
	return net.setupDNS(dnsNetwork)
}

func (net WindowsNetManager) setupInterfaces(networks boshsettings.Networks) error {
	for _, network := range networks {
		var gateway string

		if network.IsDefaultFor("gateway") || len(networks) == 1 {
			gateway = network.Gateway
		}
		_, _, err := net.psRunner.RunCommand(boshsys.PSCommand{
			Script: fmt.Sprintf(NicSettingsTemplate, network.Mac, network.IP, network.Netmask, gateway),
		})
		if err != nil {
			return bosherr.WrapError(err, "Configuring interface")
		}
	}
	return nil
}

func (net WindowsNetManager) setupDNS(dnsNetwork boshsettings.Network) error {
	if len(dnsNetwork.DNS) > 0 {
		_, _, err := net.psRunner.RunCommand(boshsys.PSCommand{
			Script: fmt.Sprintf(SetDNSTemplate, strings.Join(dnsNetwork.DNS, `","`)),
		})
		if err != nil {
			return bosherr.WrapError(err, "Configuring DNS servers")
		}
	} else {
		_, _, err := net.psRunner.RunCommand(boshsys.PSCommand{Script: ResetDNSTemplate})
		if err != nil {
			return bosherr.WrapError(err, "Resetting DNS servers")
		}
	}
	return nil
}

func (net WindowsNetManager) GetConfiguredNetworkInterfaces() ([]string, error) {
	panic("Not implemented")
}
<commit_msg>Wait for internet connectivity after windows Agent sets up networking<commit_after>package net

import (
	"fmt"
	"strings"
	"time"

	boshsettings "github.com/cloudfoundry/bosh-agent/settings"
	bosherr "github.com/cloudfoundry/bosh-utils/errors"
	boshlog "github.com/cloudfoundry/bosh-utils/logger"
	boshsys "github.com/cloudfoundry/bosh-utils/system"
)

type WindowsNetManager struct {
	psRunner boshsys.PSRunner

	logTag string
	logger boshlog.Logger
}

func NewWindowsNetManager(psRunner boshsys.PSRunner, logger boshlog.Logger) Manager {
	return WindowsNetManager{
		psRunner: psRunner,

		logTag: "WindowsNetManager",
		logger: logger,
	}
}

const (
	SetDNSTemplate = `
[array]$interfaces = Get-DNSClientServerAddress
$dns = @("%s")
foreach($interface in $interfaces) {
	Set-DnsClientServerAddress -InterfaceAlias $interface.InterfaceAlias -ServerAddresses ($dns -join ",")
}
`

	ResetDNSTemplate = `
[array]$interfaces = Get-DNSClientServerAddress
foreach($interface in $interfaces) {
	Set-DnsClientServerAddress -InterfaceAlias $interface.InterfaceAlias -ResetServerAddresses
}
`

	NicSettingsTemplate = `
$connectionName=(get-wmiobject win32_networkadapter | where-object {$_.MacAddress -eq '%s'}).netconnectionid
netsh interface ip set address $connectionName static %s %s %s
`
)

func (net WindowsNetManager) SetupNetworking(networks boshsettings.Networks, errCh chan error) error {

	nonVipNetworks := boshsettings.Networks{}

	for networkName, networkSettings := range networks {
		if networkSettings.IsVIP() {
			continue
		}
		nonVipNetworks[networkName] = networkSettings
	}

	err := net.setupInterfaces(nonVipNetworks)
	if err != nil {
		return err
	}

	dnsNetwork, _ := nonVipNetworks.DefaultNetworkFor("dns")
	dns := net.setupDNS(dnsNetwork)
	time.Sleep(5 * time.Second)
	return dns
}

func (net WindowsNetManager) setupInterfaces(networks boshsettings.Networks) error {
	for _, network := range networks {
		var gateway string

		if network.IsDefaultFor("gateway") || len(networks) == 1 {
			gateway = network.Gateway
		}
		_, _, err := net.psRunner.RunCommand(boshsys.PSCommand{
			Script: fmt.Sprintf(NicSettingsTemplate, network.Mac, network.IP, network.Netmask, gateway),
		})
		if err != nil {
			return bosherr.WrapError(err, "Configuring interface")
		}
	}
	return nil
}

func (net WindowsNetManager) setupDNS(dnsNetwork boshsettings.Network) error {
	if len(dnsNetwork.DNS) > 0 {
		_, _, err := net.psRunner.RunCommand(boshsys.PSCommand{
			Script: fmt.Sprintf(SetDNSTemplate, strings.Join(dnsNetwork.DNS, `","`)),
		})
		if err != nil {
			return bosherr.WrapError(err, "Configuring DNS servers")
		}
	} else {
		_, _, err := net.psRunner.RunCommand(boshsys.PSCommand{Script: ResetDNSTemplate})
		if err != nil {
			return bosherr.WrapError(err, "Resetting DNS servers")
		}
	}
	return nil
}

func (net WindowsNetManager) GetConfiguredNetworkInterfaces() ([]string, error) {
	panic("Not implemented")
}
<|endoftext|>


<commit_before>/*******************************************************************************
*
* Copyright 2017 SAP SE
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You should have received a copy of the License along with this
* program. If not, 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 plugins

import (
	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack"
	"github.com/sapcc/limes"
	"github.com/sapcc/limes/pkg/core"
)

type neutronPlugin struct {
	cfg           core.ServiceConfiguration
	resources     []limes.ResourceInfo
	resourcesMeta []neutronResourceMetadata
}

var neutronResources = []limes.ResourceInfo{
	////////// SDN resources
	{
		Name:     "floating_ips",
		Unit:     limes.UnitNone,
		Category: "networking",
	},
	{
		Name:     "networks",
		Unit:     limes.UnitNone,
		Category: "networking",
	},
	{
		Name:     "ports",
		Unit:     limes.UnitNone,
		Category: "networking",
	},
	{
		Name:     "rbac_policies",
		Unit:     limes.UnitNone,
		Category: "networking",
	},
	{
		Name:     "routers",
		Unit:     limes.UnitNone,
		Category: "networking",
	},
	{
		Name:     "security_group_rules",
		Unit:     limes.UnitNone,
		Category: "networking",
		//for "default" security group
		AutoApproveInitialQuota: 4,
	},
	{
		Name:     "security_groups",
		Unit:     limes.UnitNone,
		Category: "networking",
		//for "default" security group
		AutoApproveInitialQuota: 1,
	},
	{
		Name:     "subnet_pools",
		Unit:     limes.UnitNone,
		Category: "networking",
	},
	{
		Name:     "subnets",
		Unit:     limes.UnitNone,
		Category: "networking",
	},
	////////// LBaaS resources
	{
		Name:     "healthmonitors",
		Unit:     limes.UnitNone,
		Category: "loadbalancing",
	},
	{
		Name:     "l7policies",
		Unit:     limes.UnitNone,
		Category: "loadbalancing",
	},
	{
		Name:     "listeners",
		Unit:     limes.UnitNone,
		Category: "loadbalancing",
	},
	{
		Name:     "loadbalancers",
		Unit:     limes.UnitNone,
		Category: "loadbalancing",
	},
	{
		Name:     "pools",
		Unit:     limes.UnitNone,
		Category: "loadbalancing",
	},
	{
		Name:     "pool_members",
		Unit:     limes.UnitNone,
		Category: "loadbalancing",
	},
}

func init() {
	core.RegisterQuotaPlugin(func(c core.ServiceConfiguration, scrapeSubresources map[string]bool) core.QuotaPlugin {
		return &neutronPlugin{
			cfg:           c,
			resources:     neutronResources,
			resourcesMeta: neutronResourceMeta,
		}
	})
}

//Init implements the core.QuotaPlugin interface.
func (p *neutronPlugin) Init(provider *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) error {
	return nil
}

//ServiceInfo implements the core.QuotaPlugin interface.
func (p *neutronPlugin) ServiceInfo() limes.ServiceInfo {
	return limes.ServiceInfo{
		Type:        "network",
		ProductName: "neutron",
		Area:        "network",
	}
}

//Resources implements the core.QuotaPlugin interface.
func (p *neutronPlugin) Resources() []limes.ResourceInfo {
	return p.resources
}

type neutronResourceMetadata struct {
	LimesName   string
	NeutronName string
}

var neutronResourceMeta = []neutronResourceMetadata{
	{
		LimesName:   "networks",
		NeutronName: "network",
	},
	{
		LimesName:   "subnets",
		NeutronName: "subnet",
	},
	{
		LimesName:   "subnet_pools",
		NeutronName: "subnetpool",
	},
	{
		LimesName:   "floating_ips",
		NeutronName: "floatingip",
	},
	{
		LimesName:   "routers",
		NeutronName: "router",
	},
	{
		LimesName:   "ports",
		NeutronName: "port",
	},
	{
		LimesName:   "security_groups",
		NeutronName: "security_group",
	},
	{
		LimesName:   "security_group_rules",
		NeutronName: "security_group_rule",
	},
	{
		LimesName:   "rbac_policies",
		NeutronName: "rbac_policy",
	},
	{
		LimesName:   "loadbalancers",
		NeutronName: "loadbalancer",
	},
	{
		LimesName:   "listeners",
		NeutronName: "listener",
	},
	{
		LimesName:   "pools",
		NeutronName: "pool",
	},
	{
		LimesName:   "healthmonitors",
		NeutronName: "healthmonitor",
	},
	{
		LimesName:   "l7policies",
		NeutronName: "l7policy",
	},
	{
		LimesName:   "pool_members",
		NeutronName: "member",
	},
}

type neutronQueryOpts struct {
	Fields      string `q:"fields"`
	ProjectUUID string `q:"tenant_id"`
}

//Scrape implements the core.QuotaPlugin interface.
func (p *neutronPlugin) Scrape(provider *gophercloud.ProviderClient, eo gophercloud.EndpointOpts, clusterID, domainUUID, projectUUID string) (map[string]core.ResourceData, error) {
	client, err := openstack.NewNetworkV2(provider, eo)
	if err != nil {
		return nil, err
	}

	var result gophercloud.Result
	url := client.ServiceURL("quotas", projectUUID, "details")
	_, err = client.Get(url, &result.Body, nil)
	if err != nil {
		return nil, err
	}

	type neutronQuotaStruct struct {
		Quota int64  `json:"limit"`
		Usage uint64 `json:"used"`
	}
	var quotas struct {
		Values map[string]neutronQuotaStruct `json:"quota"`
	}
	quotas.Values = make(map[string]neutronQuotaStruct)
	err = result.ExtractInto(&quotas)
	if err != nil {
		return nil, err
	}

	//convert data returned by Neutron into Limes' internal format
	data := make(map[string]core.ResourceData)
	for _, res := range p.resourcesMeta {
		values := quotas.Values[res.NeutronName]
		data[res.LimesName] = core.ResourceData{
			Quota: values.Quota,
			Usage: values.Usage,
		}
	}
	return data, nil
}

//SetQuota implements the core.QuotaPlugin interface.
func (p *neutronPlugin) SetQuota(provider *gophercloud.ProviderClient, eo gophercloud.EndpointOpts, clusterID, domainUUID, projectUUID string, quotas map[string]uint64) error {
	//map resource names from Limes to Neutron
	var requestData struct {
		Quotas map[string]uint64 `json:"quota"`
	}
	requestData.Quotas = make(map[string]uint64)
	for _, res := range p.resourcesMeta {
		quota, exists := quotas[res.LimesName]
		if exists {
			requestData.Quotas[res.NeutronName] = quota
		}
	}

	client, err := openstack.NewNetworkV2(provider, eo)
	if err != nil {
		return err
	}

	url := client.ServiceURL("quotas", projectUUID)
	_, err = client.Put(url, requestData, nil, &gophercloud.RequestOpts{OkCodes: []int{200}})
	return err
}
<commit_msg>plugins/neutron: support Octavia API if available<commit_after>/*******************************************************************************
*
* Copyright 2017 SAP SE
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You should have received a copy of the License along with this
* program. If not, 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 plugins

import (
	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack"
	"github.com/sapcc/limes"
	"github.com/sapcc/limes/pkg/core"
)

type neutronPlugin struct {
	cfg           core.ServiceConfiguration
	resources     []limes.ResourceInfo
	resourcesMeta []neutronResourceMetadata
	hasOctavia    bool
}

var neutronResources = []limes.ResourceInfo{
	////////// SDN resources
	{
		Name:     "floating_ips",
		Unit:     limes.UnitNone,
		Category: "networking",
	},
	{
		Name:     "networks",
		Unit:     limes.UnitNone,
		Category: "networking",
	},
	{
		Name:     "ports",
		Unit:     limes.UnitNone,
		Category: "networking",
	},
	{
		Name:     "rbac_policies",
		Unit:     limes.UnitNone,
		Category: "networking",
	},
	{
		Name:     "routers",
		Unit:     limes.UnitNone,
		Category: "networking",
	},
	{
		Name:     "security_group_rules",
		Unit:     limes.UnitNone,
		Category: "networking",
		//for "default" security group
		AutoApproveInitialQuota: 4,
	},
	{
		Name:     "security_groups",
		Unit:     limes.UnitNone,
		Category: "networking",
		//for "default" security group
		AutoApproveInitialQuota: 1,
	},
	{
		Name:     "subnet_pools",
		Unit:     limes.UnitNone,
		Category: "networking",
	},
	{
		Name:     "subnets",
		Unit:     limes.UnitNone,
		Category: "networking",
	},
	////////// LBaaS resources
	{
		Name:     "healthmonitors",
		Unit:     limes.UnitNone,
		Category: "loadbalancing",
	},
	{
		Name:     "l7policies",
		Unit:     limes.UnitNone,
		Category: "loadbalancing",
	},
	{
		Name:     "listeners",
		Unit:     limes.UnitNone,
		Category: "loadbalancing",
	},
	{
		Name:     "loadbalancers",
		Unit:     limes.UnitNone,
		Category: "loadbalancing",
	},
	{
		Name:     "pools",
		Unit:     limes.UnitNone,
		Category: "loadbalancing",
	},
	{
		Name:     "pool_members",
		Unit:     limes.UnitNone,
		Category: "loadbalancing",
	},
}

func init() {
	core.RegisterQuotaPlugin(func(c core.ServiceConfiguration, scrapeSubresources map[string]bool) core.QuotaPlugin {
		return &neutronPlugin{
			cfg:           c,
			resources:     neutronResources,
			resourcesMeta: neutronResourceMeta,
		}
	})
}

//Init implements the core.QuotaPlugin interface.
func (p *neutronPlugin) Init(provider *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) error {
	_, err := openstack.NewLoadBalancerV2(provider, eo)
	switch err.(type) {
	case *gophercloud.ErrEndpointNotFound:
		p.hasOctavia = false
	case nil:
		p.hasOctavia = true
	default:
		return err
	}

	return nil
}

//ServiceInfo implements the core.QuotaPlugin interface.
func (p *neutronPlugin) ServiceInfo() limes.ServiceInfo {
	return limes.ServiceInfo{
		Type:        "network",
		ProductName: "neutron",
		Area:        "network",
	}
}

//Resources implements the core.QuotaPlugin interface.
func (p *neutronPlugin) Resources() []limes.ResourceInfo {
	return p.resources
}

type neutronResourceMetadata struct {
	LimesName   string
	NeutronName string
	InOctavia   bool
}

var neutronResourceMeta = []neutronResourceMetadata{
	{
		LimesName:   "networks",
		NeutronName: "network",
	},
	{
		LimesName:   "subnets",
		NeutronName: "subnet",
	},
	{
		LimesName:   "subnet_pools",
		NeutronName: "subnetpool",
	},
	{
		LimesName:   "floating_ips",
		NeutronName: "floatingip",
	},
	{
		LimesName:   "routers",
		NeutronName: "router",
	},
	{
		LimesName:   "ports",
		NeutronName: "port",
	},
	{
		LimesName:   "security_groups",
		NeutronName: "security_group",
	},
	{
		LimesName:   "security_group_rules",
		NeutronName: "security_group_rule",
	},
	{
		LimesName:   "rbac_policies",
		NeutronName: "rbac_policy",
	},
	{
		LimesName:   "loadbalancers",
		NeutronName: "loadbalancer",
		InOctavia:   true,
	},
	{
		LimesName:   "listeners",
		NeutronName: "listener",
		InOctavia:   true,
	},
	{
		LimesName:   "pools",
		NeutronName: "pool",
		InOctavia:   true,
	},
	{
		LimesName:   "healthmonitors",
		NeutronName: "healthmonitor",
		InOctavia:   true,
	},
	{
		LimesName:   "l7policies",
		NeutronName: "l7policy",
		InOctavia:   true,
	},
	{
		LimesName:   "pool_members",
		NeutronName: "member",
		InOctavia:   true,
	},
}

type neutronQueryOpts struct {
	Fields      string `q:"fields"`
	ProjectUUID string `q:"tenant_id"`
}

//Scrape implements the core.QuotaPlugin interface.
func (p *neutronPlugin) Scrape(provider *gophercloud.ProviderClient, eo gophercloud.EndpointOpts, clusterID, domainUUID, projectUUID string) (map[string]core.ResourceData, error) {
	client, err := openstack.NewNetworkV2(provider, eo)
	if err != nil {
		return nil, err
	}

	var result gophercloud.Result
	url := client.ServiceURL("quotas", projectUUID, "details")
	_, err = client.Get(url, &result.Body, nil)
	if err != nil {
		return nil, err
	}

	type neutronQuotaStruct struct {
		Quota int64  `json:"limit"`
		Usage uint64 `json:"used"`
	}
	var quotas struct {
		Values map[string]neutronQuotaStruct `json:"quota"`
	}
	quotas.Values = make(map[string]neutronQuotaStruct)
	err = result.ExtractInto(&quotas)
	if err != nil {
		return nil, err
	}

	//convert data returned by Neutron into Limes' internal format
	data := make(map[string]core.ResourceData)
	for _, res := range p.resourcesMeta {
		values := quotas.Values[res.NeutronName]
		data[res.LimesName] = core.ResourceData{
			Quota: values.Quota,
			Usage: values.Usage,
		}
	}
	return data, nil
}

//SetQuota implements the core.QuotaPlugin interface.
func (p *neutronPlugin) SetQuota(provider *gophercloud.ProviderClient, eo gophercloud.EndpointOpts, clusterID, domainUUID, projectUUID string, quotas map[string]uint64) error {
	//map resource names from Limes to Neutron/Octavia
	var neutronRequestData struct {
		Quotas map[string]uint64 `json:"quota"`
	}
	var octaviaRequestData struct {
		Quotas map[string]uint64 `json:"quota"`
	}
	neutronRequestData.Quotas = make(map[string]uint64)
	octaviaRequestData.Quotas = make(map[string]uint64)
	for _, res := range p.resourcesMeta {
		quota, exists := quotas[res.LimesName]
		if exists {
			neutronRequestData.Quotas[res.NeutronName] = quota
		}
		if exists && res.InOctavia {
			octaviaRequestData.Quotas[res.NeutronName] = quota
		}
	}

	neutronClient, err := openstack.NewNetworkV2(provider, eo)
	if err != nil {
		return err
	}
	neutronURL := neutronClient.ServiceURL("quotas", projectUUID)
	_, err = neutronClient.Put(neutronURL, neutronRequestData, nil, &gophercloud.RequestOpts{OkCodes: []int{200}})
	if err != nil {
		return err
	}

	if p.hasOctavia {
		octaviaClient, err := openstack.NewLoadBalancerV2(provider, eo)
		if err != nil {
			return err
		}
		octaviaURL := octaviaClient.ServiceURL("lbaas", "quotas", projectUUID)
		_, err = octaviaClient.Put(octaviaURL, octaviaRequestData, nil, &gophercloud.RequestOpts{OkCodes: []int{202}})
		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package project

var (
	description string = "The azure-operator manages Kubernetes clusters on Azure."
	gitSHA             = "n/a"
	name        string = "azure-operator"
	source      string = "https://github.com/giantswarm/azure-operator"
	version            = "6.0.3"
)

func Description() string {
	return description
}

func GitSHA() string {
	return gitSHA
}

func Name() string {
	return name
}

func Source() string {
	return source
}

func Version() string {
	return version
}
<commit_msg>Bump version to 6.0.4-dev (#1693)<commit_after>package project

var (
	description string = "The azure-operator manages Kubernetes clusters on Azure."
	gitSHA             = "n/a"
	name        string = "azure-operator"
	source      string = "https://github.com/giantswarm/azure-operator"
	version            = "6.0.4-dev"
)

func Description() string {
	return description
}

func GitSHA() string {
	return gitSHA
}

func Name() string {
	return name
}

func Source() string {
	return source
}

func Version() string {
	return version
}
<|endoftext|>


<commit_before>/*
Copyright The Helm Authors.

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

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

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

package version // import "k8s.io/helm/pkg/version"

import "k8s.io/helm/pkg/proto/hapi/version"

var (
	// Version is the current version of the Helm.
	// Update this whenever making a new release.
	// The version is of the format Major.Minor.Patch[-Prerelease][+BuildMetadata]
	//
	// Increment major number for new feature additions and behavioral changes.
	// Increment minor number for bug fixes and performance enhancements.
	// Increment patch number for critical fixes to existing releases.
	Version = "v2.8"

	// BuildMetadata is extra build time data
	BuildMetadata = "unreleased"
	// GitCommit is the git sha1
	GitCommit = ""
	// GitTreeState is the state of the git tree
	GitTreeState = ""
)

// GetVersion returns the semver string of the version
func GetVersion() string {
	if BuildMetadata == "" {
		return Version
	}
	return Version + "+" + BuildMetadata
}

// GetVersionProto returns protobuf representing the version
func GetVersionProto() *version.Version {
	return &version.Version{
		SemVer:       GetVersion(),
		GitCommit:    GitCommit,
		GitTreeState: GitTreeState,
	}
}
<commit_msg>bump version to v2.10<commit_after>/*
Copyright The Helm Authors.

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

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

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

package version // import "k8s.io/helm/pkg/version"

import "k8s.io/helm/pkg/proto/hapi/version"

var (
	// Version is the current version of the Helm.
	// Update this whenever making a new release.
	// The version is of the format Major.Minor.Patch[-Prerelease][+BuildMetadata]
	//
	// Increment major number for new feature additions and behavioral changes.
	// Increment minor number for bug fixes and performance enhancements.
	// Increment patch number for critical fixes to existing releases.
	Version = "v2.10"

	// BuildMetadata is extra build time data
	BuildMetadata = "unreleased"
	// GitCommit is the git sha1
	GitCommit = ""
	// GitTreeState is the state of the git tree
	GitTreeState = ""
)

// GetVersion returns the semver string of the version
func GetVersion() string {
	if BuildMetadata == "" {
		return Version
	}
	return Version + "+" + BuildMetadata
}

// GetVersionProto returns protobuf representing the version
func GetVersionProto() *version.Version {
	return &version.Version{
		SemVer:       GetVersion(),
		GitCommit:    GitCommit,
		GitTreeState: GitTreeState,
	}
}
<|endoftext|>


<commit_before>/******************************************************************************
go-utils Source Code
Copyright (C) 2013 Lumen LLC.

This file is part of the go-utils Source Code.

go-utils is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

go-utils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with go-utils.  If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/

package canvas

type Pageview map[string]interface{}
<commit_msg>Add minor commentary to pageview.go.<commit_after>/******************************************************************************
go-utils Source Code
Copyright (C) 2013 Lumen LLC.

This file is part of the go-utils Source Code.

go-utils is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

go-utils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with go-utils.  If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/

package canvas

// Instead of using the Pageview type,
// we might just want to consider using a map[string]interface{}
type Pageview map[string]interface{}
<|endoftext|>


<commit_before>package captcha

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

type driver interface {
	Type() string
	Config(w http.ResponseWriter, r *http.Request) (json.RawMessage, error)
	Reset(w http.ResponseWriter, r *http.Request) (json.RawMessage, error)
	Verify(r *http.Request, token string) (bool, error)
}

type CommonOutput struct {
	Type   string
	Config json.RawMessage
}

func New() *Captcha {
	return &Captcha{}
}

type Captcha struct {
	driver driver
}

func (c *Captcha) ActionConfig(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	config, err := c.driver.Config(w, r)
	if err != nil {
		panic(err)
	}
	output, err := json.Marshal(CommonOutput{
		Type:   c.driver.Type(),
		Config: config,
	})
	if err != nil {
		panic(err)
	}
	_, err = w.Write(output)
	if err != nil {
		panic(err)
	}
}

func (c *Captcha) ActionReset(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	config, err := c.driver.Reset(w, r)
	if err != nil {
		panic(err)
	}
	output, err := json.Marshal(CommonOutput{
		Type:   c.driver.Type(),
		Config: config,
	})
	if err != nil {
		panic(err)
	}
	_, err = w.Write(output)
	if err != nil {
		panic(err)
	}
}

func (c *Captcha) Verify(r *http.Request, token string) (bool, error) {
	return c.driver.Verify(r, token)
}
<commit_msg>update<commit_after>package captcha

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

type driver interface {
	Type() string
	Config(w http.ResponseWriter, r *http.Request) (json.RawMessage, error)
	Reset(w http.ResponseWriter, r *http.Request) (json.RawMessage, error)
	Verify(r *http.Request, token string) (bool, error)
}

type CommonOutput struct {
	Type    string
	Enabled bool
	Config  json.RawMessage
}

func New() *Captcha {
	return &Captcha{}
}
func defaultEnabledChecker(captcha *Captcha, w http.ResponseWriter, r *http.Request) (bool, error) {
	return true, nil
}

type Captcha struct {
	driver         driver
	Disabled       bool
	EnabledChecker func(captcha *Captcha, w http.ResponseWriter, r *http.Request) (bool, error)
}

func (c *Captcha) EnabledCheck(w http.ResponseWriter, r *http.Request) (bool, error) {
	if c.Disabled {
		return false, nil
	}
	return c.EnabledChecker(c, w, r)
}

func (c *Captcha) ConfigAction(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	enabled, err := c.EnabledCheck(w, r)
	if err != nil {
		panic(err)
	}
	output := CommonOutput{
		Type:    c.driver.Type(),
		Enabled: enabled,
	}
	if enabled {
		config, err := c.driver.Config(w, r)
		if err != nil {
			panic(err)
		}
		output.Config = config
	}
	outputJSON, err := json.Marshal(output)
	if err != nil {
		panic(err)
	}
	_, err = w.Write(outputJSON)
	if err != nil {
		panic(err)
	}
}

func (c *Captcha) ResetAction(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	enabled, err := c.EnabledCheck(w, r)
	if err != nil {
		panic(err)
	}
	output := CommonOutput{
		Type:    c.driver.Type(),
		Enabled: enabled,
	}
	if enabled {
		config, err := c.driver.Reset(w, r)
		if err != nil {
			panic(err)
		}
		output.Config = config
	}
	outputJSON, err := json.Marshal(output)
	if err != nil {
		panic(err)
	}
	_, err = w.Write(outputJSON)
	if err != nil {
		panic(err)
	}
}

func (c *Captcha) Verify(r *http.Request, token string) (bool, error) {
	return c.driver.Verify(r, token)
}
<|endoftext|>


<commit_before>// Package api holds common data types and public interface exposed by the indexer library.
package api

// Refer to the doc
// https://docs.google.com/a/squareup.com/document/d/1k0Wgi2wnJPQoyDyReb9dyIqRrD8-v0u8hz37S282ii4/edit
// for the terminology.

// MetricKey is the logical name of a given metric.
// MetricKey should not contain any variable component in it.
type MetricKey string

// TagSet is the set of key-value pairs associated with a given metric.
type TagSet map[string]string

// TaggedMetric is composition of a MetricKey and a TagSet.
// TaggedMetric should uniquely identify a single series of metric.
type TaggedMetric struct {
	MetricKey MetricKey
	TagSet    TagSet
}

// GraphiteMetric is a flat, dot-separated identifier to a series of metric.
type GraphiteMetric string

// API is the set of public methods exposed by the indexer library.
type API interface {
	// AddMetric adds the metric to the system.
	AddMetric(metric TaggedMetric) error

  // RemoveMetric removes the metric from the system.
	RemoveMetric(metric TaggedMetric) error

  // Convert the given tag-based metric name to graphite metric name,
  // using the configured rules. May error out.
	ToGraphiteName(metric TaggedMetric) (GraphiteMetric, error)

  // Converts the given graphite metric to the tag-based meric,
  // using the configured rules. May error out.
	ToTaggedName(metric GraphiteMetric) (TaggedMetric, error)

  // For a given MetricKey, retrieve all the tagsets associated with it.
	GetAllTags(metricKey MetricKey) []TagSet

  // For a given tag key-value pair, obtain the list of all the MetricKeys
  // associated with them.
	GetMericsForTag(tagKey string, tagValue string) []MetricKey
}
<commit_msg>running go fmt<commit_after>// Package api holds common data types and public interface exposed by the indexer library.
package api

// Refer to the doc
// https://docs.google.com/a/squareup.com/document/d/1k0Wgi2wnJPQoyDyReb9dyIqRrD8-v0u8hz37S282ii4/edit
// for the terminology.

// MetricKey is the logical name of a given metric.
// MetricKey should not contain any variable component in it.
type MetricKey string

// TagSet is the set of key-value pairs associated with a given metric.
type TagSet map[string]string

// TaggedMetric is composition of a MetricKey and a TagSet.
// TaggedMetric should uniquely identify a single series of metric.
type TaggedMetric struct {
	MetricKey MetricKey
	TagSet    TagSet
}

// GraphiteMetric is a flat, dot-separated identifier to a series of metric.
type GraphiteMetric string

// API is the set of public methods exposed by the indexer library.
type API interface {
	// AddMetric adds the metric to the system.
	AddMetric(metric TaggedMetric) error

	// RemoveMetric removes the metric from the system.
	RemoveMetric(metric TaggedMetric) error

	// Convert the given tag-based metric name to graphite metric name,
	// using the configured rules. May error out.
	ToGraphiteName(metric TaggedMetric) (GraphiteMetric, error)

	// Converts the given graphite metric to the tag-based meric,
	// using the configured rules. May error out.
	ToTaggedName(metric GraphiteMetric) (TaggedMetric, error)

	// For a given MetricKey, retrieve all the tagsets associated with it.
	GetAllTags(metricKey MetricKey) []TagSet

	// For a given tag key-value pair, obtain the list of all the MetricKeys
	// associated with them.
	GetMericsForTag(tagKey string, tagValue string) []MetricKey
}
<|endoftext|>


<commit_before>package model

// The service is paused and will not trigger any alarms
const StatePaused = "paused"

// The service is perfectly fine
const StateOk = "ok"

// The service is in a warning state
const StateWarning = "warning"

// The service is in an error state
const StateError = "error"

// The number of beats that we save
const PreviousBeatsCount = 20

// Service is something that can issue a beat
type Service struct {
	Name           string
	LastValue      int
	LastBeat       int64
	PreviousBeats  []int64
	LastUpdated    int64
	WarningTimeout int64
	ErrorTimeout   int64
	State          string
}

// View is a collection of services
type View struct {
	Name        string
	State       string
	Regexp      string
	LastUpdated int64
	IncidentNbr int
	Alerts      []string
}
<commit_msg>Increasing the number of persisted beats to 100<commit_after>package model

// The service is paused and will not trigger any alarms
const StatePaused = "paused"

// The service is perfectly fine
const StateOk = "ok"

// The service is in a warning state
const StateWarning = "warning"

// The service is in an error state
const StateError = "error"

// The number of beats that we save
const PreviousBeatsCount = 100

// Service is something that can issue a beat
type Service struct {
	Name           string
	LastValue      int
	LastBeat       int64
	PreviousBeats  []int64
	LastUpdated    int64
	WarningTimeout int64
	ErrorTimeout   int64
	State          string
}

// View is a collection of services
type View struct {
	Name        string
	State       string
	Regexp      string
	LastUpdated int64
	IncidentNbr int
	Alerts      []string
}
<|endoftext|>


<commit_before><commit_msg>Fix alignment issue for unicode<commit_after><|endoftext|>


<commit_before><commit_msg>context: reduce verbosity<commit_after><|endoftext|>


<commit_before><commit_msg>Add methods to init logging counters.<commit_after><|endoftext|>


<commit_before>package app

import (
	"net/http"
	"sort"
	"sync"

	"github.com/gorilla/mux"

	"github.com/weaveworks/scope/render"
	"github.com/weaveworks/scope/report"
)

const apiTopologyURL = "/api/topology/"

var (
	topologyRegistry = &registry{
		items: map[string]APITopologyDesc{},
	}
	kubernetesTopologies = []APITopologyDesc{
		{
			id:       "pods",
			renderer: render.PodRenderer,
			Name:     "Pods",
			Options: map[string][]APITopologyOption{"system": {
				{"show", "System pods shown", false, render.FilterNoop},
				{"hide", "System pods hidden", true, render.FilterSystem},
			}},
		},
		{
			id:       "pods-by-service",
			parent:   "pods",
			renderer: render.PodServiceRenderer,
			Name:     "by service",
			Options: map[string][]APITopologyOption{"system": {
				{"show", "System services shown", false, render.FilterNoop},
				{"hide", "System services hidden", true, render.FilterSystem},
			}},
		},
	}
)

func init() {
	containerFilters := map[string][]APITopologyOption{
		"system": {
			{"show", "System containers shown", false, render.FilterNoop},
			{"hide", "System containers hidden", true, render.FilterSystem},
		},
		"stopped": {
			{"show", "Stopped containers shown", false, render.FilterNoop},
			{"hide", "Stopped containers hidden", true, render.FilterStopped},
		},
	}

	// Topology option labels should tell the current state. The first item must
	// be the verb to get to that state
	topologyRegistry.add(
		APITopologyDesc{
			id:       "applications",
			renderer: render.FilterUnconnected(render.ProcessWithContainerNameRenderer),
			Name:     "Applications",
			Options: map[string][]APITopologyOption{"unconnected": {
				// Show the user why there are filtered nodes in this view.
				// Don't give them the option to show those nodes.
				{"hide", "Unconnected nodes hidden", true, render.FilterNoop},
			}},
		},
		APITopologyDesc{
			id:       "applications-by-name",
			parent:   "applications",
			renderer: render.FilterUnconnected(render.ProcessNameRenderer),
			Name:     "by name",
			Options: map[string][]APITopologyOption{"unconnected": {
				// Ditto above.
				{"hide", "Unconnected nodes hidden", true, render.FilterNoop},
			}},
		},
		APITopologyDesc{
			id:       "containers",
			renderer: render.ContainerWithImageNameRenderer,
			Name:     "Containers",
			Options:  containerFilters,
		},
		APITopologyDesc{
			id:       "containers-by-image",
			parent:   "containers",
			renderer: render.ContainerImageRenderer,
			Name:     "by image",
			Options:  containerFilters,
		},
		APITopologyDesc{
			id:       "containers-by-hostname",
			parent:   "containers",
			renderer: render.ContainerHostnameRenderer,
			Name:     "by hostname",
			Options:  containerFilters,
		},
		APITopologyDesc{
			id:       "hosts",
			renderer: render.HostRenderer,
			Name:     "Hosts",
			Options:  map[string][]APITopologyOption{},
		},
	)
}

// registry is a threadsafe store of the available topologies
type registry struct {
	sync.RWMutex
	items map[string]APITopologyDesc
}

// APITopologyDesc is returned in a list by the /api/topology handler.
type APITopologyDesc struct {
	id       string
	parent   string
	renderer render.Renderer

	Name    string                         `json:"name"`
	Options map[string][]APITopologyOption `json:"options"`

	URL           string            `json:"url"`
	SubTopologies []APITopologyDesc `json:"sub_topologies,omitempty"`
	Stats         topologyStats     `json:"stats,omitempty"`
}

type byName []APITopologyDesc

func (a byName) Len() int           { return len(a) }
func (a byName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a byName) Less(i, j int) bool { return a[i].Name < a[j].Name }

// APITopologyOption describes a &param=value to a given topology.
type APITopologyOption struct {
	Value   string `json:"value"`
	Display string `json:"display"`
	Default bool   `json:"default,omitempty"`

	decorator func(render.Renderer) render.Renderer
}

type topologyStats struct {
	NodeCount          int `json:"node_count"`
	NonpseudoNodeCount int `json:"nonpseudo_node_count"`
	EdgeCount          int `json:"edge_count"`
	FilteredNodes      int `json:"filtered_nodes"`
}

func (r *registry) add(ts ...APITopologyDesc) {
	r.Lock()
	defer r.Unlock()
	for _, t := range ts {
		t.URL = apiTopologyURL + t.id

		if t.parent != "" {
			parent := r.items[t.parent]
			parent.SubTopologies = append(parent.SubTopologies, t)
			sort.Sort(byName(parent.SubTopologies))
			r.items[t.parent] = parent
		}

		r.items[t.id] = t
	}
}

func (r *registry) get(name string) (APITopologyDesc, bool) {
	r.RLock()
	defer r.RUnlock()
	t, ok := r.items[name]
	return t, ok
}

func (r *registry) walk(f func(APITopologyDesc)) {
	r.RLock()
	defer r.RUnlock()
	descs := []APITopologyDesc{}
	for _, desc := range r.items {
		if desc.parent != "" {
			continue
		}
		descs = append(descs, desc)
	}
	sort.Sort(byName(descs))
	for _, desc := range descs {
		f(desc)
	}
}

// makeTopologyList returns a handler that yields an APITopologyList.
func (r *registry) makeTopologyList(rep Reporter) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, req *http.Request) {
		var (
			rpt        = rep.Report()
			topologies = []APITopologyDesc{}
		)
		r.walk(func(desc APITopologyDesc) {
			renderer := renderedForRequest(req, desc)
			desc.Stats = decorateWithStats(rpt, renderer)
			for i := range desc.SubTopologies {
				renderer := renderedForRequest(req, desc.SubTopologies[i])
				desc.SubTopologies[i].Stats = decorateWithStats(rpt, renderer)
			}
			topologies = append(topologies, desc)
		})
		respondWith(w, http.StatusOK, topologies)
	}
}

func decorateWithStats(rpt report.Report, renderer render.Renderer) topologyStats {
	var (
		nodes     int
		realNodes int
		edges     int
	)
	for _, n := range renderer.Render(rpt) {
		nodes++
		if !n.Pseudo {
			realNodes++
		}
		edges += len(n.Adjacency)
	}
	renderStats := renderer.Stats(rpt)
	return topologyStats{
		NodeCount:          nodes,
		NonpseudoNodeCount: realNodes,
		EdgeCount:          edges,
		FilteredNodes:      renderStats.FilteredNodes,
	}
}

func (r *registry) enableKubernetesTopologies() {
	r.add(kubernetesTopologies...)
}

func renderedForRequest(r *http.Request, topology APITopologyDesc) render.Renderer {
	renderer := topology.renderer
	for param, opts := range topology.Options {
		value := r.FormValue(param)
		for _, opt := range opts {
			if (value == "" && opt.Default) || (opt.Value != "" && opt.Value == value) {
				renderer = opt.decorator(renderer)
			}
		}
	}
	return renderer
}

type reportRenderHandler func(Reporter, render.Renderer, http.ResponseWriter, *http.Request)

func (r *registry) captureRenderer(rep Reporter, f reportRenderHandler) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		topology, ok := r.get(mux.Vars(req)["topology"])
		if !ok {
			http.NotFound(w, req)
			return
		}
		renderer := renderedForRequest(req, topology)
		f(rep, renderer, w, req)
	}
}

func (r *registry) captureRendererWithoutFilters(rep Reporter, topologyID string, f reportRenderHandler) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		topology, ok := r.get(topologyID)
		if !ok {
			http.NotFound(w, req)
			return
		}
		f(rep, topology.renderer, w, req)
	}
}
<commit_msg>Rename 'by hostname' to 'by dns name'<commit_after>package app

import (
	"net/http"
	"sort"
	"sync"

	"github.com/gorilla/mux"

	"github.com/weaveworks/scope/render"
	"github.com/weaveworks/scope/report"
)

const apiTopologyURL = "/api/topology/"

var (
	topologyRegistry = &registry{
		items: map[string]APITopologyDesc{},
	}
	kubernetesTopologies = []APITopologyDesc{
		{
			id:       "pods",
			renderer: render.PodRenderer,
			Name:     "Pods",
			Options: map[string][]APITopologyOption{"system": {
				{"show", "System pods shown", false, render.FilterNoop},
				{"hide", "System pods hidden", true, render.FilterSystem},
			}},
		},
		{
			id:       "pods-by-service",
			parent:   "pods",
			renderer: render.PodServiceRenderer,
			Name:     "by service",
			Options: map[string][]APITopologyOption{"system": {
				{"show", "System services shown", false, render.FilterNoop},
				{"hide", "System services hidden", true, render.FilterSystem},
			}},
		},
	}
)

func init() {
	containerFilters := map[string][]APITopologyOption{
		"system": {
			{"show", "System containers shown", false, render.FilterNoop},
			{"hide", "System containers hidden", true, render.FilterSystem},
		},
		"stopped": {
			{"show", "Stopped containers shown", false, render.FilterNoop},
			{"hide", "Stopped containers hidden", true, render.FilterStopped},
		},
	}

	// Topology option labels should tell the current state. The first item must
	// be the verb to get to that state
	topologyRegistry.add(
		APITopologyDesc{
			id:       "applications",
			renderer: render.FilterUnconnected(render.ProcessWithContainerNameRenderer),
			Name:     "Applications",
			Options: map[string][]APITopologyOption{"unconnected": {
				// Show the user why there are filtered nodes in this view.
				// Don't give them the option to show those nodes.
				{"hide", "Unconnected nodes hidden", true, render.FilterNoop},
			}},
		},
		APITopologyDesc{
			id:       "applications-by-name",
			parent:   "applications",
			renderer: render.FilterUnconnected(render.ProcessNameRenderer),
			Name:     "by name",
			Options: map[string][]APITopologyOption{"unconnected": {
				// Ditto above.
				{"hide", "Unconnected nodes hidden", true, render.FilterNoop},
			}},
		},
		APITopologyDesc{
			id:       "containers",
			renderer: render.ContainerWithImageNameRenderer,
			Name:     "Containers",
			Options:  containerFilters,
		},
		APITopologyDesc{
			id:       "containers-by-image",
			parent:   "containers",
			renderer: render.ContainerImageRenderer,
			Name:     "by image",
			Options:  containerFilters,
		},
		APITopologyDesc{
			id:       "containers-by-hostname",
			parent:   "containers",
			renderer: render.ContainerHostnameRenderer,
			Name:     "by DNS name",
			Options:  containerFilters,
		},
		APITopologyDesc{
			id:       "hosts",
			renderer: render.HostRenderer,
			Name:     "Hosts",
			Options:  map[string][]APITopologyOption{},
		},
	)
}

// registry is a threadsafe store of the available topologies
type registry struct {
	sync.RWMutex
	items map[string]APITopologyDesc
}

// APITopologyDesc is returned in a list by the /api/topology handler.
type APITopologyDesc struct {
	id       string
	parent   string
	renderer render.Renderer

	Name    string                         `json:"name"`
	Options map[string][]APITopologyOption `json:"options"`

	URL           string            `json:"url"`
	SubTopologies []APITopologyDesc `json:"sub_topologies,omitempty"`
	Stats         topologyStats     `json:"stats,omitempty"`
}

type byName []APITopologyDesc

func (a byName) Len() int           { return len(a) }
func (a byName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a byName) Less(i, j int) bool { return a[i].Name < a[j].Name }

// APITopologyOption describes a &param=value to a given topology.
type APITopologyOption struct {
	Value   string `json:"value"`
	Display string `json:"display"`
	Default bool   `json:"default,omitempty"`

	decorator func(render.Renderer) render.Renderer
}

type topologyStats struct {
	NodeCount          int `json:"node_count"`
	NonpseudoNodeCount int `json:"nonpseudo_node_count"`
	EdgeCount          int `json:"edge_count"`
	FilteredNodes      int `json:"filtered_nodes"`
}

func (r *registry) add(ts ...APITopologyDesc) {
	r.Lock()
	defer r.Unlock()
	for _, t := range ts {
		t.URL = apiTopologyURL + t.id

		if t.parent != "" {
			parent := r.items[t.parent]
			parent.SubTopologies = append(parent.SubTopologies, t)
			sort.Sort(byName(parent.SubTopologies))
			r.items[t.parent] = parent
		}

		r.items[t.id] = t
	}
}

func (r *registry) get(name string) (APITopologyDesc, bool) {
	r.RLock()
	defer r.RUnlock()
	t, ok := r.items[name]
	return t, ok
}

func (r *registry) walk(f func(APITopologyDesc)) {
	r.RLock()
	defer r.RUnlock()
	descs := []APITopologyDesc{}
	for _, desc := range r.items {
		if desc.parent != "" {
			continue
		}
		descs = append(descs, desc)
	}
	sort.Sort(byName(descs))
	for _, desc := range descs {
		f(desc)
	}
}

// makeTopologyList returns a handler that yields an APITopologyList.
func (r *registry) makeTopologyList(rep Reporter) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, req *http.Request) {
		var (
			rpt        = rep.Report()
			topologies = []APITopologyDesc{}
		)
		r.walk(func(desc APITopologyDesc) {
			renderer := renderedForRequest(req, desc)
			desc.Stats = decorateWithStats(rpt, renderer)
			for i := range desc.SubTopologies {
				renderer := renderedForRequest(req, desc.SubTopologies[i])
				desc.SubTopologies[i].Stats = decorateWithStats(rpt, renderer)
			}
			topologies = append(topologies, desc)
		})
		respondWith(w, http.StatusOK, topologies)
	}
}

func decorateWithStats(rpt report.Report, renderer render.Renderer) topologyStats {
	var (
		nodes     int
		realNodes int
		edges     int
	)
	for _, n := range renderer.Render(rpt) {
		nodes++
		if !n.Pseudo {
			realNodes++
		}
		edges += len(n.Adjacency)
	}
	renderStats := renderer.Stats(rpt)
	return topologyStats{
		NodeCount:          nodes,
		NonpseudoNodeCount: realNodes,
		EdgeCount:          edges,
		FilteredNodes:      renderStats.FilteredNodes,
	}
}

func (r *registry) enableKubernetesTopologies() {
	r.add(kubernetesTopologies...)
}

func renderedForRequest(r *http.Request, topology APITopologyDesc) render.Renderer {
	renderer := topology.renderer
	for param, opts := range topology.Options {
		value := r.FormValue(param)
		for _, opt := range opts {
			if (value == "" && opt.Default) || (opt.Value != "" && opt.Value == value) {
				renderer = opt.decorator(renderer)
			}
		}
	}
	return renderer
}

type reportRenderHandler func(Reporter, render.Renderer, http.ResponseWriter, *http.Request)

func (r *registry) captureRenderer(rep Reporter, f reportRenderHandler) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		topology, ok := r.get(mux.Vars(req)["topology"])
		if !ok {
			http.NotFound(w, req)
			return
		}
		renderer := renderedForRequest(req, topology)
		f(rep, renderer, w, req)
	}
}

func (r *registry) captureRendererWithoutFilters(rep Reporter, topologyID string, f reportRenderHandler) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		topology, ok := r.get(topologyID)
		if !ok {
			http.NotFound(w, req)
			return
		}
		f(rep, topology.renderer, w, req)
	}
}
<|endoftext|>


<commit_before>// Copyright 2020 CUE Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cue

import (
	"strconv"
	"strings"

	"cuelang.org/go/cue/ast"
	"cuelang.org/go/cue/errors"
	"cuelang.org/go/cue/literal"
	"cuelang.org/go/cue/parser"
	"cuelang.org/go/cue/token"
	"cuelang.org/go/internal"
	"cuelang.org/go/internal/core/adt"
	"github.com/cockroachdb/apd/v2"
)

// A Selector is path component in a path.
type Selector struct {
	sel selector
}

// String reports the CUE representation of a selector.
func (sel Selector) String() string {
	return sel.sel.String()
}

type selector interface {
	String() string

	feature(ctx adt.Runtime) adt.Feature
	kind() adt.FeatureType
}

// A Path is series of selectors to query a CUE value.
type Path struct {
	path []Selector
}

// MakePath creates a Path from a sequence of selectors.
func MakePath(selectors ...Selector) Path {
	return Path{path: selectors}
}

// ParsePath parses a CUE expression into a Path. Any error resulting from
// this conversion can be obtained by calling Err on the result.
func ParsePath(s string) Path {
	expr, err := parser.ParseExpr("", s)
	if err != nil {
		return MakePath(Selector{pathError{errors.Promote(err, "invalid path")}})
	}

	return Path{path: toSelectors(expr)}
}

// String reports the CUE representation of p.
func (p Path) String() string {
	if err := p.Err(); err != nil {
		return "_|_"
	}

	b := &strings.Builder{}
	for i, sel := range p.path {
		x := sel.sel
		// TODO: use '.' in all cases, once supported.
		switch {
		case x.kind() == adt.IntLabel:
			b.WriteByte('[')
			b.WriteString(x.String())
			b.WriteByte(']')
			continue
		case i > 0:
			b.WriteByte('.')
		}

		b.WriteString(x.String())
	}
	return b.String()
}

func toSelectors(expr ast.Expr) []Selector {
	switch x := expr.(type) {
	case *ast.Ident:
		return []Selector{identSelector(x)}

	case *ast.IndexExpr:
		a := toSelectors(x.X)
		var sel Selector
		if b, ok := x.Index.(*ast.BasicLit); !ok {
			sel = Selector{pathError{
				errors.Newf(token.NoPos, "non-constant expression %s",
					internal.DebugStr(x.Index))}}
		} else {
			sel = basicLitSelector(b)
		}
		return append(a, sel)

	case *ast.SelectorExpr:
		a := toSelectors(x.X)
		return append(a, identSelector(x.Sel))

	default:
		return []Selector{Selector{pathError{
			errors.Newf(token.NoPos, "invalid label %s ", internal.DebugStr(x)),
		}}}
	}
}

func basicLitSelector(b *ast.BasicLit) Selector {
	switch b.Kind {
	case token.INT:
		var n literal.NumInfo
		if err := literal.ParseNum(b.Value, &n); err != nil {
			return Selector{pathError{
				errors.Newf(token.NoPos, "invalid string index %s", b.Value),
			}}
		}
		var d apd.Decimal
		_ = n.Decimal(&d)
		i, err := d.Int64()
		if err != nil {
			return Selector{pathError{
				errors.Newf(token.NoPos, "integer %s out of range", b.Value),
			}}
		}
		return Index(int(i))

	case token.STRING:
		info, _, _, _ := literal.ParseQuotes(b.Value, b.Value)
		if !info.IsDouble() {
			return Selector{pathError{
				errors.Newf(token.NoPos, "invalid string index %s", b.Value)}}
		}
		s, _ := literal.Unquote(b.Value)
		return Selector{stringSelector(s)}

	default:
		return Selector{pathError{
			errors.Newf(token.NoPos, "invalid literal %s", b.Value),
		}}
	}
}

func identSelector(label ast.Label) Selector {
	switch x := label.(type) {
	case *ast.Ident:
		if isHiddenOrDefinition(x.Name) {
			return Selector{definitionSelector(x.Name)}
		}
		return Selector{stringSelector(x.Name)}

	case *ast.BasicLit:
		return basicLitSelector(x)

	default:
		return Selector{pathError{
			errors.Newf(token.NoPos, "invalid label %s ", internal.DebugStr(x)),
		}}
	}
}

// Err reports errors that occurred when generating the path.
func (p Path) Err() error {
	var errs errors.Error
	for _, x := range p.path {
		if err, ok := x.sel.(pathError); ok {
			errs = errors.Append(errs, err.Error)
		}
	}
	return errs
}

func isHiddenOrDefinition(s string) bool {
	return strings.HasPrefix(s, "#") || strings.HasPrefix(s, "_")
}

// A Def marks a string as a definition label. An # will be added if a string is
// not prefixed with an # or _ already. Hidden labels are qualified by the
// package in which they are looked up.
func Def(s string) Selector {
	if !isHiddenOrDefinition(s) {
		s = "#" + s
	}
	return Selector{definitionSelector(s)}
}

type definitionSelector string

// String returns the CUE representation of the definition.
func (d definitionSelector) String() string {
	return string(d)
}

func (d definitionSelector) kind() adt.FeatureType {
	switch {
	case strings.HasPrefix(string(d), "#"):
		return adt.DefinitionLabel
	case strings.HasPrefix(string(d), "_#"):
		return adt.HiddenDefinitionLabel
	case strings.HasPrefix(string(d), "_"):
		return adt.HiddenLabel
	default:
		return adt.StringLabel
	}
}

func (d definitionSelector) feature(r adt.Runtime) adt.Feature {
	return adt.MakeIdentLabel(r, string(d), "")
}

// A Str is a CUE string label. Definition selectors are defined with Def.
func Str(s string) Selector {
	return Selector{stringSelector(s)}
}

type stringSelector string

func (s stringSelector) String() string {
	str := string(s)
	if isHiddenOrDefinition(str) || !ast.IsValidIdent(str) {
		return literal.Label.Quote(str)
	}
	return str
}

func (s stringSelector) kind() adt.FeatureType { return adt.StringLabel }

func (s stringSelector) feature(r adt.Runtime) adt.Feature {
	return adt.MakeStringLabel(r, string(s))
}

// An Index selects a list element by index.
func Index(x int) Selector {
	f, err := adt.MakeLabel(nil, int64(x), adt.IntLabel)
	if err != nil {
		return Selector{pathError{err}}
	}
	return Selector{indexSelector(f)}
}

type indexSelector adt.Feature

func (s indexSelector) String() string {
	return strconv.Itoa(adt.Feature(s).Index())
}

func (s indexSelector) kind() adt.FeatureType { return adt.IntLabel }

func (s indexSelector) feature(r adt.Runtime) adt.Feature {
	return adt.Feature(s)
}

// TODO: allow import paths to be represented?
//
// // ImportPath defines a lookup at the root of an instance. It must be the first
// // element of a Path.
// func ImportPath(s string) Selector {
// 	return importSelector(s)
// }

// type importSelector string

// func (s importSelector) String() string {
// 	return literal.String.Quote(string(s))
// }

// func (s importSelector) feature(r adt.Runtime) adt.Feature {
// 	return adt.InvalidLabel
// }

// TODO: allow looking up in parent scopes?

// // Parent returns a Selector for looking up in the parent of a current node.
// // Parent selectors may only occur at the start of a Path.
// func Parent() Selector {
// 	return parentSelector{}
// }

// type parentSelector struct{}

// func (p parentSelector) String() string { return "__up" }
// func (p parentSelector) feature(r adt.Runtime) adt.Feature {
// 	return adt.InvalidLabel
// }

type pathError struct {
	errors.Error
}

func (p pathError) String() string        { return p.Error.Error() }
func (p pathError) kind() adt.FeatureType { return 0 }
func (p pathError) feature(r adt.Runtime) adt.Feature {
	return adt.InvalidLabel
}
<commit_msg>cue: doc improvements<commit_after>// Copyright 2020 CUE Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cue

import (
	"strconv"
	"strings"

	"cuelang.org/go/cue/ast"
	"cuelang.org/go/cue/errors"
	"cuelang.org/go/cue/literal"
	"cuelang.org/go/cue/parser"
	"cuelang.org/go/cue/token"
	"cuelang.org/go/internal"
	"cuelang.org/go/internal/core/adt"
	"github.com/cockroachdb/apd/v2"
)

// A Selector is a component of a path.
type Selector struct {
	sel selector
}

// String reports the CUE representation of a selector.
func (sel Selector) String() string {
	return sel.sel.String()
}

type selector interface {
	String() string

	feature(ctx adt.Runtime) adt.Feature
	kind() adt.FeatureType
}

// A Path is series of selectors to query a CUE value.
type Path struct {
	path []Selector
}

// MakePath creates a Path from a sequence of selectors.
func MakePath(selectors ...Selector) Path {
	return Path{path: selectors}
}

// ParsePath parses a CUE expression into a Path. Any error resulting from
// this conversion can be obtained by calling Err on the result.
func ParsePath(s string) Path {
	expr, err := parser.ParseExpr("", s)
	if err != nil {
		return MakePath(Selector{pathError{errors.Promote(err, "invalid path")}})
	}

	return Path{path: toSelectors(expr)}
}

// String reports the CUE representation of p.
func (p Path) String() string {
	if err := p.Err(); err != nil {
		return "_|_"
	}

	b := &strings.Builder{}
	for i, sel := range p.path {
		x := sel.sel
		// TODO: use '.' in all cases, once supported.
		switch {
		case x.kind() == adt.IntLabel:
			b.WriteByte('[')
			b.WriteString(x.String())
			b.WriteByte(']')
			continue
		case i > 0:
			b.WriteByte('.')
		}

		b.WriteString(x.String())
	}
	return b.String()
}

func toSelectors(expr ast.Expr) []Selector {
	switch x := expr.(type) {
	case *ast.Ident:
		return []Selector{identSelector(x)}

	case *ast.IndexExpr:
		a := toSelectors(x.X)
		var sel Selector
		if b, ok := x.Index.(*ast.BasicLit); !ok {
			sel = Selector{pathError{
				errors.Newf(token.NoPos, "non-constant expression %s",
					internal.DebugStr(x.Index))}}
		} else {
			sel = basicLitSelector(b)
		}
		return append(a, sel)

	case *ast.SelectorExpr:
		a := toSelectors(x.X)
		return append(a, identSelector(x.Sel))

	default:
		return []Selector{Selector{pathError{
			errors.Newf(token.NoPos, "invalid label %s ", internal.DebugStr(x)),
		}}}
	}
}

func basicLitSelector(b *ast.BasicLit) Selector {
	switch b.Kind {
	case token.INT:
		var n literal.NumInfo
		if err := literal.ParseNum(b.Value, &n); err != nil {
			return Selector{pathError{
				errors.Newf(token.NoPos, "invalid string index %s", b.Value),
			}}
		}
		var d apd.Decimal
		_ = n.Decimal(&d)
		i, err := d.Int64()
		if err != nil {
			return Selector{pathError{
				errors.Newf(token.NoPos, "integer %s out of range", b.Value),
			}}
		}
		return Index(int(i))

	case token.STRING:
		info, _, _, _ := literal.ParseQuotes(b.Value, b.Value)
		if !info.IsDouble() {
			return Selector{pathError{
				errors.Newf(token.NoPos, "invalid string index %s", b.Value)}}
		}
		s, _ := literal.Unquote(b.Value)
		return Selector{stringSelector(s)}

	default:
		return Selector{pathError{
			errors.Newf(token.NoPos, "invalid literal %s", b.Value),
		}}
	}
}

func identSelector(label ast.Label) Selector {
	switch x := label.(type) {
	case *ast.Ident:
		if isHiddenOrDefinition(x.Name) {
			return Selector{definitionSelector(x.Name)}
		}
		return Selector{stringSelector(x.Name)}

	case *ast.BasicLit:
		return basicLitSelector(x)

	default:
		return Selector{pathError{
			errors.Newf(token.NoPos, "invalid label %s ", internal.DebugStr(x)),
		}}
	}
}

// Err reports errors that occurred when generating the path.
func (p Path) Err() error {
	var errs errors.Error
	for _, x := range p.path {
		if err, ok := x.sel.(pathError); ok {
			errs = errors.Append(errs, err.Error)
		}
	}
	return errs
}

func isHiddenOrDefinition(s string) bool {
	return strings.HasPrefix(s, "#") || strings.HasPrefix(s, "_")
}

// A Def marks a string as a definition label. An # will be added if a string is
// not prefixed with an # or _# already. Hidden labels are qualified by the
// package in which they are looked up.
func Def(s string) Selector {
	if !isHiddenOrDefinition(s) {
		s = "#" + s
	}
	return Selector{definitionSelector(s)}
}

type definitionSelector string

// String returns the CUE representation of the definition.
func (d definitionSelector) String() string {
	return string(d)
}

func (d definitionSelector) kind() adt.FeatureType {
	switch {
	case strings.HasPrefix(string(d), "#"):
		return adt.DefinitionLabel
	case strings.HasPrefix(string(d), "_#"):
		return adt.HiddenDefinitionLabel
	case strings.HasPrefix(string(d), "_"):
		return adt.HiddenLabel
	default:
		panic("invalid definition")
	}
}

func (d definitionSelector) feature(r adt.Runtime) adt.Feature {
	return adt.MakeIdentLabel(r, string(d), "")
}

// A Str is a CUE string label. Definition selectors are defined with Def.
func Str(s string) Selector {
	return Selector{stringSelector(s)}
}

type stringSelector string

func (s stringSelector) String() string {
	str := string(s)
	if isHiddenOrDefinition(str) || !ast.IsValidIdent(str) {
		return literal.Label.Quote(str)
	}
	return str
}

func (s stringSelector) kind() adt.FeatureType { return adt.StringLabel }

func (s stringSelector) feature(r adt.Runtime) adt.Feature {
	return adt.MakeStringLabel(r, string(s))
}

// An Index selects a list element by index.
func Index(x int) Selector {
	f, err := adt.MakeLabel(nil, int64(x), adt.IntLabel)
	if err != nil {
		return Selector{pathError{err}}
	}
	return Selector{indexSelector(f)}
}

type indexSelector adt.Feature

func (s indexSelector) String() string {
	return strconv.Itoa(adt.Feature(s).Index())
}

func (s indexSelector) kind() adt.FeatureType { return adt.IntLabel }

func (s indexSelector) feature(r adt.Runtime) adt.Feature {
	return adt.Feature(s)
}

// TODO: allow import paths to be represented?
//
// // ImportPath defines a lookup at the root of an instance. It must be the first
// // element of a Path.
// func ImportPath(s string) Selector {
// 	return importSelector(s)
// }

// type importSelector string

// func (s importSelector) String() string {
// 	return literal.String.Quote(string(s))
// }

// func (s importSelector) feature(r adt.Runtime) adt.Feature {
// 	return adt.InvalidLabel
// }

// TODO: allow looking up in parent scopes?

// // Parent returns a Selector for looking up in the parent of a current node.
// // Parent selectors may only occur at the start of a Path.
// func Parent() Selector {
// 	return parentSelector{}
// }

// type parentSelector struct{}

// func (p parentSelector) String() string { return "__up" }
// func (p parentSelector) feature(r adt.Runtime) adt.Feature {
// 	return adt.InvalidLabel
// }

type pathError struct {
	errors.Error
}

func (p pathError) String() string        { return p.Error.Error() }
func (p pathError) kind() adt.FeatureType { return 0 }
func (p pathError) feature(r adt.Runtime) adt.Feature {
	return adt.InvalidLabel
}
<|endoftext|>


<commit_before>package models

import (
	"github.com/ararog/timeago"
	"github.com/jinzhu/gorm"
	"time"
)

type Job struct {
	gorm.Model

	Reference string
	Status    string
	Container string
	Message   string
	Start     time.Time
	End       time.Time
	Tag       string
	BuildDir  string

	Branch   Branch
	BranchID uint `gorm:"index"`

	Build   Build
	BuildID uint `gorm:"index"`

	StatusTime string `gorm:"-"`

	Artifacts []Artifact
}

func (j *Job) SetStatusTime() {
	if j.Start.IsZero() {
		j.StatusTime = "not started"
	} else if j.End.IsZero() {
		j.StatusTime, _ = timeago.TimeAgoFromNowWithTime(j.Start)
	} else {
		j.StatusTime = j.End.Sub(j.Start).String()
	}
}

func (j *Job) StoreTag(tag string) {
	j.Tag = tag
	Handle().Save(j)
}

func (j *Job) SetStatus(status string, message ...string) error {
	t := time.Now()
	final := false

	j.Status = status

	// Error, failed and passed are final statusses, add the end-time
	if status == StatusError || status == StatusFailed || status == StatusPassed {
		final = true
		j.End = t
	}
	if len(message) == 1 {
		j.Message = message[0]
	}
	err := Handle().Save(j).Error
	if final && err == nil {
		UpdateBranchStatus(j.BranchID, status, t)
	}
	return err
}
<commit_msg>Set top-level state to building when we are building<commit_after>package models

import (
	"github.com/ararog/timeago"
	"github.com/jinzhu/gorm"
	"time"
)

type Job struct {
	gorm.Model

	Reference string
	Status    string
	Container string
	Message   string
	Start     time.Time
	End       time.Time
	Tag       string
	BuildDir  string

	Branch   Branch
	BranchID uint `gorm:"index"`

	Build   Build
	BuildID uint `gorm:"index"`

	StatusTime string `gorm:"-"`

	Artifacts []Artifact
}

func (j *Job) SetStatusTime() {
	if j.Start.IsZero() {
		j.StatusTime = "not started"
	} else if j.End.IsZero() {
		j.StatusTime, _ = timeago.TimeAgoFromNowWithTime(j.Start)
	} else {
		j.StatusTime = j.End.Sub(j.Start).String()
	}
}

func (j *Job) StoreTag(tag string) {
	j.Tag = tag
	Handle().Save(j)
}

func (j *Job) SetStatus(status string, message ...string) error {
	t := time.Now()
	j.Status = status

	// Error, failed and passed are final statusses, add the end-time
	if status == StatusError || status == StatusFailed || status == StatusPassed {
		j.End = t
	}
	if len(message) == 1 {
		j.Message = message[0]
	}
	err := Handle().Save(j).Error
	UpdateBranchStatus(j.BranchID, status, t)
	return err
}
<|endoftext|>


<commit_before><commit_msg>Handle alternative input using keys on stdin.<commit_after><|endoftext|>


<commit_before>package common

import (
	"fmt"
	"log"
	"os"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/ec2metadata"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/hashicorp/go-cleanhttp"
	"github.com/hashicorp/packer/template/interpolate"
)

// AccessConfig is for common configuration related to AWS access
type AccessConfig struct {
	AccessKey         string `mapstructure:"access_key"`
	CustomEndpointEc2 string `mapstructure:"custom_endpoint_ec2"`
	MFACode           string `mapstructure:"mfa_code"`
	ProfileName       string `mapstructure:"profile"`
	RawRegion         string `mapstructure:"region"`
	SecretKey         string `mapstructure:"secret_key"`
	SkipValidation    bool   `mapstructure:"skip_region_validation"`
	Token             string `mapstructure:"token"`
	session           *session.Session
}

// Config returns a valid aws.Config object for access to AWS services, or
// an error if the authentication and region couldn't be resolved
func (c *AccessConfig) Session() (*session.Session, error) {
	if c.session != nil {
		return c.session, nil
	}

	if c.ProfileName != "" {
		if err := os.Setenv("AWS_PROFILE", c.ProfileName); err != nil {
			log.Printf("Set env error: %s", err)
		}
	}

	config := aws.NewConfig().WithMaxRetries(11).WithCredentialsChainVerboseErrors(true)

	if region := c.region(); region != "" {
		config = config.WithRegion(region)
	}

	if c.CustomEndpointEc2 != "" {
		config = config.WithEndpoint(c.CustomEndpointEc2)
	}

	if c.AccessKey != "" {
		creds := credentials.NewChainCredentials(
			[]credentials.Provider{
				&credentials.StaticProvider{
					Value: credentials.Value{
						AccessKeyID:     c.AccessKey,
						SecretAccessKey: c.SecretKey,
						SessionToken:    c.Token,
					},
				},
			})
		config = config.WithCredentials(creds)
	}

	opts := session.Options{
		SharedConfigState: session.SharedConfigEnable,
		Config:            *config,
	}
	if c.MFACode != "" {
		opts.AssumeRoleTokenProvider = func() (string, error) {
			return c.MFACode, nil
		}
	}
	var err error
	c.session, err = session.NewSessionWithOptions(opts)
	if err != nil {
		return nil, err
	}

	return c.session, nil
}

// region returns either the region from config or region from metadata service
func (c *AccessConfig) region() string {
	if c.RawRegion != "" {
		return c.RawRegion
	}

	client := cleanhttp.DefaultClient()

	// Keep the default timeout (100ms) low as we don't want to wait in non-EC2 environments
	client.Timeout = 100 * time.Millisecond
	ec2meta := ec2metadata.New(session.New(), &aws.Config{
		HTTPClient: client,
	})
	region, err := ec2meta.Region()
	if err != nil {
		log.Println("Error getting region from metadata service, "+
			"probably because we're not running on AWS.", err)
		return ""
	}
	return region
}

func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error {
	var errs []error
	if c.RawRegion != "" && !c.SkipValidation {
		if valid := ValidateRegion(c.RawRegion); !valid {
			errs = append(errs, fmt.Errorf("Unknown region: %s", c.RawRegion))
		}
	}

	if len(errs) > 0 {
		return errs
	}

	return nil
}
<commit_msg>this is a critical error<commit_after>package common

import (
	"fmt"
	"log"
	"os"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/ec2metadata"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/hashicorp/go-cleanhttp"
	"github.com/hashicorp/packer/template/interpolate"
)

// AccessConfig is for common configuration related to AWS access
type AccessConfig struct {
	AccessKey         string `mapstructure:"access_key"`
	CustomEndpointEc2 string `mapstructure:"custom_endpoint_ec2"`
	MFACode           string `mapstructure:"mfa_code"`
	ProfileName       string `mapstructure:"profile"`
	RawRegion         string `mapstructure:"region"`
	SecretKey         string `mapstructure:"secret_key"`
	SkipValidation    bool   `mapstructure:"skip_region_validation"`
	Token             string `mapstructure:"token"`
	session           *session.Session
}

// Config returns a valid aws.Config object for access to AWS services, or
// an error if the authentication and region couldn't be resolved
func (c *AccessConfig) Session() (*session.Session, error) {
	if c.session != nil {
		return c.session, nil
	}

	if c.ProfileName != "" {
		if err := os.Setenv("AWS_PROFILE", c.ProfileName); err != nil {
			return nil, fmt.Errorf("Set env error: %s", err)
		}
	}

	config := aws.NewConfig().WithMaxRetries(11).WithCredentialsChainVerboseErrors(true)

	if region := c.region(); region != "" {
		config = config.WithRegion(region)
	}

	if c.CustomEndpointEc2 != "" {
		config = config.WithEndpoint(c.CustomEndpointEc2)
	}

	if c.AccessKey != "" {
		creds := credentials.NewChainCredentials(
			[]credentials.Provider{
				&credentials.StaticProvider{
					Value: credentials.Value{
						AccessKeyID:     c.AccessKey,
						SecretAccessKey: c.SecretKey,
						SessionToken:    c.Token,
					},
				},
			})
		config = config.WithCredentials(creds)
	}

	opts := session.Options{
		SharedConfigState: session.SharedConfigEnable,
		Config:            *config,
	}
	if c.MFACode != "" {
		opts.AssumeRoleTokenProvider = func() (string, error) {
			return c.MFACode, nil
		}
	}
	var err error
	c.session, err = session.NewSessionWithOptions(opts)
	if err != nil {
		return nil, err
	}

	return c.session, nil
}

// region returns either the region from config or region from metadata service
func (c *AccessConfig) region() string {
	if c.RawRegion != "" {
		return c.RawRegion
	}

	client := cleanhttp.DefaultClient()

	// Keep the default timeout (100ms) low as we don't want to wait in non-EC2 environments
	client.Timeout = 100 * time.Millisecond
	ec2meta := ec2metadata.New(session.New(), &aws.Config{
		HTTPClient: client,
	})
	region, err := ec2meta.Region()
	if err != nil {
		log.Println("Error getting region from metadata service, "+
			"probably because we're not running on AWS.", err)
		return ""
	}
	return region
}

func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error {
	var errs []error
	if c.RawRegion != "" && !c.SkipValidation {
		if valid := ValidateRegion(c.RawRegion); !valid {
			errs = append(errs, fmt.Errorf("Unknown region: %s", c.RawRegion))
		}
	}

	if len(errs) > 0 {
		return errs
	}

	return nil
}
<|endoftext|>