<commit_before>package main // FIXME omapi

import (
	"bytes"
	"crypto/hmac"
	"crypto/md5"
	"encoding/base64"
	"encoding/binary"
	"fmt"
	"math/rand"
	"net"
	"time"
	"sort"
	"os"
)

type Opcode int32

const (
	OpOpen Opcode = 1 + iota
	OpRefresh
	OpUpdate
	OpNotify
	OpStatus
	OpDelete
)

var Ethernet = []byte{0, 0, 0, 1}
var TokenRing = []byte{0, 0, 0, 6}
var FDDI = []byte{0, 0, 0, 8}

var True = []byte{0, 0, 0, 1}

func (opcode Opcode) String() (ret string) {
	switch opcode {
	case 1:
		ret = "open"
	case 2:
		ret = "refresh"
	case 3:
		ret = "update"
	case 4:
		ret = "notify"
	case 5:
		ret = "status"
	case 6:
		ret = "delete"
	}

	return
}

// TODO add size checks for all operations
type buffer struct {
	buffer *bytes.Buffer
}

func newBuffer() *buffer {
	return &buffer{new(bytes.Buffer)}
}

func (b *buffer) add_bytes(data []byte) {
	b.buffer.Write(data)
}

func (b *buffer) add(data interface{}) {
	err := binary.Write(b.buffer, binary.BigEndian, data)
	if err != nil {
		panic(err)
	}
}

func (b *buffer) add_map(data map[string][]byte) {
	// We need to add the map in a deterministic order for signing to
	// work, so we first sort the keys in alphabetical order, then use
	// that order to access the map entries.

	keys := make(sort.StringSlice, 0, len(data))

	for key := range data {
		keys = append(keys, key)
	}

	sort.Sort(keys)

	for _, key := range keys {
		value := data[key]

		b.add(int16(len(key)))
		b.add([]byte(key))

		b.add(int32(len(value)))
		b.add(value)
	}

	b.add([]byte("\x00\x00"))
}

func (b *buffer) bytes() []byte {
	return b.buffer.Bytes()
}

type Message struct {
	AuthID    int32
	Opcode    Opcode
	Handle    int32
	Tid       int32
	Rid       int32
	Message   map[string][]byte
	Object    map[string][]byte
	Signature []byte
}

func NewMessage() *Message {
	msg := &Message{
		Tid:     rand.Int31(),
		Message: make(map[string][]byte),
		Object:  make(map[string][]byte),
	}

	return msg
}

func NewOpenMessage(typeName string) *Message {
	message := NewMessage()
	message.Opcode = OpOpen
	message.Message["type"] = []byte(typeName)

	return message
}

func NewDeleteMessage(handle int32) *Message {
	message := NewMessage()
	message.Opcode = OpDelete
	message.Handle = handle

	return message
}

func (m *Message) Bytes(forSigning bool) []byte {
	ret := newBuffer()
	if !forSigning {
		ret.add(m.AuthID)
	}

	ret.add(int32(len(m.Signature)))
	ret.add(m.Opcode)
	ret.add(m.Handle)
	ret.add(m.Tid)
	ret.add(m.Rid)
	ret.add_map(m.Message)
	ret.add_map(m.Object)
	if !forSigning {
		ret.add(m.Signature)
	}

	return ret.buffer.Bytes()
}

func (m *Message) Sign(auth Authenticator) {
	m.AuthID = auth.AuthID()
	m.Signature = auth.Sign(m)
}

func (m *Message) Verify(auth Authenticator) bool {
	return bytes.Equal(auth.Sign(m), m.Signature)
}

func (m *Message) IsResponseTo(other *Message) bool {
	return m.Rid == other.Tid
}

type Connection struct {
	Hostname      string
	Port          int
	Username      string
	Key           string
	Authenticator Authenticator
	connection    *net.TCPConn
	inBuffer      *bytes.Buffer
}

func NewConnection(hostname string, port int, username string, key string) *Connection {
	con := &Connection{
		Hostname:      hostname,
		Port:          port,
		Username:      username,
		Key:           key,
		Authenticator: new(NullAuthenticator),
		inBuffer:      new(bytes.Buffer),
	}

	var newAuth Authenticator = new(NullAuthenticator)

	if len(username) > 0 && len(key) > 0 {
		decodedKey, err := base64.StdEncoding.DecodeString(key)
		if err != nil {
			panic(err)
		}
		newAuth = &HMACMD5Authenticator{username, decodedKey, -1}
	}

	raddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", hostname, port))
	if err != nil {
		// TODO return the error instead
		panic(err)
	}
	tcpConn, err := net.DialTCP("tcp", nil, raddr)
	if err != nil {
		// TODO return the error instead
		panic(err)
	}

	con.connection = tcpConn

	con.SendProtocolInitialization()
	con.ReceiveProtocolInitialization()
	con.initializeAuthenticator(newAuth)

	return con
}

func (con *Connection) initializeAuthenticator(auth Authenticator) {
	if _, ok := auth.(*NullAuthenticator); ok {
		return
	}

	message := NewOpenMessage("authenticator")
	for key, value := range auth.AuthObject() {
		message.Object[key] = value
	}

	response := con.queryServer(message)

	if response.Opcode != OpUpdate {
		panic("received non-update response for open")
	}

	if response.Handle == 0 {
		panic("received invalid authid from server")
	}

	auth.SetAuthID(response.Handle)
	con.Authenticator = auth
}

func (con *Connection) queryServer(msg *Message) *Message {
	msg.Sign(con.Authenticator)
	con.Send(msg.Bytes(false))
	response := con.parseMessage()
	if !response.IsResponseTo(msg) {
		panic("received message is not the desired response")
	}

	// TODO check authid

	return response
}

func (con *Connection) Send(data []byte) (n int, err error) {
	return con.connection.Write(data)
}

func (con *Connection) SendProtocolInitialization() {
	buf := newBuffer()
	buf.add(int32(100)) // Protocol version
	buf.add(int32(24))  // Header size
	con.Send(buf.bytes())
}

func (con *Connection) Read() {
	buf := make([]byte, 2048)
	n, err := con.connection.Read(buf)
	if err != nil {
		panic(err)
	}

	con.inBuffer.Write(buf[0:n])
}

func (con *Connection) WaitForN(n int) {
	for con.inBuffer.Len() < n {
		con.Read()
	}
}

func (con *Connection) parseStartupMessage() (version, headerSize int32) {
	con.WaitForN(8)

	binary.Read(con.inBuffer, binary.BigEndian, &version)
	binary.Read(con.inBuffer, binary.BigEndian, &headerSize)

	return
}

func (con *Connection) parseMap() map[string][]byte {
	dict := make(map[string][]byte)

	var (
		keyLength   int16
		valueLength int32
		key         []byte
		value       []byte
	)

	for {
		con.WaitForN(2)
		binary.Read(con.inBuffer, binary.BigEndian, &keyLength)
		if keyLength == 0 {
			// end of map
			break
		}

		con.WaitForN(int(keyLength))
		key = make([]byte, keyLength)
		con.inBuffer.Read(key)

		con.WaitForN(4)
		binary.Read(con.inBuffer, binary.BigEndian, &valueLength)
		con.WaitForN(int(valueLength))
		value = make([]byte, valueLength)
		con.inBuffer.Read(value)

		dict[string(key)] = value
	}

	return dict
}

func (con *Connection) parseMessage() *Message {
	message := new(Message)
	con.WaitForN(24) // authid + authlen + opcode + handle + tid + rid

	var authlen int32

	binary.Read(con.inBuffer, binary.BigEndian, &message.AuthID)
	binary.Read(con.inBuffer, binary.BigEndian, &authlen)
	binary.Read(con.inBuffer, binary.BigEndian, &message.Opcode)
	binary.Read(con.inBuffer, binary.BigEndian, &message.Handle)
	binary.Read(con.inBuffer, binary.BigEndian, &message.Tid)
	binary.Read(con.inBuffer, binary.BigEndian, &message.Rid)

	message.Message = con.parseMap()
	message.Object = con.parseMap()

	con.WaitForN(int(authlen))
	message.Signature = make([]byte, authlen)
	con.inBuffer.Read(message.Signature)

	return message
}

func (con *Connection) ReceiveProtocolInitialization() {
	version, headerSize := con.parseStartupMessage()
	if version != 100 {
		panic("version mismatch")
	}

	if headerSize != 24 {
		panic("header size mismatch")
	}
}

type Authenticator interface {
	Sign(*Message) []byte
	AuthObject() map[string][]byte
	AuthLen() int32
	AuthID() int32
	SetAuthID(int32)
}

type NullAuthenticator struct{}

func (_ *NullAuthenticator) AuthObject() map[string][]byte {
	return make(map[string][]byte)
}

func (_ *NullAuthenticator) Sign(_ *Message) []byte {
	return []byte("")
}

func (_ *NullAuthenticator) AuthLen() int32 {
	return 0
}

func (_ *NullAuthenticator) AuthID() int32 {
	return 0
}

func (_ *NullAuthenticator) SetAuthID(_ int32) {
}

type HMACMD5Authenticator struct {
	Username string
	Key      []byte
	_AuthID  int32
}

func (auth *HMACMD5Authenticator) AuthObject() map[string][]byte {
	ret := make(map[string][]byte)
	ret["name"] = []byte(auth.Username)
	ret["algorithm"] = []byte("hmac-md5.SIG-ALG.REG.INT.")

	return ret
}

func (auth *HMACMD5Authenticator) Sign(m *Message) []byte {
	hmac := hmac.New(md5.New, auth.Key)

	// The signature's length is part of the message that we are
	// signing, so initialize the signature with the correct length.
	m.Signature = bytes.Repeat([]byte("\x00"), int(auth.AuthLen()))
	hmac.Write(m.Bytes(true))

	return hmac.Sum(nil)
}

func (_ *HMACMD5Authenticator) AuthLen() int32 {
	return 16
}

func (auth *HMACMD5Authenticator) AuthID() int32 {
	return auth._AuthID
}

func (auth *HMACMD5Authenticator) SetAuthID(val int32) {
	auth._AuthID = val
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())

	key := os.Getenv("OMAPI_KEY")
	connection := NewConnection("192.168.1.1", 7911, "omapi_key", key)

	// message := NewOpenMessage("lease")
	// mac, _ := net.ParseMAC("bc:ae:c5:76:1d:5a")
	// message.Object["hardware-address"] = []byte(mac)
	// response := connection.queryServer(message)
	// fmt.Println(response)

	// message := NewOpenMessage("host")
	// // message.Message["create"] = Ethernet
	// mac, _ := net.ParseMAC("08:00:27:4f:72:21")
	// message.Object["hardware-address"] = []byte(mac)

	// // buf := new(bytes.Buffer)
	// // binary.Write(buf, binary.BigEndian, int32(1))

	// message.Object["hardware-type"] = Ethernet

	// response := connection.queryServer(message)
	// fmt.Println(response)
	// response = connection.queryServer(NewDeleteMessage(response.Handle))
	// fmt.Println(response)

	mac, _ := net.ParseMAC("08:00:27:4f:72:21")
	ip := net.ParseIP("192.168.1.33")
	message := NewOpenMessage("host")

	message.Message["create"] = True
	message.Message["exclusive"] = True
	message.Object["hardware-address"] = []byte(mac)
	message.Object["hardware-type"] = Ethernet
	message.Object["ip-address"] = []byte(ip[12:])
	message.Object["statements"] = []byte("ddns-hostname=\"win7.vm\";")
	message.Object["name"] = []byte("win7.vm")

	response := connection.queryServer(message)
	if response.Opcode != OpUpdate {
		fmt.Println("add failed:", string(response.Message["message"]))
	}
	// fmt.Println(response)
}
<commit_msg>gofmt<commit_after>package main // FIXME omapi

import (
	"bytes"
	"crypto/hmac"
	"crypto/md5"
	"encoding/base64"
	"encoding/binary"
	"fmt"
	"math/rand"
	"net"
	"os"
	"sort"
	"time"
)

type Opcode int32

const (
	OpOpen Opcode = 1 + iota
	OpRefresh
	OpUpdate
	OpNotify
	OpStatus
	OpDelete
)

var Ethernet = []byte{0, 0, 0, 1}
var TokenRing = []byte{0, 0, 0, 6}
var FDDI = []byte{0, 0, 0, 8}

var True = []byte{0, 0, 0, 1}

func (opcode Opcode) String() (ret string) {
	switch opcode {
	case 1:
		ret = "open"
	case 2:
		ret = "refresh"
	case 3:
		ret = "update"
	case 4:
		ret = "notify"
	case 5:
		ret = "status"
	case 6:
		ret = "delete"
	}

	return
}

// TODO add size checks for all operations
type buffer struct {
	buffer *bytes.Buffer
}

func newBuffer() *buffer {
	return &buffer{new(bytes.Buffer)}
}

func (b *buffer) add_bytes(data []byte) {
	b.buffer.Write(data)
}

func (b *buffer) add(data interface{}) {
	err := binary.Write(b.buffer, binary.BigEndian, data)
	if err != nil {
		panic(err)
	}
}

func (b *buffer) add_map(data map[string][]byte) {
	// We need to add the map in a deterministic order for signing to
	// work, so we first sort the keys in alphabetical order, then use
	// that order to access the map entries.

	keys := make(sort.StringSlice, 0, len(data))

	for key := range data {
		keys = append(keys, key)
	}

	sort.Sort(keys)

	for _, key := range keys {
		value := data[key]

		b.add(int16(len(key)))
		b.add([]byte(key))

		b.add(int32(len(value)))
		b.add(value)
	}

	b.add([]byte("\x00\x00"))
}

func (b *buffer) bytes() []byte {
	return b.buffer.Bytes()
}

type Message struct {
	AuthID    int32
	Opcode    Opcode
	Handle    int32
	Tid       int32
	Rid       int32
	Message   map[string][]byte
	Object    map[string][]byte
	Signature []byte
}

func NewMessage() *Message {
	msg := &Message{
		Tid:     rand.Int31(),
		Message: make(map[string][]byte),
		Object:  make(map[string][]byte),
	}

	return msg
}

func NewOpenMessage(typeName string) *Message {
	message := NewMessage()
	message.Opcode = OpOpen
	message.Message["type"] = []byte(typeName)

	return message
}

func NewDeleteMessage(handle int32) *Message {
	message := NewMessage()
	message.Opcode = OpDelete
	message.Handle = handle

	return message
}

func (m *Message) Bytes(forSigning bool) []byte {
	ret := newBuffer()
	if !forSigning {
		ret.add(m.AuthID)
	}

	ret.add(int32(len(m.Signature)))
	ret.add(m.Opcode)
	ret.add(m.Handle)
	ret.add(m.Tid)
	ret.add(m.Rid)
	ret.add_map(m.Message)
	ret.add_map(m.Object)
	if !forSigning {
		ret.add(m.Signature)
	}

	return ret.buffer.Bytes()
}

func (m *Message) Sign(auth Authenticator) {
	m.AuthID = auth.AuthID()
	m.Signature = auth.Sign(m)
}

func (m *Message) Verify(auth Authenticator) bool {
	return bytes.Equal(auth.Sign(m), m.Signature)
}

func (m *Message) IsResponseTo(other *Message) bool {
	return m.Rid == other.Tid
}

type Connection struct {
	Hostname      string
	Port          int
	Username      string
	Key           string
	Authenticator Authenticator
	connection    *net.TCPConn
	inBuffer      *bytes.Buffer
}

func NewConnection(hostname string, port int, username string, key string) *Connection {
	con := &Connection{
		Hostname:      hostname,
		Port:          port,
		Username:      username,
		Key:           key,
		Authenticator: new(NullAuthenticator),
		inBuffer:      new(bytes.Buffer),
	}

	var newAuth Authenticator = new(NullAuthenticator)

	if len(username) > 0 && len(key) > 0 {
		decodedKey, err := base64.StdEncoding.DecodeString(key)
		if err != nil {
			panic(err)
		}
		newAuth = &HMACMD5Authenticator{username, decodedKey, -1}
	}

	raddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", hostname, port))
	if err != nil {
		// TODO return the error instead
		panic(err)
	}
	tcpConn, err := net.DialTCP("tcp", nil, raddr)
	if err != nil {
		// TODO return the error instead
		panic(err)
	}

	con.connection = tcpConn

	con.SendProtocolInitialization()
	con.ReceiveProtocolInitialization()
	con.initializeAuthenticator(newAuth)

	return con
}

func (con *Connection) initializeAuthenticator(auth Authenticator) {
	if _, ok := auth.(*NullAuthenticator); ok {
		return
	}

	message := NewOpenMessage("authenticator")
	for key, value := range auth.AuthObject() {
		message.Object[key] = value
	}

	response := con.queryServer(message)

	if response.Opcode != OpUpdate {
		panic("received non-update response for open")
	}

	if response.Handle == 0 {
		panic("received invalid authid from server")
	}

	auth.SetAuthID(response.Handle)
	con.Authenticator = auth
}

func (con *Connection) queryServer(msg *Message) *Message {
	msg.Sign(con.Authenticator)
	con.Send(msg.Bytes(false))
	response := con.parseMessage()
	if !response.IsResponseTo(msg) {
		panic("received message is not the desired response")
	}

	// TODO check authid

	return response
}

func (con *Connection) Send(data []byte) (n int, err error) {
	return con.connection.Write(data)
}

func (con *Connection) SendProtocolInitialization() {
	buf := newBuffer()
	buf.add(int32(100)) // Protocol version
	buf.add(int32(24))  // Header size
	con.Send(buf.bytes())
}

func (con *Connection) Read() {
	buf := make([]byte, 2048)
	n, err := con.connection.Read(buf)
	if err != nil {
		panic(err)
	}

	con.inBuffer.Write(buf[0:n])
}

func (con *Connection) WaitForN(n int) {
	for con.inBuffer.Len() < n {
		con.Read()
	}
}

func (con *Connection) parseStartupMessage() (version, headerSize int32) {
	con.WaitForN(8)

	binary.Read(con.inBuffer, binary.BigEndian, &version)
	binary.Read(con.inBuffer, binary.BigEndian, &headerSize)

	return
}

func (con *Connection) parseMap() map[string][]byte {
	dict := make(map[string][]byte)

	var (
		keyLength   int16
		valueLength int32
		key         []byte
		value       []byte
	)

	for {
		con.WaitForN(2)
		binary.Read(con.inBuffer, binary.BigEndian, &keyLength)
		if keyLength == 0 {
			// end of map
			break
		}

		con.WaitForN(int(keyLength))
		key = make([]byte, keyLength)
		con.inBuffer.Read(key)

		con.WaitForN(4)
		binary.Read(con.inBuffer, binary.BigEndian, &valueLength)
		con.WaitForN(int(valueLength))
		value = make([]byte, valueLength)
		con.inBuffer.Read(value)

		dict[string(key)] = value
	}

	return dict
}

func (con *Connection) parseMessage() *Message {
	message := new(Message)
	con.WaitForN(24) // authid + authlen + opcode + handle + tid + rid

	var authlen int32

	binary.Read(con.inBuffer, binary.BigEndian, &message.AuthID)
	binary.Read(con.inBuffer, binary.BigEndian, &authlen)
	binary.Read(con.inBuffer, binary.BigEndian, &message.Opcode)
	binary.Read(con.inBuffer, binary.BigEndian, &message.Handle)
	binary.Read(con.inBuffer, binary.BigEndian, &message.Tid)
	binary.Read(con.inBuffer, binary.BigEndian, &message.Rid)

	message.Message = con.parseMap()
	message.Object = con.parseMap()

	con.WaitForN(int(authlen))
	message.Signature = make([]byte, authlen)
	con.inBuffer.Read(message.Signature)

	return message
}

func (con *Connection) ReceiveProtocolInitialization() {
	version, headerSize := con.parseStartupMessage()
	if version != 100 {
		panic("version mismatch")
	}

	if headerSize != 24 {
		panic("header size mismatch")
	}
}

type Authenticator interface {
	Sign(*Message) []byte
	AuthObject() map[string][]byte
	AuthLen() int32
	AuthID() int32
	SetAuthID(int32)
}

type NullAuthenticator struct{}

func (_ *NullAuthenticator) AuthObject() map[string][]byte {
	return make(map[string][]byte)
}

func (_ *NullAuthenticator) Sign(_ *Message) []byte {
	return []byte("")
}

func (_ *NullAuthenticator) AuthLen() int32 {
	return 0
}

func (_ *NullAuthenticator) AuthID() int32 {
	return 0
}

func (_ *NullAuthenticator) SetAuthID(_ int32) {
}

type HMACMD5Authenticator struct {
	Username string
	Key      []byte
	_AuthID  int32
}

func (auth *HMACMD5Authenticator) AuthObject() map[string][]byte {
	ret := make(map[string][]byte)
	ret["name"] = []byte(auth.Username)
	ret["algorithm"] = []byte("hmac-md5.SIG-ALG.REG.INT.")

	return ret
}

func (auth *HMACMD5Authenticator) Sign(m *Message) []byte {
	hmac := hmac.New(md5.New, auth.Key)

	// The signature's length is part of the message that we are
	// signing, so initialize the signature with the correct length.
	m.Signature = bytes.Repeat([]byte("\x00"), int(auth.AuthLen()))
	hmac.Write(m.Bytes(true))

	return hmac.Sum(nil)
}

func (_ *HMACMD5Authenticator) AuthLen() int32 {
	return 16
}

func (auth *HMACMD5Authenticator) AuthID() int32 {
	return auth._AuthID
}

func (auth *HMACMD5Authenticator) SetAuthID(val int32) {
	auth._AuthID = val
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())

	key := os.Getenv("OMAPI_KEY")
	connection := NewConnection("192.168.1.1", 7911, "omapi_key", key)

	// message := NewOpenMessage("lease")
	// mac, _ := net.ParseMAC("bc:ae:c5:76:1d:5a")
	// message.Object["hardware-address"] = []byte(mac)
	// response := connection.queryServer(message)
	// fmt.Println(response)

	// message := NewOpenMessage("host")
	// // message.Message["create"] = Ethernet
	// mac, _ := net.ParseMAC("08:00:27:4f:72:21")
	// message.Object["hardware-address"] = []byte(mac)

	// // buf := new(bytes.Buffer)
	// // binary.Write(buf, binary.BigEndian, int32(1))

	// message.Object["hardware-type"] = Ethernet

	// response := connection.queryServer(message)
	// fmt.Println(response)
	// response = connection.queryServer(NewDeleteMessage(response.Handle))
	// fmt.Println(response)

	mac, _ := net.ParseMAC("08:00:27:4f:72:21")
	ip := net.ParseIP("192.168.1.33")
	message := NewOpenMessage("host")

	message.Message["create"] = True
	message.Message["exclusive"] = True
	message.Object["hardware-address"] = []byte(mac)
	message.Object["hardware-type"] = Ethernet
	message.Object["ip-address"] = []byte(ip[12:])
	message.Object["statements"] = []byte("ddns-hostname=\"win7.vm\";")
	message.Object["name"] = []byte("win7.vm")

	response := connection.queryServer(message)
	if response.Opcode != OpUpdate {
		fmt.Println("add failed:", string(response.Message["message"]))
	}
	// fmt.Println(response)
}
<|endoftext|>


<commit_before>package app

import (
	"errors"
	"fmt"
	"strings"

	"github.com/moncho/dry/appui"
	"github.com/moncho/dry/docker"
	"github.com/moncho/dry/ui"
	termbox "github.com/nsf/termbox-go"
)

type cMenuEventHandler struct {
	baseEventHandler
}

func (h *cMenuEventHandler) handle(event termbox.Event, f func(eventHandler)) {

	handled := true
	switch event.Key {

	case termbox.KeyEsc:
		h.screen.Cursor.Reset()
		h.dry.SetViewMode(Main)
		f(viewsToHandlers[Main])

	case termbox.KeyEnter:
		err := widgets.ContainerMenu.OnEvent(func(s string) error {
			//s is a string made of two parts: an Id and a description
			//separated by ":"
			cd := strings.Split(s, ":")
			if len(cd) != 2 {
				return errors.New("Invalid command description: " + s)
			}
			id := cd[0]
			command, err := docker.CommandFromDescription(cd[1])
			if err != nil {
				return err
			}
			h.handleCommand(id, command, f)
			return nil
		})
		if err != nil {
			h.dry.appmessage(fmt.Sprintf("Could not run command: %s", err.Error()))
		}
	default:
		handled = false
	}

	if !handled {
		h.baseEventHandler.handle(event, f)
	} else {
		refreshScreen()
	}
}

func (h *cMenuEventHandler) handleCommand(id string, command docker.Command, f func(eventHandler)) {

	dry := h.dry
	screen := h.screen

	container := dry.dockerDaemon.ContainerByID(id)
	switch command {
	case docker.KILL:
		prompt := appui.NewPrompt(
			fmt.Sprintf("Do you want to kill container %s? (y/N)", id))
		widgets.add(prompt)
		forwarder := newEventForwarder()
		f(forwarder)
		refreshScreen()

		go func() {
			events := ui.EventSource{
				Events: forwarder.events(),
				EventHandledCallback: func(e termbox.Event) error {
					return refreshScreen()
				},
			}
			prompt.OnFocus(events)
			conf, cancel := prompt.Text()
			f(h)
			widgets.remove(prompt)
			if cancel || (conf != "y" && conf != "Y") {
				return
			}

			dry.actionMessage(id, "Killing")
			err := dry.dockerDaemon.Kill(id)
			if err == nil {
				widgets.ContainerMenu.ForContainer(id)
				refreshScreen()
			} else {
				dry.errorMessage(id, "killing", err)
			}

		}()
	case docker.RESTART:

		prompt := appui.NewPrompt(
			fmt.Sprintf("Do you want to restart container %s? (y/N)", id))
		widgets.add(prompt)
		forwarder := newEventForwarder()
		f(forwarder)
		refreshScreen()

		go func() {
			events := ui.EventSource{
				Events: forwarder.events(),
				EventHandledCallback: func(e termbox.Event) error {
					return refreshScreen()
				},
			}
			prompt.OnFocus(events)
			conf, cancel := prompt.Text()
			f(h)
			widgets.remove(prompt)
			if cancel || (conf != "y" && conf != "Y") {

				return
			}

			if err := dry.dockerDaemon.RestartContainer(id); err == nil {
				widgets.ContainerMenu.ForContainer(id)
				refreshScreen()
			} else {
				dry.appmessage(
					fmt.Sprintf("Error restarting container %s, err: %s", id, err.Error()))
			}

		}()

	case docker.STOP:

		prompt := appui.NewPrompt(
			fmt.Sprintf("Do you want to stop container %s? (y/N)", id))
		widgets.add(prompt)
		forwarder := newEventForwarder()
		f(forwarder)
		refreshScreen()

		go func() {
			events := ui.EventSource{
				Events: forwarder.events(),
				EventHandledCallback: func(e termbox.Event) error {
					return refreshScreen()
				},
			}
			prompt.OnFocus(events)
			conf, cancel := prompt.Text()
			f(h)
			widgets.remove(prompt)
			if cancel || (conf != "y" && conf != "Y") {

				return
			}

			dry.actionMessage(id, "Stopping")
			err := dry.dockerDaemon.StopContainer(id)
			if err == nil {
				widgets.ContainerMenu.ForContainer(id)
				refreshScreen()
			} else {
				dry.errorMessage(id, "stopping", err)
			}

		}()
	case docker.LOGS:

		prompt := logsPrompt()
		widgets.add(prompt)
		forwarder := newEventForwarder()
		f(forwarder)
		refreshScreen()
		go func() {
			events := ui.EventSource{
				Events: forwarder.events(),
				EventHandledCallback: func(e termbox.Event) error {
					return refreshScreen()
				},
			}
			prompt.OnFocus(events)
			widgets.remove(prompt)
			since, canceled := prompt.Text()

			if canceled {
				return
			}

			logs, err := h.dry.dockerDaemon.Logs(id, since)
			if err == nil {
				appui.Stream(logs, forwarder.events(),
					func() {
						h.dry.SetViewMode(ContainerMenu)
						f(h)
						f(h)
						refreshScreen()
					})
			} else {
				h.dry.appmessage("Error showing container logs: " + err.Error())
			}
		}()
	case docker.RM:
		prompt := appui.NewPrompt(
			fmt.Sprintf("Do you want to remove container %s? (y/N)", id))
		widgets.add(prompt)
		forwarder := newEventForwarder()
		f(forwarder)
		refreshScreen()

		go func() {
			events := ui.EventSource{
				Events: forwarder.events(),
				EventHandledCallback: func(e termbox.Event) error {
					return refreshScreen()
				},
			}
			prompt.OnFocus(events)
			conf, cancel := prompt.Text()
			f(h)
			widgets.remove(prompt)
			if cancel || (conf != "y" && conf != "Y") {

				return
			}

			dry.actionMessage(id, "Removing")
			err := dry.dockerDaemon.Rm(id)
			if err == nil {
				dry.actionMessage(id, "removed")
				f(viewsToHandlers[Main])
				dry.SetViewMode(Main)
				refreshScreen()
			} else {
				dry.errorMessage(id, "removing", err)
			}

		}()

	case docker.STATS:
		forwarder := newEventForwarder()
		f(forwarder)
		refreshScreen()

		h.dry.SetViewMode(NoView)
		statsChan := dry.dockerDaemon.OpenChannel(container)
		go statsScreen(container, statsChan, screen, forwarder.events(),
			func() {
				h.dry.SetViewMode(ContainerMenu)
				f(h)
				f(h)
				refreshScreen()
			})

	case docker.INSPECT:
		forwarder := newEventForwarder()
		f(forwarder)
		refreshScreen()

		err := inspect(
			h.screen,
			forwarder.events(),
			func(id string) (interface{}, error) {
				return h.dry.dockerDaemon.Inspect(id)
			},
			func() {
				h.dry.SetViewMode(ContainerMenu)
				f(h)
				refreshScreen()
			})(id)

		if err != nil {
			dry.appmessage(
				fmt.Sprintf("Error inspecting container: %s", err.Error()))
			return
		}
	case docker.HISTORY:
		history, err := dry.dockerDaemon.History(container.ImageID)

		if err == nil {
			renderer := appui.NewDockerImageHistoryRenderer(history)
			forwarder := newEventForwarder()
			f(forwarder)
			go appui.Less(renderer, screen, forwarder.events(), func() {
				h.dry.SetViewMode(ContainerMenu)
				f(h)
				refreshScreen()
			})
		} else {
			dry.appmessage(
				fmt.Sprintf("Error showing image history: %s", err.Error()))
		}
	}
}
<commit_msg>Minor<commit_after>package app

import (
	"errors"
	"fmt"
	"strings"

	"github.com/moncho/dry/appui"
	"github.com/moncho/dry/docker"
	"github.com/moncho/dry/ui"
	termbox "github.com/nsf/termbox-go"
)

type cMenuEventHandler struct {
	baseEventHandler
}

func (h *cMenuEventHandler) handle(event termbox.Event, f func(eventHandler)) {

	handled := true
	switch event.Key {

	case termbox.KeyEsc:
		h.screen.Cursor.Reset()
		h.dry.SetViewMode(Main)
		f(viewsToHandlers[Main])

	case termbox.KeyEnter:
		err := widgets.ContainerMenu.OnEvent(func(s string) error {
			//s is a string made of two parts: an Id and a description
			//separated by ":"
			cd := strings.Split(s, ":")
			if len(cd) != 2 {
				return errors.New("Invalid command description: " + s)
			}
			id := cd[0]
			command, err := docker.CommandFromDescription(cd[1])
			if err != nil {
				return err
			}
			h.handleCommand(id, command, f)
			return nil
		})
		if err != nil {
			h.dry.appmessage(fmt.Sprintf("Could not run command: %s", err.Error()))
		}
	default:
		handled = false
	}

	if !handled {
		h.baseEventHandler.handle(event, f)
	} else {
		refreshScreen()
	}
}

func (h *cMenuEventHandler) handleCommand(id string, command docker.Command, f func(eventHandler)) {

	dry := h.dry
	screen := h.screen

	container := dry.dockerDaemon.ContainerByID(id)
	switch command {
	case docker.KILL:
		prompt := appui.NewPrompt(
			fmt.Sprintf("Do you want to kill container %s? (y/N)", id))
		widgets.add(prompt)
		forwarder := newEventForwarder()
		f(forwarder)
		refreshScreen()

		go func() {
			events := ui.EventSource{
				Events: forwarder.events(),
				EventHandledCallback: func(e termbox.Event) error {
					return refreshScreen()
				},
			}
			prompt.OnFocus(events)
			conf, cancel := prompt.Text()
			f(h)
			widgets.remove(prompt)
			if cancel || (conf != "y" && conf != "Y") {
				return
			}

			dry.actionMessage(id, "Killing")
			err := dry.dockerDaemon.Kill(id)
			if err == nil {
				widgets.ContainerMenu.ForContainer(id)
				refreshScreen()
			} else {
				dry.errorMessage(id, "killing", err)
			}

		}()
	case docker.RESTART:

		prompt := appui.NewPrompt(
			fmt.Sprintf("Do you want to restart container %s? (y/N)", id))
		widgets.add(prompt)
		forwarder := newEventForwarder()
		f(forwarder)
		refreshScreen()

		go func() {
			events := ui.EventSource{
				Events: forwarder.events(),
				EventHandledCallback: func(e termbox.Event) error {
					return refreshScreen()
				},
			}
			prompt.OnFocus(events)
			conf, cancel := prompt.Text()
			f(h)
			widgets.remove(prompt)
			if cancel || (conf != "y" && conf != "Y") {

				return
			}

			if err := dry.dockerDaemon.RestartContainer(id); err == nil {
				widgets.ContainerMenu.ForContainer(id)
				refreshScreen()
			} else {
				dry.appmessage(
					fmt.Sprintf("Error restarting container %s, err: %s", id, err.Error()))
			}

		}()

	case docker.STOP:

		prompt := appui.NewPrompt(
			fmt.Sprintf("Do you want to stop container %s? (y/N)", id))
		widgets.add(prompt)
		forwarder := newEventForwarder()
		f(forwarder)
		refreshScreen()

		go func() {
			events := ui.EventSource{
				Events: forwarder.events(),
				EventHandledCallback: func(e termbox.Event) error {
					return refreshScreen()
				},
			}
			prompt.OnFocus(events)
			conf, cancel := prompt.Text()
			f(h)
			widgets.remove(prompt)
			if cancel || (conf != "y" && conf != "Y") {

				return
			}

			dry.actionMessage(id, "Stopping")
			err := dry.dockerDaemon.StopContainer(id)
			if err == nil {
				widgets.ContainerMenu.ForContainer(id)
				refreshScreen()
			} else {
				dry.errorMessage(id, "stopping", err)
			}

		}()
	case docker.LOGS:

		prompt := logsPrompt()
		widgets.add(prompt)
		forwarder := newEventForwarder()
		f(forwarder)
		refreshScreen()
		go func() {
			events := ui.EventSource{
				Events: forwarder.events(),
				EventHandledCallback: func(e termbox.Event) error {
					return refreshScreen()
				},
			}
			prompt.OnFocus(events)
			widgets.remove(prompt)
			since, canceled := prompt.Text()

			if canceled {
				return
			}

			logs, err := h.dry.dockerDaemon.Logs(id, since)
			if err == nil {
				appui.Stream(logs, forwarder.events(),
					func() {
						h.dry.SetViewMode(ContainerMenu)
						f(h)
						refreshScreen()
					})
			} else {
				h.dry.appmessage("Error showing container logs: " + err.Error())
			}
		}()
	case docker.RM:
		prompt := appui.NewPrompt(
			fmt.Sprintf("Do you want to remove container %s? (y/N)", id))
		widgets.add(prompt)
		forwarder := newEventForwarder()
		f(forwarder)
		refreshScreen()

		go func() {
			events := ui.EventSource{
				Events: forwarder.events(),
				EventHandledCallback: func(e termbox.Event) error {
					return refreshScreen()
				},
			}
			prompt.OnFocus(events)
			conf, cancel := prompt.Text()
			f(h)
			widgets.remove(prompt)
			if cancel || (conf != "y" && conf != "Y") {

				return
			}

			dry.actionMessage(id, "Removing")
			err := dry.dockerDaemon.Rm(id)
			if err == nil {
				dry.actionMessage(id, "removed")
				f(viewsToHandlers[Main])
				dry.SetViewMode(Main)
				refreshScreen()
			} else {
				dry.errorMessage(id, "removing", err)
			}

		}()

	case docker.STATS:
		forwarder := newEventForwarder()
		f(forwarder)
		refreshScreen()

		h.dry.SetViewMode(NoView)
		statsChan := dry.dockerDaemon.OpenChannel(container)
		go statsScreen(container, statsChan, screen, forwarder.events(),
			func() {
				h.dry.SetViewMode(ContainerMenu)
				f(h)
				refreshScreen()
			})

	case docker.INSPECT:
		forwarder := newEventForwarder()
		f(forwarder)
		refreshScreen()

		err := inspect(
			h.screen,
			forwarder.events(),
			func(id string) (interface{}, error) {
				return h.dry.dockerDaemon.Inspect(id)
			},
			func() {
				h.dry.SetViewMode(ContainerMenu)
				f(h)
				refreshScreen()
			})(id)

		if err != nil {
			dry.appmessage(
				fmt.Sprintf("Error inspecting container: %s", err.Error()))
			return
		}
	case docker.HISTORY:
		history, err := dry.dockerDaemon.History(container.ImageID)

		if err == nil {
			renderer := appui.NewDockerImageHistoryRenderer(history)
			forwarder := newEventForwarder()
			f(forwarder)
			go appui.Less(renderer, screen, forwarder.events(), func() {
				h.dry.SetViewMode(ContainerMenu)
				f(h)
				refreshScreen()
			})
		} else {
			dry.appmessage(
				fmt.Sprintf("Error showing image history: %s", err.Error()))
		}
	}
}
<|endoftext|>


<commit_before>// +build go1.1

package pq

import (
	"bufio"
	"bytes"
	"database/sql"
	"database/sql/driver"
	"github.com/lib/pq/oid"
	"io"
	"net"
	"strconv"
	"strings"
	"testing"
)

var (
	selectStringQuery = "SELECT '" + strings.Repeat("0123456789", 10) + "'"
	selectSeriesQuery = "SELECT generate_series(1, 100)"
)

func BenchmarkSelectString(b *testing.B) {
	var result string
	benchQuery(b, selectStringQuery, &result)
}

func BenchmarkSelectSeries(b *testing.B) {
	var result int
	benchQuery(b, selectSeriesQuery, &result)
}

func benchQuery(b *testing.B, query string, result interface{}) {
	b.Skip("current pq database-backed benchmarks are inconsistent")
	b.StopTimer()
	db := openTestConn(b)
	defer db.Close()
	b.StartTimer()

	for i := 0; i < b.N; i++ {
		benchQueryLoop(b, db, query, result)
	}
}

func benchQueryLoop(b *testing.B, db *sql.DB, query string, result interface{}) {
	rows, err := db.Query(query)
	if err != nil {
		b.Fatal(err)
	}
	defer rows.Close()
	for rows.Next() {
		err = rows.Scan(result)
		if err != nil {
			b.Fatal("failed to scan", err)
		}
	}
}

// reading from circularConn yields content[:prefixLen] once, followed by
// content[prefixLen:] over and over again. It never returns EOF.
type circularConn struct {
	content   string
	prefixLen int
	pos       int
	net.Conn  // for all other net.Conn methods that will never be called
}

func (r *circularConn) Read(b []byte) (n int, err error) {
	n = copy(b, r.content[r.pos:])
	r.pos += n
	if r.pos >= len(r.content) {
		r.pos = r.prefixLen
	}
	return
}

func (r *circularConn) Write(b []byte) (n int, err error) { return len(b), nil }

func (r *circularConn) Close() error { return nil }

func fakeConn(content string, prefixLen int) *conn {
	c := &circularConn{content: content, prefixLen: prefixLen}
	return &conn{buf: bufio.NewReader(c), c: c}
}

// This benchmark is meant to be the same as BenchmarkSelectString, but takes
// out some of the factors this package can't control. The numbers are less noisy,
// but also the costs of network communication aren't accurately represented.
func BenchmarkMockSelectString(b *testing.B) {
	b.StopTimer()
	// taken from a recorded run of BenchmarkSelectString
	// See: http://www.postgresql.org/docs/9.2/static/protocol-message-formats.html
	const response = "1\x00\x00\x00\x04" +
		"t\x00\x00\x00\x06\x00\x00" +
		"T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" +
		"Z\x00\x00\x00\x05I" +
		"2\x00\x00\x00\x04" +
		"D\x00\x00\x00n\x00\x01\x00\x00\x00d0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" +
		"C\x00\x00\x00\rSELECT 1\x00" +
		"Z\x00\x00\x00\x05I" +
		"3\x00\x00\x00\x04" +
		"Z\x00\x00\x00\x05I"
	c := fakeConn(response, 0)
	b.StartTimer()

	for i := 0; i < b.N; i++ {
		benchMockQuery(b, c, selectStringQuery)
	}
}

var seriesRowData = func() string {
	var buf bytes.Buffer
	for i := 1; i <= 100; i++ {
		digits := byte(2)
		if i >= 100 {
			digits = 3
		} else if i < 10 {
			digits = 1
		}
		buf.WriteString("D\x00\x00\x00")
		buf.WriteByte(10 + digits)
		buf.WriteString("\x00\x01\x00\x00\x00")
		buf.WriteByte(digits)
		buf.WriteString(strconv.Itoa(i))
	}
	return buf.String()
}()

func BenchmarkMockSelectSeries(b *testing.B) {
	b.StopTimer()
	var response = "1\x00\x00\x00\x04" +
		"t\x00\x00\x00\x06\x00\x00" +
		"T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" +
		"Z\x00\x00\x00\x05I" +
		"2\x00\x00\x00\x04" +
		seriesRowData +
		"C\x00\x00\x00\x0fSELECT 100\x00" +
		"Z\x00\x00\x00\x05I" +
		"3\x00\x00\x00\x04" +
		"Z\x00\x00\x00\x05I"
	c := fakeConn(response, 0)
	b.StartTimer()

	for i := 0; i < b.N; i++ {
		benchMockQuery(b, c, selectSeriesQuery)
	}
}

func benchMockQuery(b *testing.B, c *conn, query string) {
	stmt, err := c.Prepare(query)
	if err != nil {
		b.Fatal(err)
	}
	defer stmt.Close()
	rows, err := stmt.Query(nil)
	if err != nil {
		b.Fatal(err)
	}
	defer rows.Close()
	var dest [1]driver.Value
	for {
		if err := rows.Next(dest[:]); err != nil {
			if err == io.EOF {
				break
			}
			b.Fatal(err)
		}
	}
}

func BenchmarkPreparedSelectString(b *testing.B) {
	var result string
	benchPreparedQuery(b, selectStringQuery, &result)
}

func BenchmarkPreparedSelectSeries(b *testing.B) {
	var result int
	benchPreparedQuery(b, selectSeriesQuery, &result)
}

func benchPreparedQuery(b *testing.B, query string, result interface{}) {
	b.Skip("current pq database-backed benchmarks are inconsistent")
	b.StopTimer()
	db := openTestConn(b)
	defer db.Close()
	stmt, err := db.Prepare(query)
	if err != nil {
		b.Fatal(err)
	}
	defer stmt.Close()
	b.StartTimer()

	for i := 0; i < b.N; i++ {
		benchPreparedQueryLoop(b, db, stmt, result)
	}
}

func benchPreparedQueryLoop(b *testing.B, db *sql.DB, stmt *sql.Stmt, result interface{}) {
	rows, err := stmt.Query()
	if err != nil {
		b.Fatal(err)
	}
	if !rows.Next() {
		rows.Close()
		b.Fatal("no rows")
	}
	defer rows.Close()
	for rows.Next() {
		err = rows.Scan(&result)
		if err != nil {
			b.Fatal("failed to scan")
		}
	}
}

// See the comment for BenchmarkMockSelectString.
func BenchmarkMockPreparedSelectString(b *testing.B) {
	b.StopTimer()
	const parseResponse = "1\x00\x00\x00\x04" +
		"t\x00\x00\x00\x06\x00\x00" +
		"T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" +
		"Z\x00\x00\x00\x05I"
	const responses = parseResponse +
		"2\x00\x00\x00\x04" +
		"D\x00\x00\x00n\x00\x01\x00\x00\x00d0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" +
		"C\x00\x00\x00\rSELECT 1\x00" +
		"Z\x00\x00\x00\x05I"
	c := fakeConn(responses, len(parseResponse))

	stmt, err := c.Prepare(selectStringQuery)
	if err != nil {
		b.Fatal(err)
	}
	b.StartTimer()

	for i := 0; i < b.N; i++ {
		benchPreparedMockQuery(b, c, stmt)
	}
}

func BenchmarkMockPreparedSelectSeries(b *testing.B) {
	b.StopTimer()
	const parseResponse = "1\x00\x00\x00\x04" +
		"t\x00\x00\x00\x06\x00\x00" +
		"T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" +
		"Z\x00\x00\x00\x05I"
	var responses = parseResponse +
		"2\x00\x00\x00\x04" +
		seriesRowData +
		"C\x00\x00\x00\x0fSELECT 100\x00" +
		"Z\x00\x00\x00\x05I"
	c := fakeConn(responses, len(parseResponse))

	stmt, err := c.Prepare(selectSeriesQuery)
	if err != nil {
		b.Fatal(err)
	}
	b.StartTimer()

	for i := 0; i < b.N; i++ {
		benchPreparedMockQuery(b, c, stmt)
	}
}

func benchPreparedMockQuery(b *testing.B, c *conn, stmt driver.Stmt) {
	rows, err := stmt.Query(nil)
	if err != nil {
		b.Fatal(err)
	}
	defer rows.Close()
	var dest [1]driver.Value
	for {
		if err := rows.Next(dest[:]); err != nil {
			if err == io.EOF {
				break
			}
			b.Fatal(err)
		}
	}
}

func BenchmarkEncodeInt64(b *testing.B) {
	for i := 0; i < b.N; i++ {
		encode(int64(1234), oid.T_int8)
	}
}

func BenchmarkEncodeFloat64(b *testing.B) {
	for i := 0; i < b.N; i++ {
		encode(3.14159, oid.T_float8)
	}
}

var testByteString = []byte("abcdefghijklmnopqrstuvwxyz")

func BenchmarkEncodeBytea(b *testing.B) {
	for i := 0; i < b.N; i++ {
		encode(testByteString, oid.T_bytea)
	}
}

func BenchmarkEncodeBool(b *testing.B) {
	for i := 0; i < b.N; i++ {
		encode(true, oid.T_bool)
	}
}

var testIntBytes = []byte("1234")

func BenchmarkDecodeInt64(b *testing.B) {
	for i := 0; i < b.N; i++ {
		decode(testIntBytes, oid.T_int8)
	}
}

var testFloatBytes = []byte("3.14159")

func BenchmarkDecodeFloat64(b *testing.B) {
	for i := 0; i < b.N; i++ {
		decode(testFloatBytes, oid.T_float8)
	}
}

var testBoolBytes = []byte{'t'}

func BenchmarkDecodeBool(b *testing.B) {
	for i := 0; i < b.N; i++ {
		decode(testBoolBytes, oid.T_bool)
	}
}

func TestDecodeBool(t *testing.T) {
	db := openTestConn(t)
	rows, err := db.Query("select true")
	if err != nil {
		t.Error(err)
	}
	rows.Close()
}
<commit_msg>Fix panic in bench_test when database auth is not set.<commit_after>// +build go1.1

package pq

import (
	"bufio"
	"bytes"
	"database/sql"
	"database/sql/driver"
	"github.com/lib/pq/oid"
	"io"
	"net"
	"strconv"
	"strings"
	"testing"
)

var (
	selectStringQuery = "SELECT '" + strings.Repeat("0123456789", 10) + "'"
	selectSeriesQuery = "SELECT generate_series(1, 100)"
)

func BenchmarkSelectString(b *testing.B) {
	var result string
	benchQuery(b, selectStringQuery, &result)
}

func BenchmarkSelectSeries(b *testing.B) {
	var result int
	benchQuery(b, selectSeriesQuery, &result)
}

func benchQuery(b *testing.B, query string, result interface{}) {
	b.Skip("current pq database-backed benchmarks are inconsistent")
	b.StopTimer()
	db := openTestConn(b)
	defer db.Close()
	b.StartTimer()

	for i := 0; i < b.N; i++ {
		benchQueryLoop(b, db, query, result)
	}
}

func benchQueryLoop(b *testing.B, db *sql.DB, query string, result interface{}) {
	rows, err := db.Query(query)
	if err != nil {
		b.Fatal(err)
	}
	defer rows.Close()
	for rows.Next() {
		err = rows.Scan(result)
		if err != nil {
			b.Fatal("failed to scan", err)
		}
	}
}

// reading from circularConn yields content[:prefixLen] once, followed by
// content[prefixLen:] over and over again. It never returns EOF.
type circularConn struct {
	content   string
	prefixLen int
	pos       int
	net.Conn  // for all other net.Conn methods that will never be called
}

func (r *circularConn) Read(b []byte) (n int, err error) {
	n = copy(b, r.content[r.pos:])
	r.pos += n
	if r.pos >= len(r.content) {
		r.pos = r.prefixLen
	}
	return
}

func (r *circularConn) Write(b []byte) (n int, err error) { return len(b), nil }

func (r *circularConn) Close() error { return nil }

func fakeConn(content string, prefixLen int) *conn {
	c := &circularConn{content: content, prefixLen: prefixLen}
	return &conn{buf: bufio.NewReader(c), c: c}
}

// This benchmark is meant to be the same as BenchmarkSelectString, but takes
// out some of the factors this package can't control. The numbers are less noisy,
// but also the costs of network communication aren't accurately represented.
func BenchmarkMockSelectString(b *testing.B) {
	b.StopTimer()
	// taken from a recorded run of BenchmarkSelectString
	// See: http://www.postgresql.org/docs/9.2/static/protocol-message-formats.html
	const response = "1\x00\x00\x00\x04" +
		"t\x00\x00\x00\x06\x00\x00" +
		"T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" +
		"Z\x00\x00\x00\x05I" +
		"2\x00\x00\x00\x04" +
		"D\x00\x00\x00n\x00\x01\x00\x00\x00d0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" +
		"C\x00\x00\x00\rSELECT 1\x00" +
		"Z\x00\x00\x00\x05I" +
		"3\x00\x00\x00\x04" +
		"Z\x00\x00\x00\x05I"
	c := fakeConn(response, 0)
	b.StartTimer()

	for i := 0; i < b.N; i++ {
		benchMockQuery(b, c, selectStringQuery)
	}
}

var seriesRowData = func() string {
	var buf bytes.Buffer
	for i := 1; i <= 100; i++ {
		digits := byte(2)
		if i >= 100 {
			digits = 3
		} else if i < 10 {
			digits = 1
		}
		buf.WriteString("D\x00\x00\x00")
		buf.WriteByte(10 + digits)
		buf.WriteString("\x00\x01\x00\x00\x00")
		buf.WriteByte(digits)
		buf.WriteString(strconv.Itoa(i))
	}
	return buf.String()
}()

func BenchmarkMockSelectSeries(b *testing.B) {
	b.StopTimer()
	var response = "1\x00\x00\x00\x04" +
		"t\x00\x00\x00\x06\x00\x00" +
		"T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" +
		"Z\x00\x00\x00\x05I" +
		"2\x00\x00\x00\x04" +
		seriesRowData +
		"C\x00\x00\x00\x0fSELECT 100\x00" +
		"Z\x00\x00\x00\x05I" +
		"3\x00\x00\x00\x04" +
		"Z\x00\x00\x00\x05I"
	c := fakeConn(response, 0)
	b.StartTimer()

	for i := 0; i < b.N; i++ {
		benchMockQuery(b, c, selectSeriesQuery)
	}
}

func benchMockQuery(b *testing.B, c *conn, query string) {
	stmt, err := c.Prepare(query)
	if err != nil {
		b.Fatal(err)
	}
	defer stmt.Close()
	rows, err := stmt.Query(nil)
	if err != nil {
		b.Fatal(err)
	}
	defer rows.Close()
	var dest [1]driver.Value
	for {
		if err := rows.Next(dest[:]); err != nil {
			if err == io.EOF {
				break
			}
			b.Fatal(err)
		}
	}
}

func BenchmarkPreparedSelectString(b *testing.B) {
	var result string
	benchPreparedQuery(b, selectStringQuery, &result)
}

func BenchmarkPreparedSelectSeries(b *testing.B) {
	var result int
	benchPreparedQuery(b, selectSeriesQuery, &result)
}

func benchPreparedQuery(b *testing.B, query string, result interface{}) {
	b.Skip("current pq database-backed benchmarks are inconsistent")
	b.StopTimer()
	db := openTestConn(b)
	defer db.Close()
	stmt, err := db.Prepare(query)
	if err != nil {
		b.Fatal(err)
	}
	defer stmt.Close()
	b.StartTimer()

	for i := 0; i < b.N; i++ {
		benchPreparedQueryLoop(b, db, stmt, result)
	}
}

func benchPreparedQueryLoop(b *testing.B, db *sql.DB, stmt *sql.Stmt, result interface{}) {
	rows, err := stmt.Query()
	if err != nil {
		b.Fatal(err)
	}
	if !rows.Next() {
		rows.Close()
		b.Fatal("no rows")
	}
	defer rows.Close()
	for rows.Next() {
		err = rows.Scan(&result)
		if err != nil {
			b.Fatal("failed to scan")
		}
	}
}

// See the comment for BenchmarkMockSelectString.
func BenchmarkMockPreparedSelectString(b *testing.B) {
	b.StopTimer()
	const parseResponse = "1\x00\x00\x00\x04" +
		"t\x00\x00\x00\x06\x00\x00" +
		"T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" +
		"Z\x00\x00\x00\x05I"
	const responses = parseResponse +
		"2\x00\x00\x00\x04" +
		"D\x00\x00\x00n\x00\x01\x00\x00\x00d0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" +
		"C\x00\x00\x00\rSELECT 1\x00" +
		"Z\x00\x00\x00\x05I"
	c := fakeConn(responses, len(parseResponse))

	stmt, err := c.Prepare(selectStringQuery)
	if err != nil {
		b.Fatal(err)
	}
	b.StartTimer()

	for i := 0; i < b.N; i++ {
		benchPreparedMockQuery(b, c, stmt)
	}
}

func BenchmarkMockPreparedSelectSeries(b *testing.B) {
	b.StopTimer()
	const parseResponse = "1\x00\x00\x00\x04" +
		"t\x00\x00\x00\x06\x00\x00" +
		"T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" +
		"Z\x00\x00\x00\x05I"
	var responses = parseResponse +
		"2\x00\x00\x00\x04" +
		seriesRowData +
		"C\x00\x00\x00\x0fSELECT 100\x00" +
		"Z\x00\x00\x00\x05I"
	c := fakeConn(responses, len(parseResponse))

	stmt, err := c.Prepare(selectSeriesQuery)
	if err != nil {
		b.Fatal(err)
	}
	b.StartTimer()

	for i := 0; i < b.N; i++ {
		benchPreparedMockQuery(b, c, stmt)
	}
}

func benchPreparedMockQuery(b *testing.B, c *conn, stmt driver.Stmt) {
	rows, err := stmt.Query(nil)
	if err != nil {
		b.Fatal(err)
	}
	defer rows.Close()
	var dest [1]driver.Value
	for {
		if err := rows.Next(dest[:]); err != nil {
			if err == io.EOF {
				break
			}
			b.Fatal(err)
		}
	}
}

func BenchmarkEncodeInt64(b *testing.B) {
	for i := 0; i < b.N; i++ {
		encode(int64(1234), oid.T_int8)
	}
}

func BenchmarkEncodeFloat64(b *testing.B) {
	for i := 0; i < b.N; i++ {
		encode(3.14159, oid.T_float8)
	}
}

var testByteString = []byte("abcdefghijklmnopqrstuvwxyz")

func BenchmarkEncodeBytea(b *testing.B) {
	for i := 0; i < b.N; i++ {
		encode(testByteString, oid.T_bytea)
	}
}

func BenchmarkEncodeBool(b *testing.B) {
	for i := 0; i < b.N; i++ {
		encode(true, oid.T_bool)
	}
}

var testIntBytes = []byte("1234")

func BenchmarkDecodeInt64(b *testing.B) {
	for i := 0; i < b.N; i++ {
		decode(testIntBytes, oid.T_int8)
	}
}

var testFloatBytes = []byte("3.14159")

func BenchmarkDecodeFloat64(b *testing.B) {
	for i := 0; i < b.N; i++ {
		decode(testFloatBytes, oid.T_float8)
	}
}

var testBoolBytes = []byte{'t'}

func BenchmarkDecodeBool(b *testing.B) {
	for i := 0; i < b.N; i++ {
		decode(testBoolBytes, oid.T_bool)
	}
}

func TestDecodeBool(t *testing.T) {
	db := openTestConn(t)
	rows, err := db.Query("select true")
	if err != nil {
		t.Fatal(err)
	}
	rows.Close()
}
<|endoftext|>


<commit_before>package lockbox

import (
	"crypto/rand"

	"encoding/pem"
	"io"
	"testing"
)

var (
	enc *Encryptor
	dec *Decryptor

	chunks = map[string][]byte{
		"128B":  mustRandomBytes(128),
		"4KB":   mustRandomBytes(4096),
		"64KB":  mustRandomBytes(65536),
		"512KB": mustRandomBytes(524288),
		"1MB":   mustRandomBytes(1048576),
		"4MB":   mustRandomBytes(4194304),
	}
)

func init() {
	ekey, dkey, err := GenerateKey(rand.Reader)
	if err != nil {
		panic(err)
	}

	eb, _ := pem.Decode(ekey)
	db, _ := pem.Decode(dkey)

	enc, err = NewEncryptor(eb)
	if err != nil {
		panic(err)
	}

	dec, err = NewDecryptor(db)
	if err != nil {
		panic(err)
	}
}

func BenchmarkLockboxEncrypt128B(b *testing.B)  { lbEncrypt("128B", b) }
func BenchmarkLockboxEncrypt4KB(b *testing.B)   { lbEncrypt("4KB", b) }
func BenchmarkLockboxEncrypt64KB(b *testing.B)  { lbEncrypt("64KB", b) }
func BenchmarkLockboxEncrypt512KB(b *testing.B) { lbEncrypt("512KB", b) }
func BenchmarkLockboxEncrypt1MB(b *testing.B)   { lbEncrypt("1MB", b) }
func BenchmarkLockboxEncrypt4MB(b *testing.B)   { lbEncrypt("4MB", b) }

func lbEncrypt(key string, b *testing.B) {
	data, ok := chunks[key]
	if !ok {
		b.Fatalf("missing chunk %s", key)
	}

	b.SetBytes(int64(len(data)))
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		enc.Encrypt(data)
	}
}

func BenchmarkLockboxDecrypt128(b *testing.B)   { lbDecrypt("128B", b) }
func BenchmarkLockboxDecrypt4096(b *testing.B)  { lbDecrypt("4KB", b) }
func BenchmarkLockboxDecrypt64KB(b *testing.B)  { lbDecrypt("64KB", b) }
func BenchmarkLockboxDecrypt512KB(b *testing.B) { lbDecrypt("512KB", b) }
func BenchmarkLockboxDecrypt1MB(b *testing.B)   { lbDecrypt("1MB", b) }
func BenchmarkLockboxDecrypt4MB(b *testing.B)   { lbDecrypt("4MB", b) }

func lbDecrypt(key string, b *testing.B) {
	chunk, ok := chunks[key]
	if !ok {
		b.Fatalf("missing chunk %s", key)
	}
	data, err := enc.Encrypt(chunk)
	if err != nil {
		panic(err)
	}

	b.SetBytes(int64(len(chunk)))
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		dec.Decrypt(data)
	}
}

func mustRandomBytes(s int) []byte {
	buf := make([]byte, s)
	if _, err := io.ReadAtLeast(rand.Reader, buf, s); err != nil {
		panic(err)
	}
	return buf
}
<commit_msg>change benchmark units<commit_after>package lockbox

import (
	"crypto/rand"

	"encoding/pem"
	"io"
	"testing"
)

var (
	enc *Encryptor
	dec *Decryptor

	chunks = map[string][]byte{
		"1B":   make([]byte, 1),
		"64B":  make([]byte, 64),
		"1KB":  make([]byte, 1024),
		"64KB": make([]byte, 65536),
		"1MB":  make([]byte, 1048576),
		"64MB": make([]byte, 67108864),
	}
)

func init() {
	ekey, dkey, err := GenerateKey(rand.Reader)
	if err != nil {
		panic(err)
	}

	eb, _ := pem.Decode(ekey)
	db, _ := pem.Decode(dkey)

	enc, err = NewEncryptor(eb)
	if err != nil {
		panic(err)
	}

	dec, err = NewDecryptor(db)
	if err != nil {
		panic(err)
	}
}

func BenchmarkLockboxEncrypt1B(b *testing.B)   { lbEncrypt("1B", b) }
func BenchmarkLockboxEncrypt64B(b *testing.B)  { lbEncrypt("64B", b) }
func BenchmarkLockboxEncrypt1KB(b *testing.B)  { lbEncrypt("1KB", b) }
func BenchmarkLockboxEncrypt64KB(b *testing.B) { lbEncrypt("64KB", b) }
func BenchmarkLockboxEncrypt1MB(b *testing.B)  { lbEncrypt("1MB", b) }
func BenchmarkLockboxEncrypt64MB(b *testing.B) { lbEncrypt("64MB", b) }

func lbEncrypt(key string, b *testing.B) {
	data, ok := chunks[key]
	if !ok {
		b.Fatalf("missing chunk %s", key)
	}

	b.SetBytes(int64(len(data)))
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		enc.Encrypt(data)
	}
}

func BenchmarkLockboxDecrypt1B(b *testing.B)   { lbDecrypt("1B", b) }
func BenchmarkLockboxDecrypt64B(b *testing.B)  { lbDecrypt("64B", b) }
func BenchmarkLockboxDecrypt1KB(b *testing.B)  { lbDecrypt("1KB", b) }
func BenchmarkLockboxDecrypt64KB(b *testing.B) { lbDecrypt("64KB", b) }
func BenchmarkLockboxDecrypt1MB(b *testing.B)  { lbDecrypt("1MB", b) }
func BenchmarkLockboxDecrypt64MB(b *testing.B) { lbDecrypt("64MB", b) }

func lbDecrypt(key string, b *testing.B) {
	chunk, ok := chunks[key]
	if !ok {
		b.Fatalf("missing chunk %s", key)
	}
	data, err := enc.Encrypt(chunk)
	if err != nil {
		panic(err)
	}

	b.SetBytes(int64(len(chunk)))
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		dec.Decrypt(data)
	}
}

func mustRandomBytes(s int) []byte {
	buf := make([]byte, s)
	if _, err := io.ReadAtLeast(rand.Reader, buf, s); err != nil {
		panic(err)
	}
	return buf
}
<|endoftext|>


<commit_before>package prototype

var defaultPrototypes = []*SpecificationSchema{
	&SpecificationSchema{
		APIVersion: "0.1",
		Name:       "io.ksonnet.pkg.namespace",
		Params: ParamSchemas{
			RequiredParam("name", "name", "Name to give the namespace.", String),
		},
		Template: SnippetSchema{
			Description: `A simple namespace. Labels are automatically populated from the name of the
namespace.`,
			ShortDescription: `Namespace with labels automatically populated from the name`,
			YAMLBody: []string{
				"kind: Namespace",
				"apiVersion: v1",
				"metadata:",
				"  name: ${name}",
				"  labels:",
				"    name: ${name}",
			},
			JSONBody: []string{
				`{`,
				`  "kind": "Namespace",`,
				`  "apiVersion": "v1",`,
				`  "metadata": {`,
				`    "name": ${name},`,
				`    "labels": {`,
				`      "name": ${name}`,
				`    }`,
				`  }`,
				`}`,
			},
			JsonnetBody: []string{
				`local k = import "k.libsonnet";`,
				`local ns = k.core.v1.namespace;`,
				``,
				`ns.new() +`,
				`ns.mixin.metadata.name(${name}) +`,
				`ns.mixin.metadata.labels({name: ${name}})`,
			},
		},
	},
	&SpecificationSchema{
		APIVersion: "0.1",
		Name:       "io.ksonnet.pkg.single-port-service",
		Params: ParamSchemas{
			RequiredParam("name", "serviceName", "Name of the service", String),
			RequiredParam("targetLabelSelector", "selector", "Label for the service to target (e.g., 'app: MyApp').", Object),
			RequiredParam("servicePort", "port", "Port for the service to expose.", NumberOrString),
			RequiredParam("targetPort", "port", "Port for the service target.", NumberOrString),
			OptionalParam("protocol", "protocol", "Protocol to use (either TCP or UDP).", "TCP", String),
		},
		Template: SnippetSchema{
			Description: `A service that exposes 'servicePort', and directs traffic
to 'targetLabelSelector', at 'targetPort'.`,
			ShortDescription: `Service that exposes a single port`,
			YAMLBody: []string{
				"kind: Service",
				"apiVersion: v1",
				"metadata:",
				"  name: ${name}",
				"spec:",
				"  selector:",
				"    ${targetLabelSelector}",
				"  ports:",
				"  - protocol: ${protocol}",
				"    port: ${servicePort}",
				"    targetPort: ${targetPort}",
			},
			JSONBody: []string{
				`{`,
				`  "kind": "Service",`,
				`  "apiVersion": "v1",`,
				`  "metadata": {`,
				`    "name": ${name}`,
				`  },`,
				`  "spec": {`,
				`    "selector": {`,
				`      ${targetLabelSelector}`,
				`    },`,
				`    "ports": [`,
				`      {`,
				`        "protocol": ${protocol},`,
				`        "port": ${servicePort},`,
				`        "targetPort": ${targetPort}`,
				`      }`,
				`    ]`,
				`  }`,
				`}`,
			},
			JsonnetBody: []string{
				`local k = import "k.libsonnet";`,
				`local service = k.core.v1.service;`,
				`local port = k.core.v1.service.mixin.spec.portsType;`,
				``,
				`service.new(`,
				`  ${name},`,
				`  ${targetLabelSelector},`,
				`  port.new(${servicePort}, ${targetPort}))`,
			},
		},
	},
	&SpecificationSchema{
		APIVersion: "0.1",
		Name:       "io.ksonnet.pkg.configMap",
		Params: ParamSchemas{
			RequiredParam("name", "name", "Name to give the configMap.", String),
			OptionalParam("data", "data", "Data for the configMap.", "{}", Object),
		},
		Template: SnippetSchema{
			Description:      `A simple config map with optional user-specified data.`,
			ShortDescription: `A simple config map with optional user-specified data`,
			YAMLBody: []string{
				"apiVersion: v1",
				"kind: ConfigMap",
				"metadata:",
				"  name: ${name}",
				"data: ${data}",
			},
			JSONBody: []string{
				`{`,
				`  "apiVersion": "v1",`,
				`  "kind": "ConfigMap",`,
				`  "metadata": {`,
				`    "name": ${name}`,
				`  },`,
				`  "data": ${data}`,
				`}`,
			},
			JsonnetBody: []string{
				`local k = import "k.libsonnet";`,
				`local configMap = k.core.v1.configMap;`,
				``,
				`configMap.new() +`,
				`configMap.mixin.metadata.name("${name}") +`,
				`configMap.data("${data}")`,
			},
		},
	},
	&SpecificationSchema{
		APIVersion: "0.1",
		Name:       "io.ksonnet.pkg.single-port-deployment",
		Params: ParamSchemas{
			RequiredParam("name", "deploymentName", "Name of the deployment", String),
			RequiredParam("image", "containerImage", "Container image to deploy", String),
			OptionalParam("replicas", "replicas", "Number of replicas", "1", Number),
			OptionalParam("port", "containerPort", "Port to expose", "80", NumberOrString),
		},
		Template: SnippetSchema{
			Description: `A deployment that replicates container 'image' some number of times
(default: 1), and exposes a port (default: 80). Labels are automatically
populated from 'name'.`,
			ShortDescription: `Replicates a container n times, exposes a single port`,
			YAMLBody: []string{
				"apiVersion: apps/v1beta1",
				"kind: Deployment",
				"metadata:",
				"  name: ${name}",
				"spec:",
				"  replicas: ${replicas:1}",
				"  template:",
				"    metadata:",
				"      labels:",
				"        app: ${name}",
				"    spec:",
				"      containers:",
				"      - name: ${name}",
				"        image: ${image}",
				"        ports:",
				"        - containerPort: ${port:80}",
			},
			JSONBody: []string{
				`{`,
				`  "apiVersion": "apps/v1beta1",`,
				`  "kind": "Deployment",`,
				`  "metadata": {`,
				`    "name": ${name}`,
				`  },`,
				`  "spec": {`,
				`    "replicas": ${replicas:1},`,
				`    "template": {`,
				`      "metadata": {`,
				`        "labels": {`,
				`          "app": ${name}`,
				`        }`,
				`      },`,
				`      "spec": {`,
				`        "containers": [`,
				`          {`,
				`            "name": ${name},`,
				`            "image": ${image},`,
				`            "ports": [`,
				`              {`,
				`                "containerPort": ${port:80}`,
				`              }`,
				`            ]`,
				`          }`,
				`        ]`,
				`      }`,
				`    }`,
				`  }`,
				`}`,
			},
			JsonnetBody: []string{
				`local k = import "k.libsonnet";`,
				`local deployment = k.apps.v1beta1.deployment;`,
				`local container = k.apps.v1beta1.deployment.mixin.spec.template.spec.containersType;`,
				`local port = container.portsType;`,
				``,
				`deployment.new(`,
				`  ${name},`,
				`  ${replicas},`,
				`  container.new(${name}, ${image}) +`,
				`    container.ports(port.new(${port:80})),`,
				`  {app: ${name}})`,
			},
		},
	},
}
<commit_msg>Add example to the service prototype's documentation<commit_after>package prototype

var defaultPrototypes = []*SpecificationSchema{
	&SpecificationSchema{
		APIVersion: "0.1",
		Name:       "io.ksonnet.pkg.namespace",
		Params: ParamSchemas{
			RequiredParam("name", "name", "Name to give the namespace.", String),
		},
		Template: SnippetSchema{
			Description: `A simple namespace. Labels are automatically populated from the name of the
namespace.`,
			ShortDescription: `Namespace with labels automatically populated from the name`,
			YAMLBody: []string{
				"kind: Namespace",
				"apiVersion: v1",
				"metadata:",
				"  name: ${name}",
				"  labels:",
				"    name: ${name}",
			},
			JSONBody: []string{
				`{`,
				`  "kind": "Namespace",`,
				`  "apiVersion": "v1",`,
				`  "metadata": {`,
				`    "name": ${name},`,
				`    "labels": {`,
				`      "name": ${name}`,
				`    }`,
				`  }`,
				`}`,
			},
			JsonnetBody: []string{
				`local k = import "k.libsonnet";`,
				`local ns = k.core.v1.namespace;`,
				``,
				`ns.new() +`,
				`ns.mixin.metadata.name(${name}) +`,
				`ns.mixin.metadata.labels({name: ${name}})`,
			},
		},
	},
	&SpecificationSchema{
		APIVersion: "0.1",
		Name:       "io.ksonnet.pkg.single-port-service",
		Params: ParamSchemas{
			RequiredParam("name", "serviceName", "Name of the service", String),
			RequiredParam("targetLabelSelector", "selector", `Label for the service to target (e.g., "{app: 'MyApp'}").`, Object),
			RequiredParam("servicePort", "port", "Port for the service to expose.", NumberOrString),
			RequiredParam("targetPort", "port", "Port for the service target.", NumberOrString),
			OptionalParam("protocol", "protocol", "Protocol to use (either TCP or UDP).", "TCP", String),
		},
		Template: SnippetSchema{
			Description: `A service that exposes 'servicePort', and directs traffic
to 'targetLabelSelector', at 'targetPort'. Since 'targetLabelSelector' is an
object literal that specifies which labels the service is meant to target, this
will typically look something like:

  ksonnet prototype use service --targetLabelSelector "{app: 'nginx'}" [...]`,
			ShortDescription: `Service that exposes a single port`,
			YAMLBody: []string{
				"kind: Service",
				"apiVersion: v1",
				"metadata:",
				"  name: ${name}",
				"spec:",
				"  selector:",
				"    ${targetLabelSelector}",
				"  ports:",
				"  - protocol: ${protocol}",
				"    port: ${servicePort}",
				"    targetPort: ${targetPort}",
			},
			JSONBody: []string{
				`{`,
				`  "kind": "Service",`,
				`  "apiVersion": "v1",`,
				`  "metadata": {`,
				`    "name": ${name}`,
				`  },`,
				`  "spec": {`,
				`    "selector": {`,
				`      ${targetLabelSelector}`,
				`    },`,
				`    "ports": [`,
				`      {`,
				`        "protocol": ${protocol},`,
				`        "port": ${servicePort},`,
				`        "targetPort": ${targetPort}`,
				`      }`,
				`    ]`,
				`  }`,
				`}`,
			},
			JsonnetBody: []string{
				`local k = import "k.libsonnet";`,
				`local service = k.core.v1.service;`,
				`local port = k.core.v1.service.mixin.spec.portsType;`,
				``,
				`service.new(`,
				`  ${name},`,
				`  ${targetLabelSelector},`,
				`  port.new(${servicePort}, ${targetPort}))`,
			},
		},
	},
	&SpecificationSchema{
		APIVersion: "0.1",
		Name:       "io.ksonnet.pkg.configMap",
		Params: ParamSchemas{
			RequiredParam("name", "name", "Name to give the configMap.", String),
			OptionalParam("data", "data", "Data for the configMap.", "{}", Object),
		},
		Template: SnippetSchema{
			Description:      `A simple config map with optional user-specified data.`,
			ShortDescription: `A simple config map with optional user-specified data`,
			YAMLBody: []string{
				"apiVersion: v1",
				"kind: ConfigMap",
				"metadata:",
				"  name: ${name}",
				"data: ${data}",
			},
			JSONBody: []string{
				`{`,
				`  "apiVersion": "v1",`,
				`  "kind": "ConfigMap",`,
				`  "metadata": {`,
				`    "name": ${name}`,
				`  },`,
				`  "data": ${data}`,
				`}`,
			},
			JsonnetBody: []string{
				`local k = import "k.libsonnet";`,
				`local configMap = k.core.v1.configMap;`,
				``,
				`configMap.new() +`,
				`configMap.mixin.metadata.name("${name}") +`,
				`configMap.data("${data}")`,
			},
		},
	},
	&SpecificationSchema{
		APIVersion: "0.1",
		Name:       "io.ksonnet.pkg.single-port-deployment",
		Params: ParamSchemas{
			RequiredParam("name", "deploymentName", "Name of the deployment", String),
			RequiredParam("image", "containerImage", "Container image to deploy", String),
			OptionalParam("replicas", "replicas", "Number of replicas", "1", Number),
			OptionalParam("port", "containerPort", "Port to expose", "80", NumberOrString),
		},
		Template: SnippetSchema{
			Description: `A deployment that replicates container 'image' some number of times
(default: 1), and exposes a port (default: 80). Labels are automatically
populated from 'name'.`,
			ShortDescription: `Replicates a container n times, exposes a single port`,
			YAMLBody: []string{
				"apiVersion: apps/v1beta1",
				"kind: Deployment",
				"metadata:",
				"  name: ${name}",
				"spec:",
				"  replicas: ${replicas:1}",
				"  template:",
				"    metadata:",
				"      labels:",
				"        app: ${name}",
				"    spec:",
				"      containers:",
				"      - name: ${name}",
				"        image: ${image}",
				"        ports:",
				"        - containerPort: ${port:80}",
			},
			JSONBody: []string{
				`{`,
				`  "apiVersion": "apps/v1beta1",`,
				`  "kind": "Deployment",`,
				`  "metadata": {`,
				`    "name": ${name}`,
				`  },`,
				`  "spec": {`,
				`    "replicas": ${replicas:1},`,
				`    "template": {`,
				`      "metadata": {`,
				`        "labels": {`,
				`          "app": ${name}`,
				`        }`,
				`      },`,
				`      "spec": {`,
				`        "containers": [`,
				`          {`,
				`            "name": ${name},`,
				`            "image": ${image},`,
				`            "ports": [`,
				`              {`,
				`                "containerPort": ${port:80}`,
				`              }`,
				`            ]`,
				`          }`,
				`        ]`,
				`      }`,
				`    }`,
				`  }`,
				`}`,
			},
			JsonnetBody: []string{
				`local k = import "k.libsonnet";`,
				`local deployment = k.apps.v1beta1.deployment;`,
				`local container = k.apps.v1beta1.deployment.mixin.spec.template.spec.containersType;`,
				`local port = container.portsType;`,
				``,
				`deployment.new(`,
				`  ${name},`,
				`  ${replicas},`,
				`  container.new(${name}, ${image}) +`,
				`    container.ports(port.new(${port:80})),`,
				`  {app: ${name}})`,
			},
		},
	},
}
<|endoftext|>


<commit_before>package main

import (
	"golang.org/x/crypto/bcrypt"
	"net/http"
	"os"
	"time"
)

func ownerNew(email string, name string, password string) (string, error) {
	if email == "" || name == "" || password == "" {
		return "", errorMissingField
	}

	if os.Getenv("FORBID_NEW_OWNERS") == "true" {
		return "", errorNewOwnerForbidden
	}

	ownerHex, err := randomHex(32)
	if err != nil {
		logger.Errorf("cannot generate ownerHex: %v", err)
		return "", errorInternal
	}

	passwordHash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		logger.Errorf("cannot generate hash from password: %v\n", err)
		return "", errorInternal
	}

	statement := `
		INSERT INTO
		owners (ownerHex, email, name, passwordHash, joinDate, confirmedEmail)
		VALUES ($1,       $2,    $3,   $4,           $5,       $6            );
	`
	_, err = db.Exec(statement, ownerHex, email, name, string(passwordHash), time.Now().UTC(), !smtpConfigured)
	if err != nil {
		// TODO: Make sure `err` is actually about conflicting UNIQUE, and not some
		// other error. If it is something else, we should probably return `errorInternal`.
		return "", errorEmailAlreadyExists
	}

	if smtpConfigured {
		confirmHex, err := randomHex(32)
		if err != nil {
			logger.Errorf("cannot generate confirmHex: %v", err)
			return "", errorInternal
		}

		statement = `
      INSERT INTO
      ownerConfirmHexes (confirmHex, ownerHex, sendDate)
      VALUES            ($1,         $2,       $3      );
    `
		_, err = db.Exec(statement, confirmHex, ownerHex, time.Now().UTC())
		if err != nil {
			logger.Errorf("cannot insert confirmHex: %v\n", err)
			return "", errorInternal
		}

		if err = smtpOwnerConfirmHex(email, name, confirmHex); err != nil {
			return "", err
		}
	}

	return ownerHex, nil
}

func ownerNewHandler(w http.ResponseWriter, r *http.Request) {
	type request struct {
		Email    *string `json:"email"`
		Name     *string `json:"name"`
		Password *string `json:"password"`
	}

	var x request
	if err := bodyUnmarshal(r, &x); err != nil {
		bodyMarshal(w, response{"success": false, "message": err.Error()})
		return
	}

	if _, err := ownerNew(*x.Email, *x.Name, *x.Password); err != nil {
		bodyMarshal(w, response{"success": false, "message": err.Error()})
		return
	}

	if _, err := commenterNew(*x.Email, *x.Name, "undefined", "undefined", "commento", *x.Password); err != nil {
		bodyMarshal(w, response{"success": false, "message": err.Error()})
		return
	}

	bodyMarshal(w, response{"success": true, "confirmEmail": smtpConfigured})
}
<commit_msg>owner_new.go: perform email check before processing<commit_after>package main

import (
	"golang.org/x/crypto/bcrypt"
	"net/http"
	"os"
	"time"
)

func ownerNew(email string, name string, password string) (string, error) {
	if email == "" || name == "" || password == "" {
		return "", errorMissingField
	}

	if os.Getenv("FORBID_NEW_OWNERS") == "true" {
		return "", errorNewOwnerForbidden
	}

	if _, err := ownerGetByEmail(email); err == nil {
		return "", errorEmailAlreadyExists
	}

	ownerHex, err := randomHex(32)
	if err != nil {
		logger.Errorf("cannot generate ownerHex: %v", err)
		return "", errorInternal
	}

	passwordHash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		logger.Errorf("cannot generate hash from password: %v\n", err)
		return "", errorInternal
	}

	statement := `
		INSERT INTO
		owners (ownerHex, email, name, passwordHash, joinDate, confirmedEmail)
		VALUES ($1,       $2,    $3,   $4,           $5,       $6            );
	`
	_, err = db.Exec(statement, ownerHex, email, name, string(passwordHash), time.Now().UTC(), !smtpConfigured)
	if err != nil {
		// TODO: Make sure `err` is actually about conflicting UNIQUE, and not some
		// other error. If it is something else, we should probably return `errorInternal`.
		return "", errorEmailAlreadyExists
	}

	if smtpConfigured {
		confirmHex, err := randomHex(32)
		if err != nil {
			logger.Errorf("cannot generate confirmHex: %v", err)
			return "", errorInternal
		}

		statement = `
      INSERT INTO
      ownerConfirmHexes (confirmHex, ownerHex, sendDate)
      VALUES            ($1,         $2,       $3      );
    `
		_, err = db.Exec(statement, confirmHex, ownerHex, time.Now().UTC())
		if err != nil {
			logger.Errorf("cannot insert confirmHex: %v\n", err)
			return "", errorInternal
		}

		if err = smtpOwnerConfirmHex(email, name, confirmHex); err != nil {
			return "", err
		}
	}

	return ownerHex, nil
}

func ownerNewHandler(w http.ResponseWriter, r *http.Request) {
	type request struct {
		Email    *string `json:"email"`
		Name     *string `json:"name"`
		Password *string `json:"password"`
	}

	var x request
	if err := bodyUnmarshal(r, &x); err != nil {
		bodyMarshal(w, response{"success": false, "message": err.Error()})
		return
	}

	if _, err := ownerNew(*x.Email, *x.Name, *x.Password); err != nil {
		bodyMarshal(w, response{"success": false, "message": err.Error()})
		return
	}

	if _, err := commenterNew(*x.Email, *x.Name, "undefined", "undefined", "commento", *x.Password); err != nil {
		bodyMarshal(w, response{"success": false, "message": err.Error()})
		return
	}

	bodyMarshal(w, response{"success": true, "confirmEmail": smtpConfigured})
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"log"
	"net/http"
	"parley/core"
	"time"
)

type Connection struct {
	username string
	socket   *websocket.Conn
}

var wsupgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}

var connections []Connection

func main() {
	port := parsePort()
	setUpRouter(port)
}

func parsePort() int {
	port := flag.Int("p", 3000, "server port 3000")
	flag.Parse()

	// check if port number is between 1 and 65535
	if *port <= 0 || *port > 1<<16-1 {
		log.Fatal(fmt.Sprintf("port %v number invalid", *port))
	}

	return *port
}

func setUpRouter(port int) {
	r := gin.Default()
	r.LoadHTMLFiles("index.html")

	r.GET("/", func(c *gin.Context) {
		c.HTML(200, "index.html", nil)
	})

	r.GET("/ws/:uname", func(c *gin.Context) {
		username := c.Param("uname")
		openws(c.Writer, c.Request, username)
	})

	r.Run(fmt.Sprintf("localhost:%v", port))
}

func openws(responseWriter http.ResponseWriter, request *http.Request, username string) {

	socket, err := wsupgrader.Upgrade(responseWriter, request, nil)
	connections = append(connections, Connection{username, socket})

	if err != nil {
		log.Print(err)
		return
	}

	for {
		t, inputBytes, err := socket.ReadMessage()
		if err != nil {
			log.Print(err)
			break
		}

		msg := core.Message{Username: username, Text: string(inputBytes), Time: time.Now()}
		jsonBytes := msg.BuildJson()

		for _, connection := range connections {
			connection.socket.WriteMessage(t, jsonBytes)
		}
	}
}
<commit_msg>fix imports<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"log"
	"net/http"
	"./core"
	"time"
)

type Connection struct {
	username string
	socket   *websocket.Conn
}

var wsupgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}

var connections []Connection

func main() {
	port := parsePort()
	setUpRouter(port)
}

func parsePort() int {
	port := flag.Int("p", 3000, "server port 3000")
	flag.Parse()

	// check if port number is between 1 and 65535
	if *port <= 0 || *port > 1<<16-1 {
		log.Fatal(fmt.Sprintf("port %v number invalid", *port))
	}

	return *port
}

func setUpRouter(port int) {
	r := gin.Default()
	r.LoadHTMLFiles("index.html")

	r.GET("/", func(c *gin.Context) {
		c.HTML(200, "index.html", nil)
	})

	r.GET("/ws/:uname", func(c *gin.Context) {
		username := c.Param("uname")
		openws(c.Writer, c.Request, username)
	})

	r.Run(fmt.Sprintf("localhost:%v", port))
}

func openws(responseWriter http.ResponseWriter, request *http.Request, username string) {

	socket, err := wsupgrader.Upgrade(responseWriter, request, nil)
	connections = append(connections, Connection{username, socket})

	if err != nil {
		log.Print(err)
		return
	}

	for {
		t, inputBytes, err := socket.ReadMessage()
		if err != nil {
			log.Print(err)
			break
		}

		msg := core.Message{Username: username, Text: string(inputBytes), Time: time.Now()}
		jsonBytes := msg.BuildJson()

		for _, connection := range connections {
			connection.socket.WriteMessage(t, jsonBytes)
		}
	}
}
<|endoftext|>


<commit_before>package api

import (
	"fmt"
	"time"

	"github.com/sclevine/agouti/api/internal/service"
)

type WebDriver struct {
	Timeout  time.Duration
	Debug    bool
	service  driverService
	sessions []*Session
}

type driverService interface {
	URL() string
	Start(debug bool) error
	Stop() error
	WaitForBoot(timeout time.Duration) error
}

func NewWebDriver(url string, command []string) *WebDriver {
	driverService := &service.Service{
		URLTemplate: url,
		CmdTemplate: command,
	}

	return &WebDriver{
		Timeout: 5 * time.Second,
		service: driverService,
	}
}

func (w *WebDriver) URL() string {
	return w.service.URL()
}

func (w *WebDriver) Open(desiredCapabilites map[string]interface{}) (*Session, error) {
	url := w.service.URL()
	if url == "" {
		return nil, fmt.Errorf("service not started")
	}

	session, err := Open(url, desiredCapabilites)
	if err != nil {
		return nil, err
	}

	w.sessions = append(w.sessions, session)
	return session, nil
}

func (w *WebDriver) Start() error {
	if err := w.service.Start(w.Debug); err != nil {
		return fmt.Errorf("failed to start service: %s", err)
	}

	if err := w.service.WaitForBoot(w.Timeout); err != nil {
		w.service.Stop()
		return err
	}

	return nil
}

func (w *WebDriver) Stop() error {
	for _, session := range w.sessions {
		session.Delete()
	}

	if err := w.service.Stop(); err != nil {
		return fmt.Errorf("failed to stop service: %s", err)
	}

	return nil
}
<commit_msg>Increase default timeout for all WebDrivers to 10 seconds<commit_after>package api

import (
	"fmt"
	"time"

	"github.com/sclevine/agouti/api/internal/service"
)

type WebDriver struct {
	Timeout  time.Duration
	Debug    bool
	service  driverService
	sessions []*Session
}

type driverService interface {
	URL() string
	Start(debug bool) error
	Stop() error
	WaitForBoot(timeout time.Duration) error
}

func NewWebDriver(url string, command []string) *WebDriver {
	driverService := &service.Service{
		URLTemplate: url,
		CmdTemplate: command,
	}

	return &WebDriver{
		Timeout: 10 * time.Second,
		service: driverService,
	}
}

func (w *WebDriver) URL() string {
	return w.service.URL()
}

func (w *WebDriver) Open(desiredCapabilites map[string]interface{}) (*Session, error) {
	url := w.service.URL()
	if url == "" {
		return nil, fmt.Errorf("service not started")
	}

	session, err := Open(url, desiredCapabilites)
	if err != nil {
		return nil, err
	}

	w.sessions = append(w.sessions, session)
	return session, nil
}

func (w *WebDriver) Start() error {
	if err := w.service.Start(w.Debug); err != nil {
		return fmt.Errorf("failed to start service: %s", err)
	}

	if err := w.service.WaitForBoot(w.Timeout); err != nil {
		w.service.Stop()
		return err
	}

	return nil
}

func (w *WebDriver) Stop() error {
	for _, session := range w.sessions {
		session.Delete()
	}

	if err := w.service.Stop(); err != nil {
		return fmt.Errorf("failed to stop service: %s", err)
	}

	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package config

import (
	"encoding/json"
	"errors"
	"fmt"
	"net"
	"net/url"

	lru "github.com/hashicorp/golang-lru"
	"k8s.io/api/admissionregistration/v1beta1"
	"k8s.io/apimachinery/pkg/runtime"
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
	webhookerrors "k8s.io/apiserver/pkg/admission/plugin/webhook/errors"
	"k8s.io/client-go/rest"
)

const (
	defaultCacheSize = 200
)

var (
	ErrNeedServiceOrURL = errors.New("webhook configuration must have either service or URL")
)

// ClientManager builds REST clients to talk to webhooks. It caches the clients
// to avoid duplicate creation.
type ClientManager struct {
	authInfoResolver     AuthenticationInfoResolver
	serviceResolver      ServiceResolver
	negotiatedSerializer runtime.NegotiatedSerializer
	cache                *lru.Cache
}

// NewClientManager creates a ClientManager.
func NewClientManager() (ClientManager, error) {
	cache, err := lru.New(defaultCacheSize)
	if err != nil {
		return ClientManager{}, err
	}
	return ClientManager{
		cache: cache,
	}, nil
}

// SetAuthenticationInfoResolverWrapper sets the
// AuthenticationInfoResolverWrapper.
func (cm *ClientManager) SetAuthenticationInfoResolverWrapper(wrapper AuthenticationInfoResolverWrapper) {
	if wrapper != nil {
		cm.authInfoResolver = wrapper(cm.authInfoResolver)
	}
}

// SetAuthenticationInfoResolver sets the AuthenticationInfoResolver.
func (cm *ClientManager) SetAuthenticationInfoResolver(resolver AuthenticationInfoResolver) {
	cm.authInfoResolver = resolver
}

// SetServiceResolver sets the ServiceResolver.
func (cm *ClientManager) SetServiceResolver(sr ServiceResolver) {
	if sr != nil {
		cm.serviceResolver = sr
	}
}

// SetNegotiatedSerializer sets the NegotiatedSerializer.
func (cm *ClientManager) SetNegotiatedSerializer(n runtime.NegotiatedSerializer) {
	cm.negotiatedSerializer = n
}

// Validate checks if ClientManager is properly set up.
func (cm *ClientManager) Validate() error {
	var errs []error
	if cm.negotiatedSerializer == nil {
		errs = append(errs, fmt.Errorf("the ClientManager requires a negotiatedSerializer"))
	}
	if cm.serviceResolver == nil {
		errs = append(errs, fmt.Errorf("the ClientManager requires a serviceResolver"))
	}
	if cm.authInfoResolver == nil {
		errs = append(errs, fmt.Errorf("the ClientManager requires an authInfoResolver"))
	}
	return utilerrors.NewAggregate(errs)
}

// HookClient get a RESTClient from the cache, or constructs one based on the
// webhook configuration.
func (cm *ClientManager) HookClient(h *v1beta1.Webhook) (*rest.RESTClient, error) {
	cacheKey, err := json.Marshal(h.ClientConfig)
	if err != nil {
		return nil, err
	}
	if client, ok := cm.cache.Get(string(cacheKey)); ok {
		return client.(*rest.RESTClient), nil
	}

	complete := func(cfg *rest.Config) (*rest.RESTClient, error) {
		cfg.TLSClientConfig.CAData = h.ClientConfig.CABundle
		cfg.ContentConfig.NegotiatedSerializer = cm.negotiatedSerializer
		cfg.ContentConfig.ContentType = runtime.ContentTypeJSON
		client, err := rest.UnversionedRESTClientFor(cfg)
		if err == nil {
			cm.cache.Add(string(cacheKey), client)
		}
		return client, err
	}

	if svc := h.ClientConfig.Service; svc != nil {
		restConfig, err := cm.authInfoResolver.ClientConfigForService(svc.Name, svc.Namespace)
		if err != nil {
			return nil, err
		}
		cfg := rest.CopyConfig(restConfig)
		serverName := svc.Name + "." + svc.Namespace + ".svc"
		host := serverName + ":443"
		cfg.Host = "https://" + host
		if svc.Path != nil {
			cfg.APIPath = *svc.Path
		}
		cfg.TLSClientConfig.ServerName = serverName

		delegateDialer := cfg.Dial
		if delegateDialer == nil {
			delegateDialer = net.Dial
		}
		cfg.Dial = func(network, addr string) (net.Conn, error) {
			if addr == host {
				u, err := cm.serviceResolver.ResolveEndpoint(svc.Namespace, svc.Name)
				if err != nil {
					return nil, err
				}
				addr = u.Host
			}
			return delegateDialer(network, addr)
		}

		return complete(cfg)
	}

	if h.ClientConfig.URL == nil {
		return nil, &webhookerrors.ErrCallingWebhook{WebhookName: h.Name, Reason: ErrNeedServiceOrURL}
	}

	u, err := url.Parse(*h.ClientConfig.URL)
	if err != nil {
		return nil, &webhookerrors.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("Unparsable URL: %v", err)}
	}

	restConfig, err := cm.authInfoResolver.ClientConfigFor(u.Host)
	if err != nil {
		return nil, err
	}

	cfg := rest.CopyConfig(restConfig)
	cfg.Host = u.Host
	cfg.APIPath = u.Path

	return complete(cfg)
}
<commit_msg>Make admission webhooks not ignore scheme<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package config

import (
	"encoding/json"
	"errors"
	"fmt"
	"net"
	"net/url"

	lru "github.com/hashicorp/golang-lru"
	"k8s.io/api/admissionregistration/v1beta1"
	"k8s.io/apimachinery/pkg/runtime"
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
	webhookerrors "k8s.io/apiserver/pkg/admission/plugin/webhook/errors"
	"k8s.io/client-go/rest"
)

const (
	defaultCacheSize = 200
)

var (
	ErrNeedServiceOrURL = errors.New("webhook configuration must have either service or URL")
)

// ClientManager builds REST clients to talk to webhooks. It caches the clients
// to avoid duplicate creation.
type ClientManager struct {
	authInfoResolver     AuthenticationInfoResolver
	serviceResolver      ServiceResolver
	negotiatedSerializer runtime.NegotiatedSerializer
	cache                *lru.Cache
}

// NewClientManager creates a ClientManager.
func NewClientManager() (ClientManager, error) {
	cache, err := lru.New(defaultCacheSize)
	if err != nil {
		return ClientManager{}, err
	}
	return ClientManager{
		cache: cache,
	}, nil
}

// SetAuthenticationInfoResolverWrapper sets the
// AuthenticationInfoResolverWrapper.
func (cm *ClientManager) SetAuthenticationInfoResolverWrapper(wrapper AuthenticationInfoResolverWrapper) {
	if wrapper != nil {
		cm.authInfoResolver = wrapper(cm.authInfoResolver)
	}
}

// SetAuthenticationInfoResolver sets the AuthenticationInfoResolver.
func (cm *ClientManager) SetAuthenticationInfoResolver(resolver AuthenticationInfoResolver) {
	cm.authInfoResolver = resolver
}

// SetServiceResolver sets the ServiceResolver.
func (cm *ClientManager) SetServiceResolver(sr ServiceResolver) {
	if sr != nil {
		cm.serviceResolver = sr
	}
}

// SetNegotiatedSerializer sets the NegotiatedSerializer.
func (cm *ClientManager) SetNegotiatedSerializer(n runtime.NegotiatedSerializer) {
	cm.negotiatedSerializer = n
}

// Validate checks if ClientManager is properly set up.
func (cm *ClientManager) Validate() error {
	var errs []error
	if cm.negotiatedSerializer == nil {
		errs = append(errs, fmt.Errorf("the ClientManager requires a negotiatedSerializer"))
	}
	if cm.serviceResolver == nil {
		errs = append(errs, fmt.Errorf("the ClientManager requires a serviceResolver"))
	}
	if cm.authInfoResolver == nil {
		errs = append(errs, fmt.Errorf("the ClientManager requires an authInfoResolver"))
	}
	return utilerrors.NewAggregate(errs)
}

// HookClient get a RESTClient from the cache, or constructs one based on the
// webhook configuration.
func (cm *ClientManager) HookClient(h *v1beta1.Webhook) (*rest.RESTClient, error) {
	cacheKey, err := json.Marshal(h.ClientConfig)
	if err != nil {
		return nil, err
	}
	if client, ok := cm.cache.Get(string(cacheKey)); ok {
		return client.(*rest.RESTClient), nil
	}

	complete := func(cfg *rest.Config) (*rest.RESTClient, error) {
		cfg.TLSClientConfig.CAData = h.ClientConfig.CABundle
		cfg.ContentConfig.NegotiatedSerializer = cm.negotiatedSerializer
		cfg.ContentConfig.ContentType = runtime.ContentTypeJSON
		client, err := rest.UnversionedRESTClientFor(cfg)
		if err == nil {
			cm.cache.Add(string(cacheKey), client)
		}
		return client, err
	}

	if svc := h.ClientConfig.Service; svc != nil {
		restConfig, err := cm.authInfoResolver.ClientConfigForService(svc.Name, svc.Namespace)
		if err != nil {
			return nil, err
		}
		cfg := rest.CopyConfig(restConfig)
		serverName := svc.Name + "." + svc.Namespace + ".svc"
		host := serverName + ":443"
		cfg.Host = "https://" + host
		if svc.Path != nil {
			cfg.APIPath = *svc.Path
		}
		cfg.TLSClientConfig.ServerName = serverName

		delegateDialer := cfg.Dial
		if delegateDialer == nil {
			delegateDialer = net.Dial
		}
		cfg.Dial = func(network, addr string) (net.Conn, error) {
			if addr == host {
				u, err := cm.serviceResolver.ResolveEndpoint(svc.Namespace, svc.Name)
				if err != nil {
					return nil, err
				}
				addr = u.Host
			}
			return delegateDialer(network, addr)
		}

		return complete(cfg)
	}

	if h.ClientConfig.URL == nil {
		return nil, &webhookerrors.ErrCallingWebhook{WebhookName: h.Name, Reason: ErrNeedServiceOrURL}
	}

	u, err := url.Parse(*h.ClientConfig.URL)
	if err != nil {
		return nil, &webhookerrors.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("Unparsable URL: %v", err)}
	}

	restConfig, err := cm.authInfoResolver.ClientConfigFor(u.Host)
	if err != nil {
		return nil, err
	}

	cfg := rest.CopyConfig(restConfig)
	cfg.Host = u.Scheme + "://" + u.Host
	cfg.APIPath = u.Path

	return complete(cfg)
}
<|endoftext|>


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

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/aclements/go-misc/internal/loganal"
)

// TODO: If searching dashboard logs, optionally print to builder URLs
// instead of local file names.

// TODO: Optionally extract failures and show only those.

// TODO: Optionally classify matched logs by failure (and show either
// file name or extracted failure).

// TODO: Option to print failure summary versus full failure message.

var (
	fileRegexps regexpList
	failRegexps regexpList

	flagDashboard = flag.Bool("dashboard", false, "search dashboard logs from fetchlogs")
	flagMD        = flag.Bool("md", false, "output in Markdown")
	flagFilesOnly = flag.Bool("l", false, "print only names of matching files")
)

func main() {
	// XXX What I want right now is just to point it at a bunch of
	// logs and have it extract the failures.
	flag.Var(&fileRegexps, "e", "show files matching `regexp`; if provided multiple times, files must match all regexps")
	flag.Var(&failRegexps, "E", "show only errors matching `regexp`; if provided multiple times, an error must match all regexps")
	flag.Parse()

	// Validate flags.
	if *flagDashboard && flag.NArg() > 0 {
		fmt.Fprintf(os.Stderr, "-dashboard and paths are incompatible\n")
		os.Exit(2)
	}

	// Gather paths.
	var paths []string
	var stripDir string
	if *flagDashboard {
		revDir := filepath.Join(xdgCacheDir(), "fetchlogs", "rev")
		paths = []string{revDir}
		stripDir = revDir + "/"
	} else {
		paths = flag.Args()
	}

	// Process files
	status := 1
	for _, path := range paths {
		filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
			if err != nil {
				status = 2
				fmt.Fprintf(os.Stderr, "%s: %v\n", path, err)
				return nil
			}
			if info.IsDir() || strings.HasPrefix(filepath.Base(path), ".") {
				return nil
			}

			nicePath := path
			if stripDir != "" && strings.HasPrefix(path, stripDir) {
				nicePath = path[len(stripDir):]
			}

			found, err := process(path, nicePath)
			if err != nil {
				status = 2
				fmt.Fprintf(os.Stderr, "%s: %v\n", path, err)
			} else if found && status == 1 {
				status = 0
			}
			return nil
		})
	}
	os.Exit(status)
}

func process(path, nicePath string) (found bool, err error) {
	// TODO: Use streaming if possible.
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return false, err
	}

	// Check regexp match.
	if !fileRegexps.AllMatch(data) || !failRegexps.AllMatch(data) {
		return false, nil
	}

	// If this is from the dashboard, get the builder URL.
	var logURL string
	if _, err := os.Stat(filepath.Join(filepath.Dir(path), ".rev.json")); err == nil {
		// TODO: Get the URL from the rev.json metadata
		link, err := os.Readlink(path)
		if err == nil {
			hash := filepath.Base(link)
			logURL = "https://build.golang.org/log/" + hash
		}
	}

	printPath := nicePath
	if *flagMD && logURL != "" {
		printPath = fmt.Sprintf("[%s](%s)", nicePath, logURL)
	}

	if *flagFilesOnly {
		fmt.Printf("%s\n", printPath)
		return true, nil
	}

	// Extract failures.
	failures, err := loganal.Extract(string(data), "", "")
	if err != nil {
		return false, err
	}

	// Print failures.
	for _, failure := range failures {
		msg := failure.FullMessage
		if msg == "" {
			msg = failure.Message
		}

		if len(failRegexps) > 0 && !failRegexps.AllMatch([]byte(msg)) {
			continue
		}

		fmt.Printf("%s:\n", printPath)
		if *flagMD {
			fmt.Printf("```\n%s\n```\n\n", msg)
		} else {
			fmt.Printf("%s\n\n", msg)
		}
	}
	return true, nil
}
<commit_msg>greplogs: command docs<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Command greplogs searches Go builder logs.
//
//     greplogs [flags] (-e regexp|-E regexp) paths...
//     greplogs [flags] (-e regexp|-E regexp) -dashboard
//
// greplogs finds builder logs matching a given set of regular
// expressions in Go syntax (godoc.org/regexp/syntax) and extracts
// failures from them.
//
// greplogs can search an arbitrary set of files just like grep.
// Alternatively, the -dashboard flag causes it to search the logs
// saved locally by fetchlogs (golang.org/x/build/cmd/fetchlogs).
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/aclements/go-misc/internal/loganal"
)

// TODO: If searching dashboard logs, optionally print to builder URLs
// instead of local file names.

// TODO: Optionally extract failures and show only those.

// TODO: Optionally classify matched logs by failure (and show either
// file name or extracted failure).

// TODO: Option to print failure summary versus full failure message.

var (
	fileRegexps regexpList
	failRegexps regexpList

	flagDashboard = flag.Bool("dashboard", false, "search dashboard logs from fetchlogs")
	flagMD        = flag.Bool("md", false, "output in Markdown")
	flagFilesOnly = flag.Bool("l", false, "print only names of matching files")
)

func main() {
	// XXX What I want right now is just to point it at a bunch of
	// logs and have it extract the failures.
	flag.Var(&fileRegexps, "e", "show files matching `regexp`; if provided multiple times, files must match all regexps")
	flag.Var(&failRegexps, "E", "show only errors matching `regexp`; if provided multiple times, an error must match all regexps")
	flag.Parse()

	// Validate flags.
	if *flagDashboard && flag.NArg() > 0 {
		fmt.Fprintf(os.Stderr, "-dashboard and paths are incompatible\n")
		os.Exit(2)
	}

	// Gather paths.
	var paths []string
	var stripDir string
	if *flagDashboard {
		revDir := filepath.Join(xdgCacheDir(), "fetchlogs", "rev")
		paths = []string{revDir}
		stripDir = revDir + "/"
	} else {
		paths = flag.Args()
	}

	// Process files
	status := 1
	for _, path := range paths {
		filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
			if err != nil {
				status = 2
				fmt.Fprintf(os.Stderr, "%s: %v\n", path, err)
				return nil
			}
			if info.IsDir() || strings.HasPrefix(filepath.Base(path), ".") {
				return nil
			}

			nicePath := path
			if stripDir != "" && strings.HasPrefix(path, stripDir) {
				nicePath = path[len(stripDir):]
			}

			found, err := process(path, nicePath)
			if err != nil {
				status = 2
				fmt.Fprintf(os.Stderr, "%s: %v\n", path, err)
			} else if found && status == 1 {
				status = 0
			}
			return nil
		})
	}
	os.Exit(status)
}

func process(path, nicePath string) (found bool, err error) {
	// TODO: Use streaming if possible.
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return false, err
	}

	// Check regexp match.
	if !fileRegexps.AllMatch(data) || !failRegexps.AllMatch(data) {
		return false, nil
	}

	// If this is from the dashboard, get the builder URL.
	var logURL string
	if _, err := os.Stat(filepath.Join(filepath.Dir(path), ".rev.json")); err == nil {
		// TODO: Get the URL from the rev.json metadata
		link, err := os.Readlink(path)
		if err == nil {
			hash := filepath.Base(link)
			logURL = "https://build.golang.org/log/" + hash
		}
	}

	printPath := nicePath
	if *flagMD && logURL != "" {
		printPath = fmt.Sprintf("[%s](%s)", nicePath, logURL)
	}

	if *flagFilesOnly {
		fmt.Printf("%s\n", printPath)
		return true, nil
	}

	// Extract failures.
	failures, err := loganal.Extract(string(data), "", "")
	if err != nil {
		return false, err
	}

	// Print failures.
	for _, failure := range failures {
		msg := failure.FullMessage
		if msg == "" {
			msg = failure.Message
		}

		if len(failRegexps) > 0 && !failRegexps.AllMatch([]byte(msg)) {
			continue
		}

		fmt.Printf("%s:\n", printPath)
		if *flagMD {
			fmt.Printf("```\n%s\n```\n\n", msg)
		} else {
			fmt.Printf("%s\n\n", msg)
		}
	}
	return true, nil
}
<|endoftext|>


<commit_before>package app

import (
	"fmt"
	"runtime"
	"time"
)

func watchdog(who interface{}) chan chan bool {
	reqs := make(chan chan bool, 1)
	pc := make([]uintptr, 11)
	runtime.Callers(2, pc)
	f := runtime.FuncForPC(pc[0])
	file, line := f.FileLine(pc[0])

	m := func() {
		for {
			<-time.After(10 * time.Second)
			reply := make(chan bool)
			select {
			case reqs <- reply:
			// pass
			default:
				panic(fmt.Sprintf("Failed to send watchdog message from %s:%d, %v", file, line, who))
			}
			select {
			case <-reply:
			// pass
			case <-time.After(1 * time.Second):
				panic(fmt.Sprintf("Failed to receive reply from %s:%d, %v", file, line, who))
			}
		}
	}

	go m()
	return reqs
}
<commit_msg>watchdog: 10 seconds timeout, plus debugging<commit_after>package app

import (
	"bytes"
	"log"
	"runtime"
	"strconv"
	"time"
)

func watchdog(who interface{}) chan chan bool {
	reqs := make(chan chan bool, 1)
	pc := make([]uintptr, 11)
	runtime.Callers(2, pc)
	f := runtime.FuncForPC(pc[0])
	file, line := f.FileLine(pc[0])

	goid := getGID()

	m := func() {
		for {
			<-time.After(10 * time.Second)
			reply := make(chan bool)
			select {
			case reqs <- reply:
			// pass
			default:
				log.Panicf("Failed to send watchdog message to goroutine %d, %s:%d, %v", goid, file, line, who)
			}
			select {
			case <-reply:
			// pass
			case <-time.After(10 * time.Second):
				log.Panicf("Failed to receive reply from goroutine %d, %s:%d, %v", goid, file, line, who)
			}
		}
	}

	go m()
	return reqs
}

// Hacky way of getting a goroutine ID.
func getGID() uint64 {
	b := make([]byte, 64)
	return extractGID(b[:runtime.Stack(b, false)])
}

func extractGID(stack []byte) uint64 {
	b := bytes.TrimPrefix(stack, []byte("goroutine "))
	b = b[:bytes.IndexByte(b, ' ')]
	gid, _ := strconv.ParseUint(string(b), 10, 64)
	return gid
}
<|endoftext|>


<commit_before>package judge

import (
	"net"
	"strings"
)

var cfRanges []*net.IPNet

// load cloudflare network ranges
func loadCfRanges() {
	//todo : add dynamic loading from https://www.cloudflare.com/ips-v4
	body := `
103.21.244.0/22
103.22.200.0/22
103.31.4.0/22
104.16.0.0/12
108.162.192.0/18
131.0.72.0/22
141.101.64.0/18
162.158.0.0/15
172.64.0.0/13
173.245.48.0/20
188.114.96.0/20
190.93.240.0/20
197.234.240.0/22
198.41.128.0/17
2400:cb00::/32
2405:8100::/32
2405:b500::/32
2606:4700::/32
2803:f800::/32
2c0f:f248::/32
2a06:98c0::/29`

	ipRanges := strings.Split(body, "\n")
	for _, cidr := range ipRanges {
		_, ipNet, err := net.ParseCIDR(cidr)
		//skip on error
		if err != nil {
			continue
		}
		cfRanges = append(cfRanges, ipNet)
	}
}

// Checks if ip belongs to a cloudflare network.
func ipBelongsToCfNetwork(ip net.IP) bool {
	for _, cidr := range cfRanges {
		belongs := cidr.Contains(ip)
		if belongs {
			return true
		}
	}
	return false
}
<commit_msg>updated cf ips.<commit_after>package judge

import (
	"net"
	"strings"
)

var cfRanges []*net.IPNet

// load cloudflare network ranges
func loadCfRanges() {
	//todo : add dynamic loading from https://www.cloudflare.com/ips-v4
	body := `
173.245.48.0/20
103.21.244.0/22
103.22.200.0/22
103.31.4.0/22
141.101.64.0/18
108.162.192.0/18
190.93.240.0/20
188.114.96.0/20
197.234.240.0/22
198.41.128.0/17
162.158.0.0/15
104.16.0.0/12
172.64.0.0/13
131.0.72.0/22
2400:cb00::/32
2606:4700::/32
2803:f800::/32
2405:b500::/32
2405:8100::/32
2a06:98c0::/29
2c0f:f248::/32`

	ipRanges := strings.Split(body, "\n")
	for _, cidr := range ipRanges {
		_, ipNet, err := net.ParseCIDR(cidr)
		//skip on error
		if err != nil {
			continue
		}
		cfRanges = append(cfRanges, ipNet)
	}
}

// Checks if ip belongs to a cloudflare network.
func ipBelongsToCfNetwork(ip net.IP) bool {
	for _, cidr := range cfRanges {
		belongs := cidr.Contains(ip)
		if belongs {
			return true
		}
	}
	return false
}
<|endoftext|>