<commit_before>package main

import (
	"fmt"
	"golang.org/x/crypto/ssh"
	"io"
	"time"
)

type Hub struct {
	Sessions   map[*Session]struct{}
	Redraw     chan struct{}
	Register   chan *Session
	Unregister chan *Session
}

func NewHub() Hub {
	return Hub{
		Sessions:   make(map[*Session]struct{}),
		Redraw:     make(chan struct{}),
		Register:   make(chan *Session),
		Unregister: make(chan *Session),
	}
}

func (h *Hub) Run(g *Game) {
	for {
		select {
		case <-h.Redraw:
			for s := range h.Sessions {
				g.Render(s)
			}
		case s := <-h.Register:
			h.Sessions[s] = struct{}{}
		case s := <-h.Unregister:
			if _, ok := h.Sessions[s]; ok {
				fmt.Fprint(s, "End of line.\r\n\r\n")
				delete(h.Sessions, s)
				s.c.Close()
			}
		}
	}
}

type Position struct {
	X float64
	Y float64
}

func (p Position) RoundX() int {
	return int(p.X + 0.5)
}

func (p Position) RoundY() int {
	return int(p.Y + 0.5)
}

type PlayerDirection int

const (
	verticalPlayerSpeed   = 0.007
	horizontalPlayerSpeed = 0.01

	playerUpRune    = '⇧'
	playerLeftRune  = '⇦'
	playerDownRune  = '⇩'
	playerRightRune = '⇨'

	PlayerUp PlayerDirection = iota
	PlayerLeft
	PlayerDown
	PlayerRight
)

type Player struct {
	Direction PlayerDirection
	Marker    rune
	Pos       *Position
}

func NewPlayer() *Player {
	return &Player{
		Marker:    playerDownRune,
		Direction: PlayerDown,
		Pos:       &Position{0, 0},
	}
}

func (p *Player) HandleUp() {
	p.Direction = PlayerUp
	p.Marker = playerUpRune
}

func (p *Player) HandleLeft() {
	p.Direction = PlayerLeft
	p.Marker = playerLeftRune
}

func (p *Player) HandleDown() {
	p.Direction = PlayerDown
	p.Marker = playerDownRune
}

func (p *Player) HandleRight() {
	p.Direction = PlayerRight
	p.Marker = playerRightRune
}

func (p *Player) Update(delta float64) {
	switch p.Direction {
	case PlayerUp:
		p.Pos.Y -= verticalPlayerSpeed * delta
	case PlayerLeft:
		p.Pos.X -= horizontalPlayerSpeed * delta
	case PlayerDown:
		p.Pos.Y += verticalPlayerSpeed * delta
	case PlayerRight:
		p.Pos.X += horizontalPlayerSpeed * delta
	}
}

type TileType int

const (
	TileGrass TileType = iota
	TileBlocker
)

type Tile struct {
	Type TileType
}

type Game struct {
	hub Hub

	Redraw chan struct{}

	// Top left is 0,0
	level [][]Tile
}

func NewGame(worldWidth, worldHeight int) *Game {
	g := &Game{
		hub:    NewHub(),
		Redraw: make(chan struct{}),
	}
	g.initalizeLevel(worldWidth, worldHeight)

	return g
}

func (g *Game) initalizeLevel(width, height int) {
	g.level = make([][]Tile, width)
	for x := range g.level {
		g.level[x] = make([]Tile, height)
	}

	// Default world to grass
	for x := range g.level {
		for y := range g.level[x] {
			g.setTileType(Position{float64(x), float64(y)}, TileGrass)
		}
	}
}

func (g *Game) setTileType(pos Position, tileType TileType) error {
	outOfBoundsErr := "The given %s value (%s) is out of bounds"
	if pos.RoundX() > len(g.level) || pos.RoundX() < 0 {
		return fmt.Errorf(outOfBoundsErr, "X", pos.X)
	} else if pos.RoundY() > len(g.level[pos.RoundX()]) || pos.RoundY() < 0 {
		return fmt.Errorf(outOfBoundsErr, "Y", pos.Y)
	}

	g.level[pos.RoundX()][pos.RoundY()].Type = tileType

	return nil
}

func (g *Game) players() map[*Player]*Session {
	players := make(map[*Player]*Session)

	for session := range g.hub.Sessions {
		players[session.Player] = session
	}

	return players
}

// Characters for rendering
const (
	verticalWall   = '┆'
	horizontalWall = '┄'
	topLeft        = '╭'
	topRight       = '╮'
	bottomRight    = '╯'
	bottomLeft     = '╰'

	grass   = ' '
	blocker = '■'
)

// Warning: this will only work with square worlds
func (g *Game) worldString() string {
	str := ""
	worldWidth := len(g.level)
	worldHeight := len(g.level[0])

	// Create two dimensional slice of runes to represent the world. It's two
	// characters larger in each direction to accomodate for walls.
	strWorld := make([][]rune, worldWidth+3)
	for x := range strWorld {
		strWorld[x] = make([]rune, worldHeight+3)
	}

	// Load the walls into the rune slice
	for x := 0; x < worldWidth+2; x++ {
		strWorld[x][0] = horizontalWall
		strWorld[x][worldHeight+1] = horizontalWall
	}
	for y := 0; y < worldHeight+2; y++ {
		strWorld[0][y] = verticalWall
		strWorld[worldWidth+1][y] = verticalWall
	}

	// Time for the edges!
	strWorld[0][0] = topLeft
	strWorld[worldWidth+1][0] = topRight
	strWorld[worldWidth+1][worldHeight+1] = bottomRight
	strWorld[0][worldHeight+1] = bottomLeft

	// Load the level into the rune slice
	for x := 0; x < worldWidth; x++ {
		for y := 0; y < worldHeight; y++ {
			tile := g.level[x][y]

			switch tile.Type {
			case TileGrass:
				strWorld[x+1][y+1] = grass
			case TileBlocker:
				strWorld[x+1][y+1] = blocker
			}
		}
	}

	// Load the players into the rune slice
	for player := range g.players() {
		pos := player.Pos
		strWorld[pos.RoundX()+1][pos.RoundY()+1] = player.Marker
	}

	// Convert the rune slice to a string
	for y := 0; y < len(strWorld[0]); y++ {
		for x := 0; x < len(strWorld); x++ {
			str += string(strWorld[x][y])
		}

		str += "\r\n"
	}

	return str
}

func (g *Game) Run() {
	// Proxy g.Redraw's channel to g.hub.Redraw
	go func() {
		for {
			g.hub.Redraw <- <-g.Redraw
		}
	}()

	// Run game loop
	go func() {
		var lastUpdate time.Time

		c := time.Tick(time.Second / 60)
		for now := range c {
			g.Update(float64(now.Sub(lastUpdate)) / float64(time.Millisecond))

			lastUpdate = now
		}
	}()

	// Redraw regularly.
	//
	// TODO: Implement diffing and only redraw when needed
	go func() {
		c := time.Tick(time.Second / 10)
		for range c {
			g.Redraw <- struct{}{}
		}
	}()

	g.hub.Run(g)
}

// Update is the main game logic loop. Delta is the time since the last update
// in milliseconds.
func (g *Game) Update(delta float64) {
	for player, session := range g.players() {
		player.Update(delta)

		// Kick player if they're out of bounds
		pos := player.Pos
		if pos.RoundX() < 0 || pos.RoundX() > len(g.level) ||
			pos.RoundY() < 0 || pos.RoundY() > len(g.level[0]) {
			g.hub.Unregister <- session
		}
	}
}

func (g *Game) Render(w io.Writer) {
	worldStr := g.worldString()

	fmt.Fprintln(w)
	fmt.Fprint(w, worldStr)
}

func (g *Game) AddSession(s *Session) {
	g.hub.Register <- s
}

type Session struct {
	c ssh.Channel

	Player *Player
}

func NewSession(c ssh.Channel) *Session {
	s := Session{c: c}
	s.Player = NewPlayer()

	return &s
}

func (s *Session) Read(p []byte) (int, error) {
	return s.c.Read(p)
}

func (s *Session) Write(p []byte) (int, error) {
	return s.c.Write(p)
}
<commit_msg>Add bike trails<commit_after>package main

import (
	"fmt"
	"golang.org/x/crypto/ssh"
	"io"
	"time"
)

type Hub struct {
	Sessions   map[*Session]struct{}
	Redraw     chan struct{}
	Register   chan *Session
	Unregister chan *Session
}

func NewHub() Hub {
	return Hub{
		Sessions:   make(map[*Session]struct{}),
		Redraw:     make(chan struct{}),
		Register:   make(chan *Session),
		Unregister: make(chan *Session),
	}
}

func (h *Hub) Run(g *Game) {
	for {
		select {
		case <-h.Redraw:
			for s := range h.Sessions {
				g.Render(s)
			}
		case s := <-h.Register:
			h.Sessions[s] = struct{}{}
		case s := <-h.Unregister:
			if _, ok := h.Sessions[s]; ok {
				fmt.Fprint(s, "End of line.\r\n\r\n")
				delete(h.Sessions, s)
				s.c.Close()
			}
		}
	}
}

type Position struct {
	X float64
	Y float64
}

func PositionFromInt(x, y int) Position {
	return Position{float64(x), float64(y)}
}

func (p Position) RoundX() int {
	return int(p.X + 0.5)
}

func (p Position) RoundY() int {
	return int(p.Y + 0.5)
}

type PlayerDirection int

const (
	verticalPlayerSpeed   = 0.007
	horizontalPlayerSpeed = 0.01

	playerUpRune    = '⇧'
	playerLeftRune  = '⇦'
	playerDownRune  = '⇩'
	playerRightRune = '⇨'

	playerTrailHorizontal      = '═'
	playerTrailVertical        = '║'
	playerTrailLeftCornerUp    = '╔'
	playerTrailLeftCornerDown  = '╚'
	playerTrailRightCornerDown = '╝'
	playerTrailRightCornerUp   = '╗'

	PlayerUp PlayerDirection = iota
	PlayerLeft
	PlayerDown
	PlayerRight
)

type PlayerTrailSegment struct {
	Marker rune
	Pos    Position
}

type Player struct {
	Direction PlayerDirection
	Marker    rune
	Pos       *Position

	Trail []PlayerTrailSegment
}

func NewPlayer() *Player {
	return &Player{
		Marker:    playerDownRune,
		Direction: PlayerDown,
		Pos:       &Position{0, 0},
	}
}

func (p *Player) addTrailSegment(pos Position, marker rune) {
	segment := PlayerTrailSegment{marker, pos}
	p.Trail = append([]PlayerTrailSegment{segment}, p.Trail...)
}

func (p *Player) HandleUp() {
	p.Direction = PlayerUp
	p.Marker = playerUpRune
}

func (p *Player) HandleLeft() {
	p.Direction = PlayerLeft
	p.Marker = playerLeftRune
}

func (p *Player) HandleDown() {
	p.Direction = PlayerDown
	p.Marker = playerDownRune
}

func (p *Player) HandleRight() {
	p.Direction = PlayerRight
	p.Marker = playerRightRune
}

func (p *Player) Update(delta float64) {
	startX, startY := p.Pos.RoundX(), p.Pos.RoundY()

	switch p.Direction {
	case PlayerUp:
		p.Pos.Y -= verticalPlayerSpeed * delta
	case PlayerLeft:
		p.Pos.X -= horizontalPlayerSpeed * delta
	case PlayerDown:
		p.Pos.Y += verticalPlayerSpeed * delta
	case PlayerRight:
		p.Pos.X += horizontalPlayerSpeed * delta
	}

	endX, endY := p.Pos.RoundX(), p.Pos.RoundY()

	// If we moved, add a trail segment.
	if endX != startX || endY != startY {
		var lastSeg *PlayerTrailSegment
		var lastSegX, lastSegY int
		if len(p.Trail) > 0 {
			lastSeg = &p.Trail[0]
			lastSegX = lastSeg.Pos.RoundX()
			lastSegY = lastSeg.Pos.RoundY()
		}

		pos := PositionFromInt(startX, startY)

		switch {
		// Handle corners. This took an ungodly amount of time to figure. Highly
		// recommend you don't touch.
		case lastSeg != nil &&
			(p.Direction == PlayerRight && endX > lastSegX && endY < lastSegY) ||
			(p.Direction == PlayerDown && endX < lastSegX && endY > lastSegY):
			p.addTrailSegment(pos, playerTrailLeftCornerUp)
		case lastSeg != nil &&
			(p.Direction == PlayerUp && endX > lastSegX && endY < lastSegY) ||
			(p.Direction == PlayerLeft && endX < lastSegX && endY > lastSegY):
			p.addTrailSegment(pos, playerTrailRightCornerDown)
		case lastSeg != nil &&
			(p.Direction == PlayerDown && endX > lastSegX && endY > lastSegY) ||
			(p.Direction == PlayerLeft && endX < lastSegX && endY < lastSegY):
			p.addTrailSegment(pos, playerTrailRightCornerUp)
		case lastSeg != nil &&
			(p.Direction == PlayerRight && endX > lastSegX && endY > lastSegY) ||
			(p.Direction == PlayerUp && endX < lastSegX && endY < lastSegY):
			p.addTrailSegment(pos, playerTrailLeftCornerDown)

		// Vertical and horizontal trails
		case endX == startX && endY < startY:
			p.addTrailSegment(pos, playerTrailVertical)
		case endX < startX && endY == startY:
			p.addTrailSegment(pos, playerTrailHorizontal)
		case endX == startX && endY > startY:
			p.addTrailSegment(pos, playerTrailVertical)
		case endX > startX && endY == startY:
			p.addTrailSegment(pos, playerTrailHorizontal)
		}
	}
}

type TileType int

const (
	TileGrass TileType = iota
	TileBlocker
)

type Tile struct {
	Type TileType
}

type Game struct {
	hub Hub

	Redraw chan struct{}

	// Top left is 0,0
	level [][]Tile
}

func NewGame(worldWidth, worldHeight int) *Game {
	g := &Game{
		hub:    NewHub(),
		Redraw: make(chan struct{}),
	}
	g.initalizeLevel(worldWidth, worldHeight)

	return g
}

func (g *Game) initalizeLevel(width, height int) {
	g.level = make([][]Tile, width)
	for x := range g.level {
		g.level[x] = make([]Tile, height)
	}

	// Default world to grass
	for x := range g.level {
		for y := range g.level[x] {
			g.setTileType(Position{float64(x), float64(y)}, TileGrass)
		}
	}
}

func (g *Game) setTileType(pos Position, tileType TileType) error {
	outOfBoundsErr := "The given %s value (%s) is out of bounds"
	if pos.RoundX() > len(g.level) || pos.RoundX() < 0 {
		return fmt.Errorf(outOfBoundsErr, "X", pos.X)
	} else if pos.RoundY() > len(g.level[pos.RoundX()]) || pos.RoundY() < 0 {
		return fmt.Errorf(outOfBoundsErr, "Y", pos.Y)
	}

	g.level[pos.RoundX()][pos.RoundY()].Type = tileType

	return nil
}

func (g *Game) players() map[*Player]*Session {
	players := make(map[*Player]*Session)

	for session := range g.hub.Sessions {
		players[session.Player] = session
	}

	return players
}

// Characters for rendering
const (
	verticalWall   = '┆'
	horizontalWall = '┄'
	topLeft        = '╭'
	topRight       = '╮'
	bottomRight    = '╯'
	bottomLeft     = '╰'

	grass   = ' '
	blocker = '■'
)

// Warning: this will only work with square worlds
func (g *Game) worldString() string {
	str := ""
	worldWidth := len(g.level)
	worldHeight := len(g.level[0])

	// Create two dimensional slice of runes to represent the world. It's two
	// characters larger in each direction to accomodate for walls.
	strWorld := make([][]rune, worldWidth+3)
	for x := range strWorld {
		strWorld[x] = make([]rune, worldHeight+3)
	}

	// Load the walls into the rune slice
	for x := 0; x < worldWidth+2; x++ {
		strWorld[x][0] = horizontalWall
		strWorld[x][worldHeight+1] = horizontalWall
	}
	for y := 0; y < worldHeight+2; y++ {
		strWorld[0][y] = verticalWall
		strWorld[worldWidth+1][y] = verticalWall
	}

	// Time for the edges!
	strWorld[0][0] = topLeft
	strWorld[worldWidth+1][0] = topRight
	strWorld[worldWidth+1][worldHeight+1] = bottomRight
	strWorld[0][worldHeight+1] = bottomLeft

	// Load the level into the rune slice
	for x := 0; x < worldWidth; x++ {
		for y := 0; y < worldHeight; y++ {
			tile := g.level[x][y]

			switch tile.Type {
			case TileGrass:
				strWorld[x+1][y+1] = grass
			case TileBlocker:
				strWorld[x+1][y+1] = blocker
			}
		}
	}

	// Load the players into the rune slice
	for player := range g.players() {
		pos := player.Pos
		strWorld[pos.RoundX()+1][pos.RoundY()+1] = player.Marker

		// Load the player's trail into the rune slice
		for _, segment := range player.Trail {
			strWorld[segment.Pos.RoundX()+1][segment.Pos.RoundY()+1] = segment.Marker
		}
	}

	// Convert the rune slice to a string
	for y := 0; y < len(strWorld[0]); y++ {
		for x := 0; x < len(strWorld); x++ {
			str += string(strWorld[x][y])
		}

		str += "\r\n"
	}

	return str
}

func (g *Game) Run() {
	// Proxy g.Redraw's channel to g.hub.Redraw
	go func() {
		for {
			g.hub.Redraw <- <-g.Redraw
		}
	}()

	// Run game loop
	go func() {
		var lastUpdate time.Time

		c := time.Tick(time.Second / 60)
		for now := range c {
			g.Update(float64(now.Sub(lastUpdate)) / float64(time.Millisecond))

			lastUpdate = now
		}
	}()

	// Redraw regularly.
	//
	// TODO: Implement diffing and only redraw when needed
	go func() {
		c := time.Tick(time.Second / 10)
		for range c {
			g.Redraw <- struct{}{}
		}
	}()

	g.hub.Run(g)
}

// Update is the main game logic loop. Delta is the time since the last update
// in milliseconds.
func (g *Game) Update(delta float64) {
	for player, session := range g.players() {
		player.Update(delta)

		// Kick player if they're out of bounds
		pos := player.Pos
		if pos.RoundX() < 0 || pos.RoundX() > len(g.level) ||
			pos.RoundY() < 0 || pos.RoundY() > len(g.level[0]) {
			g.hub.Unregister <- session
		}
	}
}

func (g *Game) Render(w io.Writer) {
	worldStr := g.worldString()

	fmt.Fprintln(w)
	fmt.Fprint(w, worldStr)
}

func (g *Game) AddSession(s *Session) {
	g.hub.Register <- s
}

type Session struct {
	c ssh.Channel

	Player *Player
}

func NewSession(c ssh.Channel) *Session {
	s := Session{c: c}
	s.Player = NewPlayer()

	return &s
}

func (s *Session) Read(p []byte) (int, error) {
	return s.c.Read(p)
}

func (s *Session) Write(p []byte) (int, error) {
	return s.c.Write(p)
}
<|endoftext|>


<commit_before>/*
Copyright 2016 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 server

import (
	"fmt"
	"io"

	"github.com/golang/glog"
	"github.com/spf13/cobra"

	"k8s.io/kubernetes/pkg/api"
	//"k8s.io/kubernetes/pkg/apimachinery/registered"
	"k8s.io/kubernetes/pkg/genericapiserver"
	genericserveroptions "k8s.io/kubernetes/pkg/genericapiserver/options"

	"github.com/kubernetes-incubator/service-catalog/pkg/apiserver"
)

// ServiceCatalogServerOptions contains the aggregation of configuration structs for
// the service-catalog server. The theory here is that any future user
// of this server will be able to use this options object as a sub
// options of its own.
type ServiceCatalogServerOptions struct {
	// the runtime configuration of our server
	GenericServerRunOptions *genericserveroptions.ServerRunOptions
	// the https configuration. certs, etc
	SecureServingOptions *genericserveroptions.SecureServingOptions
	// storage with etcd
	EtcdOptions *genericserveroptions.EtcdOptions
	// authn
	AuthenticationOptions *genericserveroptions.DelegatingAuthenticationOptions
	// authz
	AuthorizationOptions *genericserveroptions.DelegatingAuthorizationOptions
}

const (
	// I made this up to match some existing paths. I am not sure if there
	// are any restrictions on the format or structure beyond text
	// separated by slashes.
	etcdPathPrefix = "/k8s.io/service-catalog"

	// GroupName I made this up. Maybe we'll need it.
	GroupName = "service-catalog.k8s.io"
)

// NewCommandServer creates a new cobra command to run our server.
func NewCommandServer(out io.Writer) *cobra.Command {
	// initalize our sub options.
	options := &ServiceCatalogServerOptions{
		GenericServerRunOptions: genericserveroptions.NewServerRunOptions(),
		SecureServingOptions:    genericserveroptions.NewSecureServingOptions(),
		EtcdOptions:             genericserveroptions.NewEtcdOptions(),
		AuthenticationOptions:   genericserveroptions.NewDelegatingAuthenticationOptions(),
		AuthorizationOptions:    genericserveroptions.NewDelegatingAuthorizationOptions(),
	}

	// Store resources in etcd under our special prefix
	options.EtcdOptions.StorageConfig.Prefix = etcdPathPrefix

	// Create the command that runs the API server
	cmd := &cobra.Command{
		Short: "run a service-catalog server",
		Run: func(c *cobra.Command, args []string) {
			options.runServer()
		},
	}

	// We pass flags object to sub option structs to have them configure
	// themselves. Each options adds its own command line flags
	// in addition to the flags that are defined above.
	flags := cmd.Flags()
	// TODO consider an AddFlags() method on our options
	// struct. Will need to import pflag.
	//
	// repeated pattern seems like it should be refactored if all
	// options were of an interface type that specified AddFlags.
	options.GenericServerRunOptions.AddUniversalFlags(flags)
	options.SecureServingOptions.AddFlags(flags)
	options.EtcdOptions.AddFlags(flags)
	options.AuthenticationOptions.AddFlags(flags)
	options.AuthorizationOptions.AddFlags(flags)

	return cmd
}

// runServer is a method on the options for composition. allows embedding in a
// higher level options as we do the etcd and serving options.
func (serverOptions ServiceCatalogServerOptions) runServer() error {
	glog.V(4).Infoln("Preparing to run API server")
	// options
	// runtime options
	if err := serverOptions.GenericServerRunOptions.DefaultExternalAddress(serverOptions.SecureServingOptions, nil); err != nil {
		return err
	}

	// server configuration options
	glog.V(4).Infoln("Setting up secure serving options")
	if err := serverOptions.SecureServingOptions.MaybeDefaultWithSelfSignedCerts(serverOptions.GenericServerRunOptions.AdvertiseAddress.String()); err != nil {
		glog.Errorf("Error creating self-signed certificates: %v", err)
		return err
	}

	// etcd options
	if errs := serverOptions.EtcdOptions.Validate(); len(errs) > 0 {
		glog.Errorln("Error validating etcd options, do you have `--etcd-servers localhost` set?")
		return errs[0]
	}

	// config
	glog.V(4).Infoln("Configuring generic API server")
	genericconfig := genericapiserver.NewConfig().ApplyOptions(serverOptions.GenericServerRunOptions)
	// these are all mutators of each specific suboption in serverOptions object.
	// this repeated pattern seems like we could refactor
	if _, err := genericconfig.ApplySecureServingOptions(serverOptions.SecureServingOptions); err != nil {
		glog.Errorln(err)
		return err
	}

	glog.V(4).Info("Setting up authn (disabled)")
	// need to figure out what's throwing the `missing clientCA file` err
	/*
		if _, err := genericconfig.ApplyDelegatingAuthenticationOptions(serverOptions.AuthenticationOptions); err != nil {
			glog.Infoln(err)
			return err
		}
	*/

	glog.V(4).Infoln("Setting up authz (disabled)")
	// having this enabled causes the server to crash for any call
	/*
		if _, err := genericconfig.ApplyDelegatingAuthorizationOptions(serverOptions.AuthorizationOptions); err != nil {
			glog.Infoln(err)
			return err
		}
	*/

	glog.V(4).Infoln("Creating storage factory")
	// The API server stores objects using a particular API version for each
	// group, regardless of API version of the object when it was created.
	//
	// storageGroupsToEncodingVersion holds a map of API group to version that
	// the API server uses to store that group.
	storageGroupsToEncodingVersion, err := serverOptions.GenericServerRunOptions.StorageGroupsToEncodingVersion()
	if err != nil {
		return fmt.Errorf("error generating storage version map: %s", err)
	}

	// Build the default storage factory.
	//
	// The default storage factory returns the storage interface for a
	// particular GroupResource (an (api-group, resource) tuple).
	storageFactory, err := genericapiserver.BuildDefaultStorageFactory(
		serverOptions.EtcdOptions.StorageConfig,
		serverOptions.GenericServerRunOptions.DefaultStorageMediaType,
		api.Codecs,
		genericapiserver.NewDefaultResourceEncodingConfig(),
		storageGroupsToEncodingVersion,
		nil, /* group storage version overrides */
		apiserver.DefaultAPIResourceConfigSource(),
		serverOptions.GenericServerRunOptions.RuntimeConfig)
	if err != nil {
		glog.Errorf("error creating storage factory: %v", err)
		return err
	}

	// Set the finalized generic and storage configs
	config := apiserver.Config{
		GenericConfig:  genericconfig,
		StorageFactory: storageFactory,
	}

	// Fill in defaults not already set in the config
	completedconfig := config.Complete()

	// make the server
	glog.V(4).Infoln("Completing API server configuration")
	server, err := completedconfig.New()
	if err != nil {
		return fmt.Errorf("error completing API server configuration: %v", err)
	}

	// I don't like this. We're reaching in too far to call things.
	preparedserver := server.GenericAPIServer.PrepareRun() // post api installation setup? We should have set up the api already?

	stop := make(chan struct{})
	glog.Infoln("Running the API server")
	preparedserver.Run(stop)

	return nil
}
<commit_msg>add goflags so glog flags work (#258)<commit_after>/*
Copyright 2016 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 server

import (
	"flag"
	"fmt"
	"io"

	"github.com/golang/glog"
	"github.com/spf13/cobra"

	"k8s.io/kubernetes/pkg/api"
	//"k8s.io/kubernetes/pkg/apimachinery/registered"
	"k8s.io/kubernetes/pkg/genericapiserver"
	genericserveroptions "k8s.io/kubernetes/pkg/genericapiserver/options"

	"github.com/kubernetes-incubator/service-catalog/pkg/apiserver"
)

// ServiceCatalogServerOptions contains the aggregation of configuration structs for
// the service-catalog server. The theory here is that any future user
// of this server will be able to use this options object as a sub
// options of its own.
type ServiceCatalogServerOptions struct {
	// the runtime configuration of our server
	GenericServerRunOptions *genericserveroptions.ServerRunOptions
	// the https configuration. certs, etc
	SecureServingOptions *genericserveroptions.SecureServingOptions
	// storage with etcd
	EtcdOptions *genericserveroptions.EtcdOptions
	// authn
	AuthenticationOptions *genericserveroptions.DelegatingAuthenticationOptions
	// authz
	AuthorizationOptions *genericserveroptions.DelegatingAuthorizationOptions
}

const (
	// I made this up to match some existing paths. I am not sure if there
	// are any restrictions on the format or structure beyond text
	// separated by slashes.
	etcdPathPrefix = "/k8s.io/service-catalog"

	// GroupName I made this up. Maybe we'll need it.
	GroupName = "service-catalog.k8s.io"
)

// NewCommandServer creates a new cobra command to run our server.
func NewCommandServer(out io.Writer) *cobra.Command {
	// initalize our sub options.
	options := &ServiceCatalogServerOptions{
		GenericServerRunOptions: genericserveroptions.NewServerRunOptions(),
		SecureServingOptions:    genericserveroptions.NewSecureServingOptions(),
		EtcdOptions:             genericserveroptions.NewEtcdOptions(),
		AuthenticationOptions:   genericserveroptions.NewDelegatingAuthenticationOptions(),
		AuthorizationOptions:    genericserveroptions.NewDelegatingAuthorizationOptions(),
	}

	// Store resources in etcd under our special prefix
	options.EtcdOptions.StorageConfig.Prefix = etcdPathPrefix

	// Create the command that runs the API server
	cmd := &cobra.Command{
		Short: "run a service-catalog server",
		Run: func(c *cobra.Command, args []string) {
			options.runServer()
		},
	}

	// We pass flags object to sub option structs to have them configure
	// themselves. Each options adds its own command line flags
	// in addition to the flags that are defined above.
	flags := cmd.Flags()
	// TODO consider an AddFlags() method on our options
	// struct. Will need to import pflag.
	//
	// repeated pattern seems like it should be refactored if all
	// options were of an interface type that specified AddFlags.
	flags.AddGoFlagSet(flag.CommandLine)
	options.GenericServerRunOptions.AddUniversalFlags(flags)
	options.SecureServingOptions.AddFlags(flags)
	options.EtcdOptions.AddFlags(flags)
	options.AuthenticationOptions.AddFlags(flags)
	options.AuthorizationOptions.AddFlags(flags)

	return cmd
}

// runServer is a method on the options for composition. allows embedding in a
// higher level options as we do the etcd and serving options.
func (serverOptions ServiceCatalogServerOptions) runServer() error {
	glog.V(4).Infoln("Preparing to run API server")
	// options
	// runtime options
	if err := serverOptions.GenericServerRunOptions.DefaultExternalAddress(serverOptions.SecureServingOptions, nil); err != nil {
		return err
	}

	// server configuration options
	glog.V(4).Infoln("Setting up secure serving options")
	if err := serverOptions.SecureServingOptions.MaybeDefaultWithSelfSignedCerts(serverOptions.GenericServerRunOptions.AdvertiseAddress.String()); err != nil {
		glog.Errorf("Error creating self-signed certificates: %v", err)
		return err
	}

	// etcd options
	if errs := serverOptions.EtcdOptions.Validate(); len(errs) > 0 {
		glog.Errorln("Error validating etcd options, do you have `--etcd-servers localhost` set?")
		return errs[0]
	}

	// config
	glog.V(4).Infoln("Configuring generic API server")
	genericconfig := genericapiserver.NewConfig().ApplyOptions(serverOptions.GenericServerRunOptions)
	// these are all mutators of each specific suboption in serverOptions object.
	// this repeated pattern seems like we could refactor
	if _, err := genericconfig.ApplySecureServingOptions(serverOptions.SecureServingOptions); err != nil {
		glog.Errorln(err)
		return err
	}

	glog.V(4).Info("Setting up authn (disabled)")
	// need to figure out what's throwing the `missing clientCA file` err
	/*
		if _, err := genericconfig.ApplyDelegatingAuthenticationOptions(serverOptions.AuthenticationOptions); err != nil {
			glog.Infoln(err)
			return err
		}
	*/

	glog.V(4).Infoln("Setting up authz (disabled)")
	// having this enabled causes the server to crash for any call
	/*
		if _, err := genericconfig.ApplyDelegatingAuthorizationOptions(serverOptions.AuthorizationOptions); err != nil {
			glog.Infoln(err)
			return err
		}
	*/

	glog.V(4).Infoln("Creating storage factory")
	// The API server stores objects using a particular API version for each
	// group, regardless of API version of the object when it was created.
	//
	// storageGroupsToEncodingVersion holds a map of API group to version that
	// the API server uses to store that group.
	storageGroupsToEncodingVersion, err := serverOptions.GenericServerRunOptions.StorageGroupsToEncodingVersion()
	if err != nil {
		return fmt.Errorf("error generating storage version map: %s", err)
	}

	// Build the default storage factory.
	//
	// The default storage factory returns the storage interface for a
	// particular GroupResource (an (api-group, resource) tuple).
	storageFactory, err := genericapiserver.BuildDefaultStorageFactory(
		serverOptions.EtcdOptions.StorageConfig,
		serverOptions.GenericServerRunOptions.DefaultStorageMediaType,
		api.Codecs,
		genericapiserver.NewDefaultResourceEncodingConfig(),
		storageGroupsToEncodingVersion,
		nil, /* group storage version overrides */
		apiserver.DefaultAPIResourceConfigSource(),
		serverOptions.GenericServerRunOptions.RuntimeConfig)
	if err != nil {
		glog.Errorf("error creating storage factory: %v", err)
		return err
	}

	// Set the finalized generic and storage configs
	config := apiserver.Config{
		GenericConfig:  genericconfig,
		StorageFactory: storageFactory,
	}

	// Fill in defaults not already set in the config
	completedconfig := config.Complete()

	// make the server
	glog.V(4).Infoln("Completing API server configuration")
	server, err := completedconfig.New()
	if err != nil {
		return fmt.Errorf("error completing API server configuration: %v", err)
	}

	// I don't like this. We're reaching in too far to call things.
	preparedserver := server.GenericAPIServer.PrepareRun() // post api installation setup? We should have set up the api already?

	stop := make(chan struct{})
	glog.Infoln("Running the API server")
	preparedserver.Run(stop)

	return nil
}
<|endoftext|>


<commit_before>// addDNS01 handles an HTTP POST request to add a new DNS-01 challenge TXT
package main

import (
	"net/http"
	"strings"

	"github.com/letsencrypt/challtestsrv"
)

// setDefaultDNSIPv4 handles an HTTP POST request to set the default IPv4
// address used for all A query responses that do not match more-specific mocked
// responses.
//
// The POST body is expected to have one parameter:
// "ip" - the string representation of an IPv4 address to use for all A queries
//        that do not match more specific mocks.
//
// Providing an empty string as the IP value will disable the default
// A responses.
//
// A successful POST will write http.StatusOK to the client.
func (srv *managementServer) setDefaultDNSIPv4(w http.ResponseWriter, r *http.Request) {
	var request struct {
		IP string
	}
	if err := mustParsePOST(&request, r); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// Set the challenge server's default IPv4 address - we allow request.IP to be
	// the empty string so that the default can be be cleared using the same
	// method.
	srv.challSrv.SetDefaultDNSIPv4(request.IP)
	srv.log.Printf("Set default IPv4 address for DNS A queries to %q\n", request.IP)
	w.WriteHeader(http.StatusOK)
}

// setDefaultDNSIPv6 handles an HTTP POST request to set the default IPv6
// address used for all AAAA query responses that do not match more-specific
// mocked responses.
//
// The POST body is expected to have one parameter:
// "ip" - the string representation of an IPv6 address to use for all AAAA
//        queries that do not match more specific mocks.
//
// Providing an empty string as the IP value will disable the default
// A responses.
//
// A successful POST will write http.StatusOK to the client.
func (srv *managementServer) setDefaultDNSIPv6(w http.ResponseWriter, r *http.Request) {
	var request struct {
		IP string
	}
	if err := mustParsePOST(&request, r); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// Set the challenge server's default IPv6 address - we allow request.IP to be
	// the empty string so that the default can be be cleared using the same
	// method.
	srv.challSrv.SetDefaultDNSIPv6(request.IP)
	srv.log.Printf("Set default IPv6 address for DNS AAAA queries to %q\n", request.IP)
	w.WriteHeader(http.StatusOK)
}

// addDNSARecord handles an HTTP POST request to add a mock A query response record
// for a host.
//
// The POST body is expected to have two non-empty parameters:
// "host" - the hostname that when queried should return the mocked A record.
// "addresses" - an array of IPv4 addresses in string representation that should
// be used for the A records returned for the query.
//
// A successful POST will write http.StatusOK to the client.
func (srv *managementServer) addDNSARecord(w http.ResponseWriter, r *http.Request) {
	var request struct {
		Host      string
		Addresses []string
	}
	if err := mustParsePOST(&request, r); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// If the request has no addresses or an empty host it's a bad request
	if len(request.Addresses) == 0 || request.Host == "" {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	srv.challSrv.AddDNSARecord(request.Host, request.Addresses)
	srv.log.Printf("Added response for DNS A queries to %q : %s\n",
		request.Host, strings.Join(request.Addresses, ", "))
	w.WriteHeader(http.StatusOK)
}

// delDNSARecord handles an HTTP POST request to delete an existing mock A
// policy record for a host.
//
// The POST body is expected to have one non-empty parameter:
// "host" - the hostname to remove the mock A record for.
//
// A successful POST will write http.StatusOK to the client.
func (srv *managementServer) delDNSARecord(w http.ResponseWriter, r *http.Request) {
	var request struct {
		Host string
	}
	if err := mustParsePOST(&request, r); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// If the request has an empty host it's a bad request
	if request.Host == "" {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	srv.challSrv.DeleteDNSARecord(request.Host)
	srv.log.Printf("Removed response for DNS A queries to %q", request.Host)
	w.WriteHeader(http.StatusOK)
}

// addDNSAAAARecord handles an HTTP POST request to add a mock AAAA query
// response record for a host.
//
// The POST body is expected to have two non-empty parameters:
// "host" - the hostname that when queried should return the mocked A record.
// "addresses" - an array of IPv6 addresses in string representation that should
// be used for the AAAA records returned for the query.
//
// A successful POST will write http.StatusOK to the client.
func (srv *managementServer) addDNSAAAARecord(w http.ResponseWriter, r *http.Request) {
	var request struct {
		Host      string
		Addresses []string
	}
	if err := mustParsePOST(&request, r); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// If the request has no addresses or an empty host it's a bad request
	if len(request.Addresses) == 0 || request.Host == "" {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	srv.challSrv.AddDNSAAAARecord(request.Host, request.Addresses)
	srv.log.Printf("Added response for DNS AAAA queries to %q : %s\n",
		request.Host, strings.Join(request.Addresses, ", "))
	w.WriteHeader(http.StatusOK)
}

// delDNSAAAARecord handles an HTTP POST request to delete an existing mock AAAA
// policy record for a host.
//
// The POST body is expected to have one non-empty parameter:
// "host" - the hostname to remove the mock AAAA record for.
//
// A successful POST will write http.StatusOK to the client.
func (srv *managementServer) delDNSAAAARecord(w http.ResponseWriter, r *http.Request) {
	var request struct {
		Host string
	}
	if err := mustParsePOST(&request, r); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// If the request has an empty host it's a bad request
	if request.Host == "" {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	srv.challSrv.DeleteDNSAAAARecord(request.Host)
	srv.log.Printf("Removed response for DNS AAAA queries to %q", request.Host)
	w.WriteHeader(http.StatusOK)
}

// addDNSCAARecord handles an HTTP POST request to add a mock CAA query
// response record for a host.
//
// The POST body is expected to have two non-empty parameters:
// "host" - the hostname that when queried should return the mocked CAA record.
// "policies" - an array of CAA policy objects. Each policy object is expected
// to have two non-empty keys, "tag" and "value".
//
// A successful POST will write http.StatusOK to the client.
func (srv *managementServer) addDNSCAARecord(w http.ResponseWriter, r *http.Request) {
	var request struct {
		Host     string
		Policies []challtestsrv.MockCAAPolicy
	}
	if err := mustParsePOST(&request, r); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// If the request has no host or no caa policies it's a bad request
	if request.Host == "" || len(request.Policies) == 0 {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	srv.challSrv.AddDNSCAARecord(request.Host, request.Policies)
	srv.log.Printf("Added response for DNS CAA queries to %q", request.Host)
	w.WriteHeader(http.StatusOK)
}

// delDNSCAARecord handles an HTTP POST request to delete an existing mock CAA
// policy record for a host.
//
// The POST body is expected to have one non-empty parameter:
// "host" - the hostname to remove the mock CAA policy for.
//
// A successful POST will write http.StatusOK to the client.
func (srv *managementServer) delDNSCAARecord(w http.ResponseWriter, r *http.Request) {
	var request struct {
		Host string
	}
	if err := mustParsePOST(&request, r); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// If the request has an empty host it's a bad request
	if request.Host == "" {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	srv.challSrv.DeleteDNSCAARecord(request.Host)
	srv.log.Printf("Removed response for DNS CAA queries to %q", request.Host)
	w.WriteHeader(http.StatusOK)
}

// addDNSCNAMERecord handles an HTTP POST request to add a mock CNAME query
// response record and alias for a host.
//
// The POST body is expected to have two non-empty parameters:
// "host" - the hostname that should be treated as an alias to the target
// "target" - the hostname whose mocked DNS records should be returned
//
// A successful POST will write http.StatusOK to the client.
func (srv *managementServer) addDNSCNAMERecord(w http.ResponseWriter, r *http.Request) {
	var request struct {
		Host   string
		Target string
	}
	if err := mustParsePOST(&request, r); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// If the request has no host or no caa policies it's a bad request
	if request.Host == "" || request.Target == "" {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	srv.challSrv.AddDNSCNAMERecord(request.Host, request.Target)
	srv.log.Printf("Added response for DNS CNAME queries to %q targeting %q", request.Host, request.Target)
	w.WriteHeader(http.StatusOK)
}

// delDNSCNAMERecord handles an HTTP POST request to delete an existing mock
// CNAME record for a host.
//
// The POST body is expected to have one non-empty parameters:
// "host" - the hostname to remove the mock CNAME alias for.
//
// A successful POST will write http.StatusOK to the client.
func (srv *managementServer) delDNSCNAMERecord(w http.ResponseWriter, r *http.Request) {
	var request struct {
		Host string
	}
	if err := mustParsePOST(&request, r); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// If the request has an empty host it's a bad request
	if request.Host == "" {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	srv.challSrv.DeleteDNSCAARecord(request.Host)
	srv.log.Printf("Removed response for DNS CNAME queries to %q", request.Host)
	w.WriteHeader(http.StatusOK)
}
<commit_msg>pebble-challtestsrv: fix CNAME delete API (#273)<commit_after>// addDNS01 handles an HTTP POST request to add a new DNS-01 challenge TXT
package main

import (
	"net/http"
	"strings"

	"github.com/letsencrypt/challtestsrv"
)

// setDefaultDNSIPv4 handles an HTTP POST request to set the default IPv4
// address used for all A query responses that do not match more-specific mocked
// responses.
//
// The POST body is expected to have one parameter:
// "ip" - the string representation of an IPv4 address to use for all A queries
//        that do not match more specific mocks.
//
// Providing an empty string as the IP value will disable the default
// A responses.
//
// A successful POST will write http.StatusOK to the client.
func (srv *managementServer) setDefaultDNSIPv4(w http.ResponseWriter, r *http.Request) {
	var request struct {
		IP string
	}
	if err := mustParsePOST(&request, r); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// Set the challenge server's default IPv4 address - we allow request.IP to be
	// the empty string so that the default can be be cleared using the same
	// method.
	srv.challSrv.SetDefaultDNSIPv4(request.IP)
	srv.log.Printf("Set default IPv4 address for DNS A queries to %q\n", request.IP)
	w.WriteHeader(http.StatusOK)
}

// setDefaultDNSIPv6 handles an HTTP POST request to set the default IPv6
// address used for all AAAA query responses that do not match more-specific
// mocked responses.
//
// The POST body is expected to have one parameter:
// "ip" - the string representation of an IPv6 address to use for all AAAA
//        queries that do not match more specific mocks.
//
// Providing an empty string as the IP value will disable the default
// A responses.
//
// A successful POST will write http.StatusOK to the client.
func (srv *managementServer) setDefaultDNSIPv6(w http.ResponseWriter, r *http.Request) {
	var request struct {
		IP string
	}
	if err := mustParsePOST(&request, r); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// Set the challenge server's default IPv6 address - we allow request.IP to be
	// the empty string so that the default can be be cleared using the same
	// method.
	srv.challSrv.SetDefaultDNSIPv6(request.IP)
	srv.log.Printf("Set default IPv6 address for DNS AAAA queries to %q\n", request.IP)
	w.WriteHeader(http.StatusOK)
}

// addDNSARecord handles an HTTP POST request to add a mock A query response record
// for a host.
//
// The POST body is expected to have two non-empty parameters:
// "host" - the hostname that when queried should return the mocked A record.
// "addresses" - an array of IPv4 addresses in string representation that should
// be used for the A records returned for the query.
//
// A successful POST will write http.StatusOK to the client.
func (srv *managementServer) addDNSARecord(w http.ResponseWriter, r *http.Request) {
	var request struct {
		Host      string
		Addresses []string
	}
	if err := mustParsePOST(&request, r); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// If the request has no addresses or an empty host it's a bad request
	if len(request.Addresses) == 0 || request.Host == "" {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	srv.challSrv.AddDNSARecord(request.Host, request.Addresses)
	srv.log.Printf("Added response for DNS A queries to %q : %s\n",
		request.Host, strings.Join(request.Addresses, ", "))
	w.WriteHeader(http.StatusOK)
}

// delDNSARecord handles an HTTP POST request to delete an existing mock A
// policy record for a host.
//
// The POST body is expected to have one non-empty parameter:
// "host" - the hostname to remove the mock A record for.
//
// A successful POST will write http.StatusOK to the client.
func (srv *managementServer) delDNSARecord(w http.ResponseWriter, r *http.Request) {
	var request struct {
		Host string
	}
	if err := mustParsePOST(&request, r); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// If the request has an empty host it's a bad request
	if request.Host == "" {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	srv.challSrv.DeleteDNSARecord(request.Host)
	srv.log.Printf("Removed response for DNS A queries to %q", request.Host)
	w.WriteHeader(http.StatusOK)
}

// addDNSAAAARecord handles an HTTP POST request to add a mock AAAA query
// response record for a host.
//
// The POST body is expected to have two non-empty parameters:
// "host" - the hostname that when queried should return the mocked A record.
// "addresses" - an array of IPv6 addresses in string representation that should
// be used for the AAAA records returned for the query.
//
// A successful POST will write http.StatusOK to the client.
func (srv *managementServer) addDNSAAAARecord(w http.ResponseWriter, r *http.Request) {
	var request struct {
		Host      string
		Addresses []string
	}
	if err := mustParsePOST(&request, r); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// If the request has no addresses or an empty host it's a bad request
	if len(request.Addresses) == 0 || request.Host == "" {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	srv.challSrv.AddDNSAAAARecord(request.Host, request.Addresses)
	srv.log.Printf("Added response for DNS AAAA queries to %q : %s\n",
		request.Host, strings.Join(request.Addresses, ", "))
	w.WriteHeader(http.StatusOK)
}

// delDNSAAAARecord handles an HTTP POST request to delete an existing mock AAAA
// policy record for a host.
//
// The POST body is expected to have one non-empty parameter:
// "host" - the hostname to remove the mock AAAA record for.
//
// A successful POST will write http.StatusOK to the client.
func (srv *managementServer) delDNSAAAARecord(w http.ResponseWriter, r *http.Request) {
	var request struct {
		Host string
	}
	if err := mustParsePOST(&request, r); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// If the request has an empty host it's a bad request
	if request.Host == "" {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	srv.challSrv.DeleteDNSAAAARecord(request.Host)
	srv.log.Printf("Removed response for DNS AAAA queries to %q", request.Host)
	w.WriteHeader(http.StatusOK)
}

// addDNSCAARecord handles an HTTP POST request to add a mock CAA query
// response record for a host.
//
// The POST body is expected to have two non-empty parameters:
// "host" - the hostname that when queried should return the mocked CAA record.
// "policies" - an array of CAA policy objects. Each policy object is expected
// to have two non-empty keys, "tag" and "value".
//
// A successful POST will write http.StatusOK to the client.
func (srv *managementServer) addDNSCAARecord(w http.ResponseWriter, r *http.Request) {
	var request struct {
		Host     string
		Policies []challtestsrv.MockCAAPolicy
	}
	if err := mustParsePOST(&request, r); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// If the request has no host or no caa policies it's a bad request
	if request.Host == "" || len(request.Policies) == 0 {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	srv.challSrv.AddDNSCAARecord(request.Host, request.Policies)
	srv.log.Printf("Added response for DNS CAA queries to %q", request.Host)
	w.WriteHeader(http.StatusOK)
}

// delDNSCAARecord handles an HTTP POST request to delete an existing mock CAA
// policy record for a host.
//
// The POST body is expected to have one non-empty parameter:
// "host" - the hostname to remove the mock CAA policy for.
//
// A successful POST will write http.StatusOK to the client.
func (srv *managementServer) delDNSCAARecord(w http.ResponseWriter, r *http.Request) {
	var request struct {
		Host string
	}
	if err := mustParsePOST(&request, r); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// If the request has an empty host it's a bad request
	if request.Host == "" {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	srv.challSrv.DeleteDNSCAARecord(request.Host)
	srv.log.Printf("Removed response for DNS CAA queries to %q", request.Host)
	w.WriteHeader(http.StatusOK)
}

// addDNSCNAMERecord handles an HTTP POST request to add a mock CNAME query
// response record and alias for a host.
//
// The POST body is expected to have two non-empty parameters:
// "host" - the hostname that should be treated as an alias to the target
// "target" - the hostname whose mocked DNS records should be returned
//
// A successful POST will write http.StatusOK to the client.
func (srv *managementServer) addDNSCNAMERecord(w http.ResponseWriter, r *http.Request) {
	var request struct {
		Host   string
		Target string
	}
	if err := mustParsePOST(&request, r); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// If the request has no host or no caa policies it's a bad request
	if request.Host == "" || request.Target == "" {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	srv.challSrv.AddDNSCNAMERecord(request.Host, request.Target)
	srv.log.Printf("Added response for DNS CNAME queries to %q targeting %q", request.Host, request.Target)
	w.WriteHeader(http.StatusOK)
}

// delDNSCNAMERecord handles an HTTP POST request to delete an existing mock
// CNAME record for a host.
//
// The POST body is expected to have one non-empty parameters:
// "host" - the hostname to remove the mock CNAME alias for.
//
// A successful POST will write http.StatusOK to the client.
func (srv *managementServer) delDNSCNAMERecord(w http.ResponseWriter, r *http.Request) {
	var request struct {
		Host string
	}
	if err := mustParsePOST(&request, r); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// If the request has an empty host it's a bad request
	if request.Host == "" {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	srv.challSrv.DeleteDNSCNAMERecord(request.Host)
	srv.log.Printf("Removed response for DNS CNAME queries to %q", request.Host)
	w.WriteHeader(http.StatusOK)
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Skaffold 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 cmd

import (
	"bytes"
	"context"
	"errors"
	"io"
	"io/ioutil"
	"testing"

	"github.com/GoogleContainerTools/skaffold/cmd/skaffold/app/flags"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
	"github.com/GoogleContainerTools/skaffold/testutil"
)

func TestQuietFlag(t *testing.T) {
	mockCreateRunner := func(c context.Context, buildOut io.Writer) ([]build.Artifact, error) {
		return []build.Artifact{{
			ImageName: "gcr.io/skaffold/example",
			Tag:       "test",
		}}, nil
	}

	orginalCreateRunner := createRunnerAndBuildFunc
	defer func(f func(c context.Context, buildOut io.Writer) ([]build.Artifact, error)) {
		createRunnerAndBuildFunc = f
	}(orginalCreateRunner)
	var tests = []struct {
		description    string
		template       string
		expectedOutput []byte
		mock           func(context.Context, io.Writer) ([]build.Artifact, error)
		shouldErr      bool
	}{
		{
			description:    "quiet flag print build images with no template",
			expectedOutput: []byte("{[{gcr.io/skaffold/example test}]}"),
			shouldErr:      false,
			mock:           mockCreateRunner,
		},
		{
			description:    "quiet flag print build images applies pattern specified in template ",
			template:       "{{range .Builds}}{{.ImageName}} -> {{.Tag}}\n{{end}}",
			expectedOutput: []byte("gcr.io/skaffold/example -> test\n"),
			shouldErr:      false,
			mock:           mockCreateRunner,
		},
		{
			description:    "build errors out when incorrect template specified",
			template:       "{{.Incorrect}}",
			expectedOutput: nil,
			shouldErr:      true,
			mock:           mockCreateRunner,
		},
	}

	for _, test := range tests {
		t.Run(test.description, func(t *testing.T) {
			quietFlag = true
			defer func() { quietFlag = false }()
			if test.template != "" {
				buildFormatFlag = flags.NewTemplateFlag(test.template, BuildOutput{})
			}
			defer func() { buildFormatFlag = nil }()
			createRunnerAndBuildFunc = test.mock
			var output bytes.Buffer
			err := runBuild(&output)
			testutil.CheckErrorAndDeepEqual(t, test.shouldErr, err, string(test.expectedOutput), output.String())
		})
	}
}

func TestRunBuild(t *testing.T) {
	errRunner := func(c context.Context, buildOut io.Writer) ([]build.Artifact, error) {
		return nil, errors.New("some error")
	}
	mockCreateRunner := func(c context.Context, buildOut io.Writer) ([]build.Artifact, error) {
		return []build.Artifact{{
			ImageName: "gcr.io/skaffold/example",
			Tag:       "test",
		}}, nil
	}
	orginalCreateRunner := createRunnerAndBuildFunc
	defer func(f func(c context.Context, buildOut io.Writer) ([]build.Artifact, error)) {
		createRunnerAndBuildFunc = f
	}(orginalCreateRunner)

	var tests = []struct {
		description string
		mock        func(context.Context, io.Writer) ([]build.Artifact, error)
		shouldErr   bool
	}{
		{
			description: "build should return successfully when runner is successful.",
			shouldErr:   false,
			mock:        mockCreateRunner,
		},
		{
			description: "build errors out when there was runner error.",
			shouldErr:   true,
			mock:        errRunner,
		},
	}
	for _, test := range tests {
		t.Run(test.description, func(t *testing.T) {
			createRunnerAndBuildFunc = test.mock
			err := runBuild(ioutil.Discard)
			testutil.CheckError(t, test.shouldErr, err)
		})
	}
}
<commit_msg>code review comments<commit_after>/*
Copyright 2019 The Skaffold 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 cmd

import (
	"bytes"
	"context"
	"errors"
	"io"
	"io/ioutil"
	"testing"

	"github.com/GoogleContainerTools/skaffold/cmd/skaffold/app/flags"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
	"github.com/GoogleContainerTools/skaffold/testutil"
)

func TestQuietFlag(t *testing.T) {
	mockCreateRunner := func(context.Context, io.Writer) ([]build.Artifact, error) {
		return []build.Artifact{{
			ImageName: "gcr.io/skaffold/example",
			Tag:       "test",
		}}, nil
	}

	defer func(f func(context.Context, io.Writer) ([]build.Artifact, error)) {
		createRunnerAndBuildFunc = f
	}(createRunnerAndBuildFunc)

	var tests = []struct {
		description    string
		template       string
		expectedOutput []byte
		mock           func(context.Context, io.Writer) ([]build.Artifact, error)
		shouldErr      bool
	}{
		{
			description:    "quiet flag print build images with no template",
			expectedOutput: []byte("{[{gcr.io/skaffold/example test}]}"),
			shouldErr:      false,
			mock:           mockCreateRunner,
		},
		{
			description:    "quiet flag print build images applies pattern specified in template ",
			template:       "{{range .Builds}}{{.ImageName}} -> {{.Tag}}\n{{end}}",
			expectedOutput: []byte("gcr.io/skaffold/example -> test\n"),
			shouldErr:      false,
			mock:           mockCreateRunner,
		},
		{
			description:    "build errors out when incorrect template specified",
			template:       "{{.Incorrect}}",
			expectedOutput: nil,
			shouldErr:      true,
			mock:           mockCreateRunner,
		},
	}

	for _, test := range tests {
		t.Run(test.description, func(t *testing.T) {
			quietFlag = true
			defer func() { quietFlag = false }()
			if test.template != "" {
				buildFormatFlag = flags.NewTemplateFlag(test.template, BuildOutput{})
			}
			defer func() { buildFormatFlag = nil }()
			createRunnerAndBuildFunc = test.mock
			var output bytes.Buffer
			err := runBuild(&output)
			testutil.CheckErrorAndDeepEqual(t, test.shouldErr, err, string(test.expectedOutput), output.String())
		})
	}
}

func TestRunBuild(t *testing.T) {
	errRunner := func(context.Context, io.Writer) ([]build.Artifact, error) {
		return nil, errors.New("some error")
	}
	mockCreateRunner := func(context.Context, io.Writer) ([]build.Artifact, error) {
		return []build.Artifact{{
			ImageName: "gcr.io/skaffold/example",
			Tag:       "test",
		}}, nil
	}
	defer func(f func(context.Context, io.Writer) ([]build.Artifact, error)) {
		createRunnerAndBuildFunc = f
	}(createRunnerAndBuildFunc)

	var tests = []struct {
		description string
		mock        func(context.Context, io.Writer) ([]build.Artifact, error)
		shouldErr   bool
	}{
		{
			description: "build should return successfully when runner is successful.",
			shouldErr:   false,
			mock:        mockCreateRunner,
		},
		{
			description: "build errors out when there was runner error.",
			shouldErr:   true,
			mock:        errRunner,
		},
	}
	for _, test := range tests {
		t.Run(test.description, func(t *testing.T) {
			createRunnerAndBuildFunc = test.mock
			err := runBuild(ioutil.Discard)
			testutil.CheckError(t, test.shouldErr, err)
		})
	}
}
<|endoftext|>


<commit_before>package test

import (
	"encoding/json"
	"testing"

	"github.com/google/go-cmp/cmp"
	fuzz "github.com/google/gofuzz"
	jsoniter "github.com/json-iterator/go"
	"github.com/mailru/easyjson"
	"github.com/unravelin/null"
)

var fuzzFuncs = []interface{}{
	func(a *null.Bool, c fuzz.Continue) {
		a.Valid = c.RandBool()
		if a.Valid {
			a.Bool = c.RandBool()
		}
	},
	func(a *null.Float, c fuzz.Continue) {
		a.Valid = c.RandBool()
		if a.Valid {
			c.Fuzz(&a.Float64)
		}
	},
	func(a *null.Int, c fuzz.Continue) {
		a.Valid = c.RandBool()
		if a.Valid {
			c.Fuzz(&a.Int64)
		}
	},
	func(a *null.String, c fuzz.Continue) {
		a.Valid = c.RandBool()
		if a.Valid {
			c.Fuzz(&a.String)
		}
	},
	func(a *null.Time, c fuzz.Continue) {
		a.Valid = c.RandBool()
		if a.Valid {
			c.Fuzz(&a.Time)
		}
	},
}

func TestPlenc(t *testing.T) {
	f := fuzz.New().Funcs(fuzzFuncs...)
	for i := 0; i < 100; i++ {
		var in, out pltest
		f.Fuzz(&in)

		s := in.ΦλSize()
		b := make([]byte, 0, s)
		b = in.ΦλAppend(b)

		n, err := out.ΦλUnmarshal(b)
		if err != nil {
			t.Fatal(err)
		}
		if n != s || len(b) != s {
			t.Errorf("unexpected lengths %d %d %d", n, s, len(b))
		}

		if diff := cmp.Diff(in, out); diff != "" {
			t.Fatalf("values differ. %s", diff)
		}
	}
}

func TestEasyjson(t *testing.T) {
	f := fuzz.New().Funcs(fuzzFuncs...)
	for i := 0; i < 100; i++ {
		var in, out pltest
		f.Fuzz(&in)
		data, err := easyjson.Marshal(&in)
		if err != nil {
			t.Fatal(err)
		}

		if err := easyjson.Unmarshal(data, &out); err != nil {
			t.Fatal(err)
		}

		if diff := cmp.Diff(in, out); diff != "" {
			t.Fatalf("values differ. %s", diff)
		}
	}
}

func BenchmarkSerialisation(b *testing.B) {
	f := fuzz.New().Funcs(fuzzFuncs...)

	var in pltest
	f.Fuzz(&in)

	b.Run("plenc", func(b *testing.B) {
		b.ReportAllocs()
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				s := in.ΦλSize()
				bu := make([]byte, 0, s)
				bu = in.ΦλAppend(bu)

				var out pltest
				out.ΦλUnmarshal(bu)
			}
		})
	})

	b.Run("easyjson", func(b *testing.B) {
		b.ReportAllocs()
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				data, _ := easyjson.Marshal(&in)
				var out pltest
				easyjson.Unmarshal(data, &out)
			}
		})
	})

	b.Run("json", func(b *testing.B) {
		b.ReportAllocs()
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				data, _ := json.Marshal(&in)
				var out pltest
				json.Unmarshal(data, &out)
			}
		})
	})

	b.Run("jsoniter", func(b *testing.B) {
		b.ReportAllocs()
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				data, _ := jsoniter.Marshal(&in)
				var out pltest
				jsoniter.Unmarshal(data, &out)
			}
		})
	})

}
<commit_msg>Drop some stuff we're not using<commit_after>package test

import (
	"encoding/json"
	"testing"

	"github.com/google/go-cmp/cmp"
	fuzz "github.com/google/gofuzz"
	jsoniter "github.com/json-iterator/go"
	"github.com/mailru/easyjson"
	"github.com/unravelin/null"
)

var fuzzFuncs = []interface{}{
	func(a *null.Bool, c fuzz.Continue) {
		a.Valid = c.RandBool()
		if a.Valid {
			a.Bool = c.RandBool()
		}
	},
	func(a *null.Float, c fuzz.Continue) {
		a.Valid = c.RandBool()
		if a.Valid {
			c.Fuzz(&a.Float64)
		}
	},
	func(a *null.Int, c fuzz.Continue) {
		a.Valid = c.RandBool()
		if a.Valid {
			c.Fuzz(&a.Int64)
		}
	},
	func(a *null.String, c fuzz.Continue) {
		a.Valid = c.RandBool()
		if a.Valid {
			c.Fuzz(&a.String)
		}
	},
	func(a *null.Time, c fuzz.Continue) {
		a.Valid = c.RandBool()
		if a.Valid {
			c.Fuzz(&a.Time)
		}
	},
}

func TestEasyjson(t *testing.T) {
	f := fuzz.New().Funcs(fuzzFuncs...)
	for i := 0; i < 100; i++ {
		var in, out pltest
		f.Fuzz(&in)
		data, err := easyjson.Marshal(&in)
		if err != nil {
			t.Fatal(err)
		}

		if err := easyjson.Unmarshal(data, &out); err != nil {
			t.Fatal(err)
		}

		if diff := cmp.Diff(in, out); diff != "" {
			t.Fatalf("values differ. %s", diff)
		}
	}
}

func BenchmarkSerialisation(b *testing.B) {
	f := fuzz.New().Funcs(fuzzFuncs...)

	var in pltest
	f.Fuzz(&in)

	b.Run("easyjson", func(b *testing.B) {
		b.ReportAllocs()
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				data, _ := easyjson.Marshal(&in)
				var out pltest
				easyjson.Unmarshal(data, &out)
			}
		})
	})

	b.Run("json", func(b *testing.B) {
		b.ReportAllocs()
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				data, _ := json.Marshal(&in)
				var out pltest
				json.Unmarshal(data, &out)
			}
		})
	})

	b.Run("jsoniter", func(b *testing.B) {
		b.ReportAllocs()
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				data, _ := jsoniter.Marshal(&in)
				var out pltest
				jsoniter.Unmarshal(data, &out)
			}
		})
	})

}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"fmt"
	"net/http"

	"code.google.com/p/go.crypto/bcrypt"
	"github.com/go-martini/martini"
	"github.com/martini-contrib/render"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
)

type User struct {
	Id            bson.ObjectId `bson:"_id"              json:"-"`
	Username      string        `bson:"username"         json:"username"`
	Realname      string        `bson:"realname"         json:"realname"`
	Tokens        []Token       `bson:"tokens"           json:"-"`
	Role          int           `bson:"role"             json:"-"`
	Password      string        `bson:"password"         json:"-"`
	Email_address string        `bson:"email_address"    json:"email_address"`
}

type Token struct {
	Token string `bson:"token"    json:"token"`
}

type Book struct {
	Id            bson.ObjectId `bson:"_id"              json:"-"`
	Title         string        `bson:"title"            json:"title"`
	Subtitle      string        `bson:"subtitle"         json:"subtitle"`
	Description   string        `bson:"description"      json:"description"`
	Cover         string        `bson:"cover"            json:"cover"`
	Publisher     string        `bson:"publisher"        json:"publisher"`
	PublishedDate string        `bson:"publishedDate"    json:"publishedDate"`
	ISBN10        string        `bson:"isbn-10"          json:"isbn-10"`
	ISBN13        string        `bson:"isbn-13"          json:"isbn-13"`
	Owner         string        `bson:"owner"            json:"owner"`
	Formats       []Format      `bson:"formats"          json:"formats"`
}

type Format struct {
	Format string `bson:"format"    json:"format"`
	Size   string `bson:"size"      json:"size"`
}

type Feedback struct {
	Success bool   `json:"success"`
	Message string `json:"message"`
}

const (
	token_length = 40
	mongodb_host = "localhost"
	mongodb_db   = "Alexandria"
)

func randtoken(length int) string {

	const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%&?"
	var bytes = make([]byte, length)

	rand.Read(bytes)

	for i, b := range bytes {
		bytes[i] = alphanum[b%byte(len(alphanum))]
	}

	return string(bytes)

}

func main() {

	session, err := mgo.Dial(mongodb_host)

	if err != nil {
		panic(err)
	}

	defer session.Close()

	session.SetMode(mgo.Monotonic, true)

	db := session.DB(mongodb_db)

	m := martini.Classic()
	m.Use(render.Renderer())

	m.Post("/api/portal/login/", func(req *http.Request, r render.Render) {

		username := req.PostFormValue("username")
		password := req.PostFormValue("password")

		if (username == "") || (password == "") {
			feedback := Feedback{}
			feedback.Success = false
			feedback.Message = "The form is not completely filled out."
			r.JSON(400, feedback)
		} else {
			n, err := db.C("Users").Find(bson.M{"username": username}).Count()

			if err != nil {
				panic(err)
			}

			if n != 1 {
				feedback := Feedback{}
				feedback.Success = false
				feedback.Message = "The username '" + username + "' is not registered."
				r.JSON(403, feedback)
			} else {
				user := User{}

				err = db.C("Users").Find(bson.M{"username": username}).One(&user)

				if err != nil {
					panic(err)
				}

				err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))

				if err == nil {
					token := Token{}
					token.Token = randtoken(token_length)

					user.Tokens = append(user.Tokens, token)

					err := db.C("Users").Update(bson.M{"_id": user.Id}, user)

					if err != nil {
						panic(err)
					}

					r.JSON(200, token)
				} else {
					feedback := Feedback{}
					feedback.Success = false
					feedback.Message = "The username and password did not match."
					r.JSON(403, feedback)
				}
			}
		}

	})

	m.Get("/books/", func(req *http.Request, r render.Render) {

		user := User{}
		token := req.URL.Query().Get("token")

		n, err := db.C("Users").Find(bson.M{"tokens.token": token}).Count()

		if err != nil {
			panic(err)
		}

		if n == 0 {
			r.JSON(403, nil)
		} else {
			err = db.C("Users").Find(bson.M{"tokens.token": token}).One(&user)

			if err != nil {
				panic(err)
			}

			result := []Book{}

			fmt.Println(user.Id.Hex())

			err = db.C("Books").Find(bson.M{"owner": user.Id.Hex()}).All(&result)

			if err != nil {
				panic(err)
			}

			r.JSON(200, result)
		}

	})

	m.Run()
}
<commit_msg>Implement filtering of /books/ by genre or author<commit_after>package main

import (
	"crypto/rand"
	"fmt"
	"net/http"

	"code.google.com/p/go.crypto/bcrypt"
	"github.com/go-martini/martini"
	"github.com/martini-contrib/render"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
)

type User struct {
	Id            bson.ObjectId `bson:"_id"              json:"-"`
	Username      string        `bson:"username"         json:"username"`
	Realname      string        `bson:"realname"         json:"realname"`
	Tokens        []Token       `bson:"tokens"           json:"-"`
	Role          int           `bson:"role"             json:"-"`
	Password      string        `bson:"password"         json:"-"`
	Email_address string        `bson:"email_address"    json:"email_address"`
}

type Token struct {
	Token string `bson:"token"    json:"token"`
}

type Book struct {
	Id            bson.ObjectId `bson:"_id"              json:"-"`
	Title         string        `bson:"title"            json:"title"`
	Subtitle      string        `bson:"subtitle"         json:"subtitle"`
	Description   string        `bson:"description"      json:"description"`
	Cover         string        `bson:"cover"            json:"cover"`
	Publisher     string        `bson:"publisher"        json:"publisher"`
	PublishedDate string        `bson:"publishedDate"    json:"publishedDate"`
	ISBN10        string        `bson:"isbn-10"          json:"isbn-10"`
	ISBN13        string        `bson:"isbn-13"          json:"isbn-13"`
	Owner         string        `bson:"owner"            json:"owner"`
	Formats       []Format      `bson:"formats"          json:"formats"`
	Genres        []string      `bson:"genres"           json:"genres"`
	Authors       []string      `bson:"authors"          json:"authors"`
}

type Format struct {
	Format string `bson:"format"    json:"format"`
	Size   string `bson:"size"      json:"size"`
}

type Feedback struct {
	Success bool   `json:"success"`
	Message string `json:"message"`
}

const (
	token_length = 40
	mongodb_host = "localhost"
	mongodb_db   = "Alexandria"
)

func randtoken(length int) string {

	const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%&?"
	var bytes = make([]byte, length)

	rand.Read(bytes)

	for i, b := range bytes {
		bytes[i] = alphanum[b%byte(len(alphanum))]
	}

	return string(bytes)

}

func main() {

	session, err := mgo.Dial(mongodb_host)

	if err != nil {
		panic(err)
	}

	defer session.Close()

	session.SetMode(mgo.Monotonic, true)

	db := session.DB(mongodb_db)

	m := martini.Classic()
	m.Use(render.Renderer())

	m.Post("/api/portal/login/", func(req *http.Request, r render.Render) {

		username := req.PostFormValue("username")
		password := req.PostFormValue("password")

		if (username == "") || (password == "") {
			feedback := Feedback{}
			feedback.Success = false
			feedback.Message = "The form is not completely filled out."
			r.JSON(400, feedback)
		} else {
			n, err := db.C("Users").Find(bson.M{"username": username}).Count()

			if err != nil {
				panic(err)
			}

			if n != 1 {
				feedback := Feedback{}
				feedback.Success = false
				feedback.Message = "The username '" + username + "' is not registered."
				r.JSON(403, feedback)
			} else {
				user := User{}

				err = db.C("Users").Find(bson.M{"username": username}).One(&user)

				if err != nil {
					panic(err)
				}

				err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))

				if err == nil {
					token := Token{}
					token.Token = randtoken(token_length)

					user.Tokens = append(user.Tokens, token)

					err := db.C("Users").Update(bson.M{"_id": user.Id}, user)

					if err != nil {
						panic(err)
					}

					r.JSON(200, token)
				} else {
					feedback := Feedback{}
					feedback.Success = false
					feedback.Message = "The username and password did not match."
					r.JSON(403, feedback)
				}
			}
		}

	})

	m.Get("/books/", func(req *http.Request, r render.Render) {

		user := User{}
		token := req.URL.Query().Get("token")
		genre := req.URL.Query().Get("genre")
		author := req.URL.Query().Get("author")

		n, err := db.C("Users").Find(bson.M{"tokens.token": token}).Count()

		if err != nil {
			panic(err)
		}

		if n == 0 {
			r.JSON(403, nil)
		} else {
			err = db.C("Users").Find(bson.M{"tokens.token": token}).One(&user)

			if err != nil {
				panic(err)
			}

			result := []Book{}

			fmt.Println(user.Id.Hex())

			if (genre == "") && (author == "") {
				err = db.C("Books").Find(bson.M{"owner": user.Id.Hex()}).All(&result)
			} else if genre != "" {
				err = db.C("Books").Find(bson.M{"owner": user.Id.Hex(), "genres": genre}).All(&result)
			} else if author != "" {
				err = db.C("Books").Find(bson.M{"owner": user.Id.Hex(), "authors": author}).All(&result)
			}

			if err != nil {
				panic(err)
			}

			r.JSON(200, result)
		}

	})

	m.Run()
}
<|endoftext|>


<commit_before>//
//
//
//

package gdbm

// #cgo CFLAGS: -std=gnu99
// #cgo LDFLAGS: -lgdbm
// #include <stdlib.h>
// #include <gdbm.h>
// #include <string.h>
// inline datum mk_datum(char * s) {
//     datum d;
//     d.dptr = s;
//     d.dsize = strlen(s);
//     return d;
// }
import "C"

import (
    "errors"
    "unsafe"
)

//
type Database struct {
    dbf C.GDBM_FILE
}

//
type DatabaseCfg struct {
    Mode string
    BlockSize int
    Permissions int
}

func lastError() error {
    return errors.New(C.GoString(C.gdbm_strerror(C.gdbm_errno)))
}

// Simple function to open a database file with default parameters (block size
// is default for the filesystem and file permissions are set to 0666).
func Open(filename string, mode string) (db * Database, err error) {
    return OpenWithCfg(filename, DatabaseCfg{mode, 0, 0666})
}

func OpenWithCfg(filename string, cfg DatabaseCfg) (db * Database, err error) {
    var m int
    switch cfg.Mode {
    case "r": m = C.GDBM_READER
    case "w": m = C.GDBM_WRITER
    case "c": m = C.GDBM_WRCREAT
    case "n": m = C.GDBM_NEWDB
    }

    cs := C.CString(filename)
    defer C.free(unsafe.Pointer(cs))

    db.dbf = C.gdbm_open(cs, C.int(cfg.BlockSize), C.int(m), C.int(cfg.Permissions), nil)
    if db.dbf == nil {
        err = lastError()
    }
    return db, err
}

// Closes a database file.
func (db * Database) Close() {
    C.gdbm_close(db.dbf)
}

//
func (db * Database) update(key string, value string, flag C.int) (err error) {
    kcs := C.CString(key)
    vcs := C.CString(value)
    k := C.mk_datum(kcs)
    v := C.mk_datum(vcs)
    defer C.free(unsafe.Pointer(kcs))
    defer C.free(unsafe.Pointer(vcs))

    retv := C.gdbm_store(db.dbf, k, v, flag)
    if retv != 0 {
        err = lastError()
    }
    return err
}

//
func (db * Database) Insert(key string, value string) (err error) {
    return db.update(key, value, C.GDBM_INSERT)
}

//
func (db * Database) Replace(key string, value string) (err error) {
    return db.update(key, value, C.GDBM_REPLACE)
}

func (db * Database) Exists(key string) bool {
    kcs := C.CString(key)
    k := C.mk_datum(kcs)
    defer C.free(unsafe.Pointer(kcs))

    e := C.gdbm_exists(db.dbf, k)
    if e == 1 {
        return true
    }
    return false
}

func (db * Database) Fetch() {}

func (db * Database) Delete() {}

func (db * Database) Reorganize() {}

func (db * Database) Sync() {}
<commit_msg>Reorganize() and Sync()<commit_after>//
//
//
//

package gdbm

// #cgo CFLAGS: -std=gnu99
// #cgo LDFLAGS: -lgdbm
// #include <stdlib.h>
// #include <gdbm.h>
// #include <string.h>
// inline datum mk_datum(char * s) {
//     datum d;
//     d.dptr = s;
//     d.dsize = strlen(s);
//     return d;
// }
import "C"

import (
    "errors"
    "unsafe"
)

//
type Database struct {
    dbf C.GDBM_FILE
}

//
type DatabaseCfg struct {
    Mode string
    BlockSize int
    Permissions int
}

func lastError() error {
    return errors.New(C.GoString(C.gdbm_strerror(C.gdbm_errno)))
}

// Simple function to open a database file with default parameters (block size
// is default for the filesystem and file permissions are set to 0666).
func Open(filename string, mode string) (db * Database, err error) {
    return OpenWithCfg(filename, DatabaseCfg{mode, 0, 0666})
}

func OpenWithCfg(filename string, cfg DatabaseCfg) (db * Database, err error) {
    var m int
    switch cfg.Mode {
    case "r": m = C.GDBM_READER
    case "w": m = C.GDBM_WRITER
    case "c": m = C.GDBM_WRCREAT
    case "n": m = C.GDBM_NEWDB
    }

    cs := C.CString(filename)
    defer C.free(unsafe.Pointer(cs))

    db.dbf = C.gdbm_open(cs, C.int(cfg.BlockSize), C.int(m), C.int(cfg.Permissions), nil)
    if db.dbf == nil {
        err = lastError()
    }
    return db, err
}

// Closes a database file.
func (db * Database) Close() {
    C.gdbm_close(db.dbf)
}

//
func (db * Database) update(key string, value string, flag C.int) (err error) {
    kcs := C.CString(key)
    vcs := C.CString(value)
    k := C.mk_datum(kcs)
    v := C.mk_datum(vcs)
    defer C.free(unsafe.Pointer(kcs))
    defer C.free(unsafe.Pointer(vcs))

    retv := C.gdbm_store(db.dbf, k, v, flag)
    if retv != 0 {
        err = lastError()
    }
    return err
}

//
func (db * Database) Insert(key string, value string) (err error) {
    return db.update(key, value, C.GDBM_INSERT)
}

//
func (db * Database) Replace(key string, value string) (err error) {
    return db.update(key, value, C.GDBM_REPLACE)
}

func (db * Database) Exists(key string) bool {
    kcs := C.CString(key)
    k := C.mk_datum(kcs)
    defer C.free(unsafe.Pointer(kcs))

    e := C.gdbm_exists(db.dbf, k)
    if e == 1 {
        return true
    }
    return false
}

func (db * Database) Fetch() {}

func (db * Database) Delete() {}

func (db * Database) Reorganize() {
    C.gdbm_reorganize(db.dbf)
}

func (db * Database) Sync() {
    C.gdbm_sync(db.dbf)
}
<|endoftext|>


<commit_before>package cloudca

import(
  "fmt"
  "github.com/cloud-ca/go-cloudca"
  "github.com/cloud-ca/go-cloudca/api"
  "github.com/cloud-ca/go-cloudca/services/cloudca"
  "github.com/hashicorp/terraform/helper/schema"
  "log"
  "strings"
)

func resourceCloudcaVolume() *schema.Resource {
  return &schema.Resource {
    Create : resourceCloudcaVolumeCreate,
    Read : resourceCloudcaVolumeRead,
    Update : resourceCloudcaVolumeUpdate,
    Delete : resourceCloudcaVolumeDelete,

    Schema: map[string]*schema.Schema {
      "service_code": &schema.Schema {
        Type:        schema.TypeString,
        Required:    true,
        ForceNew:    true,
        Description: "A cloudca service code",
      },
      "environment_name": &schema.Schema {
        Type:        schema.TypeString,
        Required:    true,
        ForceNew:    true,
        Description: "Name of environment where port forwarding rule should be created",
      },
      "name" : &schema.Schema {
        Type:        schema.TypeString,
        Required:    true,
        ForceNew:    true,
        Description: "The name of the volume to be created",
      },
      "zone_name": &schema.Schema {
        Type:        schema.TypeString,
        Optional:    true,
        ForceNew:    true,
        Description: "The zone into which the volume will be create",
      },
      "storage_tier" : &schema.Schema {
        Type:        schema.TypeString,
        Required:    true,
        ForceNew:    true,
        Description: "The storage tier name",
      },
      "size" : &schema.Schema {
        Type:        schema.TypeInt,
        Required:    true,
        ForceNew:    true,
        Description: "The size of the disk volume in gigabytes",
      },
      "instance_id" : &schema.Schema {
        Type:        schema.TypeString,
        Optional:    true,
        Description: "The id of the instance to which the volume should be attached",
      },
    },
  }
}

func resourceCloudcaVolumeCreate(d *schema.ResourceData, meta interface{}) error {
  ccaClient := meta.(*cca.CcaClient)
  resources, _ := ccaClient.GetResources(d.Get("service_code").(string), d.Get("environment_name").(string))
  ccaResources := resources.(cloudca.Resources)

  storageTier := d.Get("storage_tier").(string)
  size := d.Get("size").(int)
  diskOfferingId, err := retrieveDiskOfferingId(&ccaResources,storageTier,size)
  if(err != nil) {
    return err
  }
  volumeToCreate := cloudca.Volume{
    Name: d.Get("name").(string),
    DiskOfferingId : diskOfferingId,
  }

  if instanceId, ok := d.GetOk("instance_id"); ok {
    volumeToCreate.InstanceId = instanceId.(string)
  }
  if zoneName, ok := d.GetOk("zone_name"); ok {
    volumeToCreate.ZoneName = zoneName.(string)
  }

  newVolume, err := ccaResources.Volumes.Create(volumeToCreate)
  if(err != nil) {
    return fmt.Errorf("Error creating the new volume %s", err)
  }
  d.SetId(newVolume.Id)
  return resourceCloudcaPublicIpRead(d, meta)
}

func resourceCloudcaVolumeRead(d *schema.ResourceData, meta interface{}) error {
  ccaClient := meta.(*cca.CcaClient)
	resources, _ := ccaClient.GetResources(d.Get("service_code").(string), d.Get("environment_name").(string))
	ccaResources := resources.(cloudca.Resources)

  volume, err := ccaResources.Volumes.Get(d.Id())
  if(err != nil) {
    return handleVolumeNotFoundError(err, d)
  }
  d.Set("name", volume.Name)
  d.Set("zone_name", volume.ZoneName)
  d.Set("storage_tier", volume.StorageTier)
  d.Set("size", volume.Size)
  d.Set("instance_id", volume.InstanceId)
  return nil
}

func resourceCloudcaVolumeUpdate(d *schema.ResourceData, meta interface{}) error {
  ccaClient := meta.(*cca.CcaClient)
	resources, _ := ccaClient.GetResources(d.Get("service_code").(string), d.Get("environment_name").(string))
	ccaResources := resources.(cloudca.Resources)

  d.Partial(true)

  if d.HasChange("instanceId") {
    oldInstanceId,newInstanceId := d.GetChange("instance_id")
    if volume, err := ccaResources.Volumes.Get(d.Id()); err != nil {
      if nerr := handleVolumeNotFoundError(err, d); nerr != nil {
        return nerr
      }
      if (oldInstanceId == nil) {
        log.Printf("[DEBUG] Instance Id %s detected. Attaching volume to instance.", newInstanceId)
        if aerr := ccaResources.Volumes.AttachToInstance(volume, newInstanceId.(string)); aerr != nil {
          return aerr
        }

      } else {
        log.Printf("[DEBUG] Instance Id has changed from %s, to %s. Attempting attach volume to new instance", oldInstanceId, newInstanceId)
        if derr := ccaResources.Volumes.DetachFromInstance(volume); derr != nil {
          return derr
        }
        if aerr := ccaResources.Volumes.AttachToInstance(volume, newInstanceId.(string)); aerr != nil {
          return aerr
        }
      }
      d.SetPartial("instance_id")
    }
  }
  d.Partial(false)
  return nil
}

func resourceCloudcaVolumeDelete(d *schema.ResourceData, meta interface{}) error {
  ccaClient := meta.(*cca.CcaClient)
	resources, _ := ccaClient.GetResources(d.Get("service_code").(string), d.Get("environment_name").(string))
	ccaResources := resources.(cloudca.Resources)

  fmt.Println("[INFO] Deleting volume: %s", d.Get("name").(string))
  if derr := ccaResources.Volumes.Delete(d.Id()); derr != nil {
    if ccaError, ok := derr.(api.CcaErrorResponse); ok {
      handleVolumeNotFoundError(ccaError, d)
    }
  }
  return nil
}

func retrieveDiskOfferingId(ccaResources *cloudca.Resources, storageTier string, size int) (id string, err error) {
  diskOfferings, err := ccaResources.DiskOfferings.List()
  if(err != nil) {
    return "", err
  }
  for _,diskOffering := range diskOfferings {
    if(strings.EqualFold(diskOffering.StorageTier, storageTier)) {
      if(diskOffering.GbSize == size) {
        return diskOffering.Id, nil
      } else {
        //is custom?
      }
    }
  }
  return "", fmt.Errorf("No valid disk offering's were found with storage tier: %s and size: %s", storageTier, size)
}

func handleVolumeNotFoundError(err error, d *schema.ResourceData) error {
  if ccaError, ok := err.(api.CcaErrorResponse); ok {
    if ccaError.StatusCode == 404 {
      fmt.Errorf("Volume with id='%s' was not found", d.Id())
      d.SetId("")
      return nil
    }
  }
  return err
}
<commit_msg>Updated to use size string<commit_after>package cloudca

import(
  "fmt"
  "github.com/cloud-ca/go-cloudca"
  "github.com/cloud-ca/go-cloudca/api"
  "github.com/cloud-ca/go-cloudca/services/cloudca"
  "github.com/hashicorp/terraform/helper/schema"
  "log"
  "strings"
)

func resourceCloudcaVolume() *schema.Resource {
  return &schema.Resource {
    Create : resourceCloudcaVolumeCreate,
    Read : resourceCloudcaVolumeRead,
    Update : resourceCloudcaVolumeUpdate,
    Delete : resourceCloudcaVolumeDelete,

    Schema: map[string]*schema.Schema {
      "service_code": &schema.Schema {
        Type:        schema.TypeString,
        Required:    true,
        ForceNew:    true,
        Description: "A cloudca service code",
      },
      "environment_name": &schema.Schema {
        Type:        schema.TypeString,
        Required:    true,
        ForceNew:    true,
        Description: "Name of environment where port forwarding rule should be created",
      },
      "name" : &schema.Schema {
        Type:        schema.TypeString,
        Required:    true,
        ForceNew:    true,
        Description: "The name of the volume to be created",
      },
      "zone_name": &schema.Schema {
        Type:        schema.TypeString,
        Optional:    true,
        ForceNew:    true,
        Description: "The zone into which the volume will be create",
      },
      "storage_tier" : &schema.Schema {
        Type:        schema.TypeString,
        Required:    true,
        ForceNew:    true,
        Description: "The storage tier name",
      },
      "size" : &schema.Schema {
        Type:        schema.TypeString,
        Required:    true,
        ForceNew:    true,
        Description: "The size of the disk volume in gigabytes",
      },
      "instance_id" : &schema.Schema {
        Type:        schema.TypeString,
        Optional:    true,
        Description: "The id of the instance to which the volume should be attached",
      },
    },
  }
}

func resourceCloudcaVolumeCreate(d *schema.ResourceData, meta interface{}) error {
  ccaClient := meta.(*cca.CcaClient)
  resources, _ := ccaClient.GetResources(d.Get("service_code").(string), d.Get("environment_name").(string))
  ccaResources := resources.(cloudca.Resources)

  storageTier := d.Get("storage_tier").(string)
  size := d.Get("size").(string)
  diskOfferingId, err := retrieveDiskOfferingId(&ccaResources,storageTier,size)
  if(err != nil) {
    return err
  }
  volumeToCreate := cloudca.Volume{
    Name: d.Get("name").(string),
    DiskOfferingId : diskOfferingId,
  }

  if instanceId, ok := d.GetOk("instance_id"); ok {
    volumeToCreate.InstanceId = instanceId.(string)
  }
  if zoneName, ok := d.GetOk("zone_name"); ok {
    volumeToCreate.ZoneName = zoneName.(string)
  }

  newVolume, err := ccaResources.Volumes.Create(volumeToCreate)
  if(err != nil) {
    return fmt.Errorf("Error creating the new volume %s", err)
  }
  d.SetId(newVolume.Id)
  return resourceCloudcaPublicIpRead(d, meta)
}

func resourceCloudcaVolumeRead(d *schema.ResourceData, meta interface{}) error {
  ccaClient := meta.(*cca.CcaClient)
	resources, _ := ccaClient.GetResources(d.Get("service_code").(string), d.Get("environment_name").(string))
	ccaResources := resources.(cloudca.Resources)

  volume, err := ccaResources.Volumes.Get(d.Id())
  if(err != nil) {
    return handleVolumeNotFoundError(err, d)
  }
  d.Set("name", volume.Name)
  d.Set("zone_name", volume.ZoneName)
  d.Set("storage_tier", volume.StorageTier)
  d.Set("size", volume.Size)
  d.Set("instance_id", volume.InstanceId)
  return nil
}

func resourceCloudcaVolumeUpdate(d *schema.ResourceData, meta interface{}) error {
  ccaClient := meta.(*cca.CcaClient)
	resources, _ := ccaClient.GetResources(d.Get("service_code").(string), d.Get("environment_name").(string))
	ccaResources := resources.(cloudca.Resources)

  d.Partial(true)

  if d.HasChange("instanceId") {
    oldInstanceId,newInstanceId := d.GetChange("instance_id")
    if volume, err := ccaResources.Volumes.Get(d.Id()); err != nil {
      if nerr := handleVolumeNotFoundError(err, d); nerr != nil {
        return nerr
      }
      if (oldInstanceId == nil) {
        log.Printf("[DEBUG] Instance Id %s detected. Attaching volume to instance.", newInstanceId)
        if aerr := ccaResources.Volumes.AttachToInstance(volume, newInstanceId.(string)); aerr != nil {
          return aerr
        }

      } else {
        log.Printf("[DEBUG] Instance Id has changed from %s, to %s. Attempting attach volume to new instance", oldInstanceId, newInstanceId)
        if derr := ccaResources.Volumes.DetachFromInstance(volume); derr != nil {
          return derr
        }
        if aerr := ccaResources.Volumes.AttachToInstance(volume, newInstanceId.(string)); aerr != nil {
          return aerr
        }
      }
      d.SetPartial("instance_id")
    }
  }
  d.Partial(false)
  return nil
}

func resourceCloudcaVolumeDelete(d *schema.ResourceData, meta interface{}) error {
  ccaClient := meta.(*cca.CcaClient)
	resources, _ := ccaClient.GetResources(d.Get("service_code").(string), d.Get("environment_name").(string))
	ccaResources := resources.(cloudca.Resources)

  fmt.Println("[INFO] Deleting volume: %s", d.Get("name").(string))
  if derr := ccaResources.Volumes.Delete(d.Id()); derr != nil {
    return handleVolumeNotFoundError(derr, d)
  }
  return nil
}

func retrieveDiskOfferingId(ccaResources *cloudca.Resources, storageTier string, size string) (id string, err error) {
  diskOfferings, err := ccaResources.DiskOfferings.List()
  if(err != nil) {
    return "", err
  }
  for _,diskOffering := range diskOfferings {
    if(strings.EqualFold(diskOffering.StorageTier, storageTier) && strings.EqualFold(diskOffering.Name,size)) {
      return diskOffering.Id, nil
    }
  }
  return "", fmt.Errorf("No valid disk offering's were found with storage tier: %s and size: %s", storageTier, size)
}

func handleVolumeNotFoundError(err error, d *schema.ResourceData) error {
  if ccaError, ok := err.(api.CcaErrorResponse); ok {
    if ccaError.StatusCode == 404 {
      fmt.Errorf("Volume with id='%s' was not found", d.Id())
      d.SetId("")
      return nil
    }
  }
  return err
}
<|endoftext|>