<commit_before>package application

import (
	"fmt"
	"strconv"

	"github.com/disintegration/imaging"
	"github.com/thoas/picfit/engine"
	"github.com/thoas/picfit/engine/backend"
	"github.com/thoas/picfit/image"
)

const (
	defaultUpscale = true
	defaultWidth   = 0
	defaultHeight  = 0
	defaultDegree  = 90
)

var formats = map[string]imaging.Format{
	"jpeg": imaging.JPEG,
	"jpg":  imaging.JPEG,
	"png":  imaging.PNG,
	"gif":  imaging.GIF,
	"bmp":  imaging.BMP,
}

type Parameters struct {
	Output     *image.ImageFile
	Operations []engine.EngineOperation
}

func NewParameters(e *engine.Engine, input *image.ImageFile, qs map[string]interface{}) (*Parameters, error) {
	format, ok := qs["fmt"].(string)
	filepath := input.Filepath

	if ok {
		if _, ok := engine.ContentTypes[format]; !ok {
			return nil, fmt.Errorf("Unknown format %s", format)
		}

	}

	if format == "" && e.Format != "" {
		format = e.Format
	}

	if format == "" {
		format = input.Format()
	}

	if format == "" {
		format = e.DefaultFormat
	}

	if format != input.Format() {
		index := len(filepath) - len(input.Format())

		filepath = filepath[:index] + format

		if contentType, ok := engine.ContentTypes[format]; ok {
			input.Headers["Content-Type"] = contentType
		}
	}

	output := &image.ImageFile{
		Source:   input.Source,
		Key:      input.Key,
		Headers:  input.Headers,
		Filepath: filepath,
	}

	var operations []engine.EngineOperation

	operation, ok := qs["op"].(engine.Operation)
	if ok {
		opts, err := newBackendOptions(e, operation, qs)
		if err != nil {
			return nil, err
		}

		opts.Format = formats[format]
		operations = append(operations, engine.EngineOperation{
			Options:   opts,
			Operation: operation,
		})
	}

	return &Parameters{
		Output:     output,
		Operations: operations,
	}, nil
}

func newBackendOptions(e *engine.Engine, operation engine.Operation, qs map[string]interface{}) (*backend.Options, error) {
	var (
		err     error
		quality int
		upscale = defaultUpscale
		height  = defaultHeight
		width   = defaultWidth
		degree  = defaultDegree
	)

	q, ok := qs["q"].(string)
	if ok {
		quality, err := strconv.Atoi(q)

		if err != nil {
			return nil, err
		}

		if quality > 100 {
			return nil, fmt.Errorf("Quality should be <= 100")
		}
	} else {
		quality = e.DefaultQuality
	}

	position, ok := qs["pos"].(string)
	if !ok && operation == engine.Flip {
		return nil, fmt.Errorf("Parameter \"pos\" not found in query string")
	}

	if deg, ok := qs["deg"].(string); ok {
		degree, err = strconv.Atoi(deg)
		if err != nil {
			return nil, err
		}
	}

	if up, ok := qs["upscale"].(string); ok {
		upscale, err = strconv.ParseBool(up)
		if err != nil {
			return nil, err
		}
	}

	if w, ok := qs["w"].(string); ok {
		width, err = strconv.Atoi(w)
		if err != nil {
			return nil, err
		}
	}

	if h, ok := qs["h"].(string); ok {
		height, err = strconv.Atoi(h)
		if err != nil {
			return nil, err
		}
	}

	return &backend.Options{
		Width:    width,
		Height:   height,
		Upscale:  upscale,
		Position: position,
		Quality:  quality,
		Degree:   degree,
	}, nil
}
<commit_msg>fix parameters<commit_after>package application

import (
	"fmt"
	"strconv"

	"github.com/disintegration/imaging"
	"github.com/thoas/picfit/engine"
	"github.com/thoas/picfit/engine/backend"
	"github.com/thoas/picfit/image"
)

const (
	defaultUpscale = true
	defaultWidth   = 0
	defaultHeight  = 0
	defaultDegree  = 90
)

var formats = map[string]imaging.Format{
	"jpeg": imaging.JPEG,
	"jpg":  imaging.JPEG,
	"png":  imaging.PNG,
	"gif":  imaging.GIF,
	"bmp":  imaging.BMP,
}

type Parameters struct {
	Output     *image.ImageFile
	Operations []engine.EngineOperation
}

func NewParameters(e *engine.Engine, input *image.ImageFile, qs map[string]interface{}) (*Parameters, error) {
	format, ok := qs["fmt"].(string)
	filepath := input.Filepath

	if ok {
		if _, ok := engine.ContentTypes[format]; !ok {
			return nil, fmt.Errorf("Unknown format %s", format)
		}

	}

	if format == "" && e.Format != "" {
		format = e.Format
	}

	if format == "" {
		format = input.Format()
	}

	if format == "" {
		format = e.DefaultFormat
	}

	if format != input.Format() {
		index := len(filepath) - len(input.Format())

		filepath = filepath[:index] + format

		if contentType, ok := engine.ContentTypes[format]; ok {
			input.Headers["Content-Type"] = contentType
		}
	}

	output := &image.ImageFile{
		Source:   input.Source,
		Key:      input.Key,
		Headers:  input.Headers,
		Filepath: filepath,
	}

	var operations []engine.EngineOperation

	op, ok := qs["op"].(string)
	if ok {
		operation := engine.Operation(op)
		opts, err := newBackendOptions(e, operation, qs)
		if err != nil {
			return nil, err
		}

		opts.Format = formats[format]
		operations = append(operations, engine.EngineOperation{
			Options:   opts,
			Operation: operation,
		})
	}

	return &Parameters{
		Output:     output,
		Operations: operations,
	}, nil
}

func newBackendOptions(e *engine.Engine, operation engine.Operation, qs map[string]interface{}) (*backend.Options, error) {
	var (
		err     error
		quality int
		upscale = defaultUpscale
		height  = defaultHeight
		width   = defaultWidth
		degree  = defaultDegree
	)

	q, ok := qs["q"].(string)
	if ok {
		quality, err := strconv.Atoi(q)

		if err != nil {
			return nil, err
		}

		if quality > 100 {
			return nil, fmt.Errorf("Quality should be <= 100")
		}
	} else {
		quality = e.DefaultQuality
	}

	position, ok := qs["pos"].(string)
	if !ok && operation == engine.Flip {
		return nil, fmt.Errorf("Parameter \"pos\" not found in query string")
	}

	if deg, ok := qs["deg"].(string); ok {
		degree, err = strconv.Atoi(deg)
		if err != nil {
			return nil, err
		}
	}

	if up, ok := qs["upscale"].(string); ok {
		upscale, err = strconv.ParseBool(up)
		if err != nil {
			return nil, err
		}
	}

	if w, ok := qs["w"].(string); ok {
		width, err = strconv.Atoi(w)
		if err != nil {
			return nil, err
		}
	}

	if h, ok := qs["h"].(string); ok {
		height, err = strconv.Atoi(h)
		if err != nil {
			return nil, err
		}
	}

	return &backend.Options{
		Width:    width,
		Height:   height,
		Upscale:  upscale,
		Position: position,
		Quality:  quality,
		Degree:   degree,
	}, nil
}
<|endoftext|>


<commit_before>package google

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"os"

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

	"google.golang.org/api/googleapi"
	"google.golang.org/api/storage/v1"
)

func resourceStorageBucketObject() *schema.Resource {
	return &schema.Resource{
		Create: resourceStorageBucketObjectCreate,
		Read:   resourceStorageBucketObjectRead,
		Delete: resourceStorageBucketObjectDelete,

		Schema: map[string]*schema.Schema{
			"bucket": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"content": &schema.Schema{
				Type:          schema.TypeString,
				Optional:      true,
				ForceNew:      true,
				ConflictsWith: []string{"source"},
			},

			"crc32c": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"md5hash": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"predefined_acl": &schema.Schema{
				Type:       schema.TypeString,
				Deprecated: "Please use resource \"storage_object_acl.predefined_acl\" instead.",
				Optional:   true,
				ForceNew:   true,
			},

			"source": &schema.Schema{
				Type:          schema.TypeString,
				Optional:      true,
				ForceNew:      true,
				ConflictsWith: []string{"content"},
			},
		},
	}
}

func objectGetId(object *storage.Object) string {
	return object.Bucket + "-" + object.Name
}

func resourceStorageBucketObjectCreate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	bucket := d.Get("bucket").(string)
	name := d.Get("name").(string)
	var media io.Reader

	if v, ok := d.GetOk("source"); ok {
		err := error(nil)
		media, err = os.Open(v.(string))
		if err != nil {
			return err
		}
	} else if v, ok := d.GetOk("content"); ok {
		media = bytes.NewReader([]byte(v.(string)))
	} else {
		return fmt.Errorf("Error, either \"content\" or \"string\" must be specified")
	}

	objectsService := storage.NewObjectsService(config.clientStorage)
	object := &storage.Object{Bucket: bucket}

	insertCall := objectsService.Insert(bucket, object)
	insertCall.Name(name)
	insertCall.Media(media)
	if v, ok := d.GetOk("predefined_acl"); ok {
		insertCall.PredefinedAcl(v.(string))
	}

	_, err := insertCall.Do()

	if err != nil {
		return fmt.Errorf("Error uploading object %s: %s", name, err)
	}

	return resourceStorageBucketObjectRead(d, meta)
}

func resourceStorageBucketObjectRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	bucket := d.Get("bucket").(string)
	name := d.Get("name").(string)

	objectsService := storage.NewObjectsService(config.clientStorage)
	getCall := objectsService.Get(bucket, name)

	res, err := getCall.Do()

	if err != nil {
		if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
			log.Printf("[WARN] Removing Bucket Object %q because it's gone", d.Get("name").(string))
			// The resource doesn't exist anymore
			d.SetId("")

			return nil
		}

		return fmt.Errorf("Error retrieving contents of object %s: %s", name, err)
	}

	d.Set("md5hash", res.Md5Hash)
	d.Set("crc32c", res.Crc32c)

	d.SetId(objectGetId(res))

	return nil
}

func resourceStorageBucketObjectDelete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	bucket := d.Get("bucket").(string)
	name := d.Get("name").(string)

	objectsService := storage.NewObjectsService(config.clientStorage)

	DeleteCall := objectsService.Delete(bucket, name)
	err := DeleteCall.Do()

	if err != nil {
		return fmt.Errorf("Error deleting contents of object %s: %s", name, err)
	}

	return nil
}
<commit_msg>Handle `google_storage_bucket_object` not being found (#14203)<commit_after>package google

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"os"

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

	"google.golang.org/api/googleapi"
	"google.golang.org/api/storage/v1"
)

func resourceStorageBucketObject() *schema.Resource {
	return &schema.Resource{
		Create: resourceStorageBucketObjectCreate,
		Read:   resourceStorageBucketObjectRead,
		Delete: resourceStorageBucketObjectDelete,

		Schema: map[string]*schema.Schema{
			"bucket": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"content": &schema.Schema{
				Type:          schema.TypeString,
				Optional:      true,
				ForceNew:      true,
				ConflictsWith: []string{"source"},
			},

			"crc32c": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"md5hash": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"predefined_acl": &schema.Schema{
				Type:       schema.TypeString,
				Deprecated: "Please use resource \"storage_object_acl.predefined_acl\" instead.",
				Optional:   true,
				ForceNew:   true,
			},

			"source": &schema.Schema{
				Type:          schema.TypeString,
				Optional:      true,
				ForceNew:      true,
				ConflictsWith: []string{"content"},
			},
		},
	}
}

func objectGetId(object *storage.Object) string {
	return object.Bucket + "-" + object.Name
}

func resourceStorageBucketObjectCreate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	bucket := d.Get("bucket").(string)
	name := d.Get("name").(string)
	var media io.Reader

	if v, ok := d.GetOk("source"); ok {
		err := error(nil)
		media, err = os.Open(v.(string))
		if err != nil {
			return err
		}
	} else if v, ok := d.GetOk("content"); ok {
		media = bytes.NewReader([]byte(v.(string)))
	} else {
		return fmt.Errorf("Error, either \"content\" or \"string\" must be specified")
	}

	objectsService := storage.NewObjectsService(config.clientStorage)
	object := &storage.Object{Bucket: bucket}

	insertCall := objectsService.Insert(bucket, object)
	insertCall.Name(name)
	insertCall.Media(media)
	if v, ok := d.GetOk("predefined_acl"); ok {
		insertCall.PredefinedAcl(v.(string))
	}

	_, err := insertCall.Do()

	if err != nil {
		return fmt.Errorf("Error uploading object %s: %s", name, err)
	}

	return resourceStorageBucketObjectRead(d, meta)
}

func resourceStorageBucketObjectRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	bucket := d.Get("bucket").(string)
	name := d.Get("name").(string)

	objectsService := storage.NewObjectsService(config.clientStorage)
	getCall := objectsService.Get(bucket, name)

	res, err := getCall.Do()

	if err != nil {
		if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
			log.Printf("[WARN] Removing Bucket Object %q because it's gone", d.Get("name").(string))
			// The resource doesn't exist anymore
			d.SetId("")

			return nil
		}

		return fmt.Errorf("Error retrieving contents of object %s: %s", name, err)
	}

	d.Set("md5hash", res.Md5Hash)
	d.Set("crc32c", res.Crc32c)

	d.SetId(objectGetId(res))

	return nil
}

func resourceStorageBucketObjectDelete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	bucket := d.Get("bucket").(string)
	name := d.Get("name").(string)

	objectsService := storage.NewObjectsService(config.clientStorage)

	DeleteCall := objectsService.Delete(bucket, name)
	err := DeleteCall.Do()

	if err != nil {
		if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
			log.Printf("[WARN] Removing Bucket Object %q because it's gone", name)
			// The resource doesn't exist anymore
			d.SetId("")

			return nil
		}

		return fmt.Errorf("Error deleting contents of object %s: %s", name, err)
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2009 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 dwarf

import (
	"sort"
	"strconv"
)

// DWARF debug info is split into a sequence of compilation units.
// Each unit has its own abbreviation table and address size.

type unit struct {
	base   Offset // byte offset of header within the aggregate info
	off    Offset // byte offset of data within the aggregate info
	data   []byte
	atable abbrevTable
	asize  int
	vers   int
	utype  uint8 // DWARF 5 unit type
	is64   bool  // True for 64-bit DWARF format
}

// Implement the dataFormat interface.

func (u *unit) version() int {
	return u.vers
}

func (u *unit) dwarf64() (bool, bool) {
	return u.is64, true
}

func (u *unit) addrsize() int {
	return u.asize
}

func (d *Data) parseUnits() ([]unit, error) {
	// Count units.
	nunit := 0
	b := makeBuf(d, unknownFormat{}, "info", 0, d.info)
	for len(b.data) > 0 {
		len, _ := b.unitLength()
		if len != Offset(uint32(len)) {
			b.error("unit length overflow")
			break
		}
		b.skip(int(len))
		nunit++
	}
	if b.err != nil {
		return nil, b.err
	}

	// Again, this time writing them down.
	b = makeBuf(d, unknownFormat{}, "info", 0, d.info)
	units := make([]unit, nunit)
	for i := range units {
		u := &units[i]
		u.base = b.off
		var n Offset
		n, u.is64 = b.unitLength()
		dataOff := b.off
		vers := b.uint16()
		if vers < 2 || vers > 5 {
			b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
			break
		}
		u.vers = int(vers)
		if vers >= 5 {
			u.utype = b.uint8()
			u.asize = int(b.uint8())
		}
		var abbrevOff uint64
		if u.is64 {
			abbrevOff = b.uint64()
		} else {
			abbrevOff = uint64(b.uint32())
		}
		atable, err := d.parseAbbrev(abbrevOff, u.vers)
		if err != nil {
			if b.err == nil {
				b.err = err
			}
			break
		}
		u.atable = atable
		if vers < 5 {
			u.asize = int(b.uint8())
		}

		switch u.utype {
		case utSkeleton, utSplitCompile:
			b.uint64() // unit ID
		case utType, utSplitType:
			b.uint64()  // type signature
			if u.is64 { // type offset
				b.uint64()
			} else {
				b.uint32()
			}
		}

		u.off = b.off
		u.data = b.bytes(int(n - (b.off - dataOff)))
	}
	if b.err != nil {
		return nil, b.err
	}
	return units, nil
}

// offsetToUnit returns the index of the unit containing offset off.
// It returns -1 if no unit contains this offset.
func (d *Data) offsetToUnit(off Offset) int {
	// Find the unit after off
	next := sort.Search(len(d.unit), func(i int) bool {
		return d.unit[i].off > off
	})
	if next == 0 {
		return -1
	}
	u := &d.unit[next-1]
	if u.off <= off && off < u.off+Offset(len(u.data)) {
		return next - 1
	}
	return -1
}
<commit_msg>debug/dwarf: skip over zero-length compilation units<commit_after>// Copyright 2009 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 dwarf

import (
	"sort"
	"strconv"
)

// DWARF debug info is split into a sequence of compilation units.
// Each unit has its own abbreviation table and address size.

type unit struct {
	base   Offset // byte offset of header within the aggregate info
	off    Offset // byte offset of data within the aggregate info
	data   []byte
	atable abbrevTable
	asize  int
	vers   int
	utype  uint8 // DWARF 5 unit type
	is64   bool  // True for 64-bit DWARF format
}

// Implement the dataFormat interface.

func (u *unit) version() int {
	return u.vers
}

func (u *unit) dwarf64() (bool, bool) {
	return u.is64, true
}

func (u *unit) addrsize() int {
	return u.asize
}

func (d *Data) parseUnits() ([]unit, error) {
	// Count units.
	nunit := 0
	b := makeBuf(d, unknownFormat{}, "info", 0, d.info)
	for len(b.data) > 0 {
		len, _ := b.unitLength()
		if len != Offset(uint32(len)) {
			b.error("unit length overflow")
			break
		}
		b.skip(int(len))
		if len > 0 {
			nunit++
		}
	}
	if b.err != nil {
		return nil, b.err
	}

	// Again, this time writing them down.
	b = makeBuf(d, unknownFormat{}, "info", 0, d.info)
	units := make([]unit, nunit)
	for i := range units {
		u := &units[i]
		u.base = b.off
		var n Offset
		for n == 0 {
			n, u.is64 = b.unitLength()
		}
		dataOff := b.off
		vers := b.uint16()
		if vers < 2 || vers > 5 {
			b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
			break
		}
		u.vers = int(vers)
		if vers >= 5 {
			u.utype = b.uint8()
			u.asize = int(b.uint8())
		}
		var abbrevOff uint64
		if u.is64 {
			abbrevOff = b.uint64()
		} else {
			abbrevOff = uint64(b.uint32())
		}
		atable, err := d.parseAbbrev(abbrevOff, u.vers)
		if err != nil {
			if b.err == nil {
				b.err = err
			}
			break
		}
		u.atable = atable
		if vers < 5 {
			u.asize = int(b.uint8())
		}

		switch u.utype {
		case utSkeleton, utSplitCompile:
			b.uint64() // unit ID
		case utType, utSplitType:
			b.uint64()  // type signature
			if u.is64 { // type offset
				b.uint64()
			} else {
				b.uint32()
			}
		}

		u.off = b.off
		u.data = b.bytes(int(n - (b.off - dataOff)))
	}
	if b.err != nil {
		return nil, b.err
	}
	return units, nil
}

// offsetToUnit returns the index of the unit containing offset off.
// It returns -1 if no unit contains this offset.
func (d *Data) offsetToUnit(off Offset) int {
	// Find the unit after off
	next := sort.Search(len(d.unit), func(i int) bool {
		return d.unit[i].off > off
	})
	if next == 0 {
		return -1
	}
	u := &d.unit[next-1]
	if u.off <= off && off < u.off+Offset(len(u.data)) {
		return next - 1
	}
	return -1
}
<|endoftext|>


<commit_before>// Package server contains handlers which respond to requests to combine
// pdf files and hands them off to the combiner package.
// TODO more informative validation errors
package server

import (
	"fmt"
	"github.com/PeopleAdmin/pdfcombiner/combiner"
	"github.com/PeopleAdmin/pdfcombiner/job"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strconv"
	"sync"
	"syscall"
)

// A CombinerServer needs a port to listen on and a WaitGroup to keep
// track of how many background jobs it has spawned that have not yet
// yet completed their work.
type CombinerServer struct {
	port    int
	pending *sync.WaitGroup
}

var invalidMessage = []byte("{\"response\":\"invalid params\"}\n")
var okMessage = []byte("{\"response\":\"ok\"}\n")
var host, _ = os.Hostname()

// Listen starts a HTTP server listening on `Port` to respond to
// JSON-formatted combination requests.
func (c CombinerServer) Listen(listenPort int) {
	c.port = listenPort
	c.pending = new(sync.WaitGroup)
	listener, err := net.Listen("tcp", c.portString())
	if err != nil {
		panic(err)
	}
	println("Accepting connections on " + c.portString())
	c.registerHandlers(listener)
	http.Serve(listener, http.DefaultServeMux)
	println("Waiting for all jobs to finish...")
	c.pending.Wait()
}

// ProcessJob is a handler to recieve a JSON body encoding a Job.  If
// it validates, send it along to be fulfilled, keeping track of the
// in-flight job count.
func (c CombinerServer) ProcessJob(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.NotFound(w, r)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	if !authenticate(w,r) {
		return
	}
	j, err := job.NewFromJSON(r.Body)
	logJobReceipt(r, j)
	if err != nil || !j.IsValid() {
		w.WriteHeader(http.StatusBadRequest)
		w.Write(invalidMessage)
		return
	}
	w.Write(okMessage)
	c.registerWorker()
	go func() {
		defer c.unregisterWorker()
		combiner.Combine(j)
	}()
}

// Ping is no-op handler for responding to things like health checks.
// It responds 200 OK with no content to all requests.
func (c CombinerServer) Ping(w http.ResponseWriter, r *http.Request) {
	log.Println(requestInfo(r))
}

func (c CombinerServer) Status(w http.ResponseWriter, r *http.Request) {
	log.Println(requestInfo(r))
	w.Header().Set("Content-Type", "application/json")
	template := `{"host": "%s", "running": %d, "waiting": %d}` + "\n"
	jobs := fmt.Sprintf(template,
		host, combiner.CurrentJobs(), combiner.CurrentWait())
	w.Write([]byte(jobs))
}

func logJobReceipt(r *http.Request, j *job.Job) {
	log.Printf("%v, callback: %v, id: \n", requestInfo(r), j.Callback, j.Id)
}

func requestInfo(r *http.Request) string {
	return fmt.Sprintf("%v %v from %v", r.Method, r.URL, r.RemoteAddr)
}

// http.ListenAndServe needs a string for the port.
func (c CombinerServer) portString() string {
	return ":" + strconv.Itoa(c.port)
}

// registerWorker increments the count of in-progress jobs
func (c CombinerServer) registerWorker() {
	c.pending.Add(1)
}

// workerDone decrements the count of in-progress jobs.
func (c CombinerServer) unregisterWorker() {
	c.pending.Done()
}

func (c CombinerServer) registerHandlers(listener net.Listener) {
	http.HandleFunc("/health_check", c.Ping)
	http.HandleFunc("/status", c.Status)
	http.HandleFunc("/", c.ProcessJob)
	handleSignals(listener)
}

// On OS shutdown or Ctrl-C, immediately close the tcp listener,
// but let background jobs finish before actually exiting.
func handleSignals(listener net.Listener) {
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, os.Interrupt)
	signal.Notify(sigs, syscall.SIGTERM)
	go func() {
		for _ = range sigs {
			listener.Close()
		}
	}()
}
<commit_msg>Make POST logline format match other log entries<commit_after>// Package server contains handlers which respond to requests to combine
// pdf files and hands them off to the combiner package.
// TODO more informative validation errors
package server

import (
	"fmt"
	"github.com/PeopleAdmin/pdfcombiner/combiner"
	"github.com/PeopleAdmin/pdfcombiner/job"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strconv"
	"sync"
	"syscall"
)

// A CombinerServer needs a port to listen on and a WaitGroup to keep
// track of how many background jobs it has spawned that have not yet
// yet completed their work.
type CombinerServer struct {
	port    int
	pending *sync.WaitGroup
}

var invalidMessage = []byte("{\"response\":\"invalid params\"}\n")
var okMessage = []byte("{\"response\":\"ok\"}\n")
var host, _ = os.Hostname()

// Listen starts a HTTP server listening on `Port` to respond to
// JSON-formatted combination requests.
func (c CombinerServer) Listen(listenPort int) {
	c.port = listenPort
	c.pending = new(sync.WaitGroup)
	listener, err := net.Listen("tcp", c.portString())
	if err != nil {
		panic(err)
	}
	println("Accepting connections on " + c.portString())
	c.registerHandlers(listener)
	http.Serve(listener, http.DefaultServeMux)
	println("Waiting for all jobs to finish...")
	c.pending.Wait()
}

// ProcessJob is a handler to recieve a JSON body encoding a Job.  If
// it validates, send it along to be fulfilled, keeping track of the
// in-flight job count.
func (c CombinerServer) ProcessJob(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.NotFound(w, r)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	if !authenticate(w,r) {
		return
	}
	j, err := job.NewFromJSON(r.Body)
	logJobReceipt(r, j)
	if err != nil || !j.IsValid() {
		w.WriteHeader(http.StatusBadRequest)
		w.Write(invalidMessage)
		return
	}
	w.Write(okMessage)
	c.registerWorker()
	go func() {
		defer c.unregisterWorker()
		combiner.Combine(j)
	}()
}

// Ping is no-op handler for responding to things like health checks.
// It responds 200 OK with no content to all requests.
func (c CombinerServer) Ping(w http.ResponseWriter, r *http.Request) {
	log.Println(requestInfo(r))
}

func (c CombinerServer) Status(w http.ResponseWriter, r *http.Request) {
	log.Println(requestInfo(r))
	w.Header().Set("Content-Type", "application/json")
	template := `{"host": "%s", "running": %d, "waiting": %d}` + "\n"
	jobs := fmt.Sprintf(template,
		host, combiner.CurrentJobs(), combiner.CurrentWait())
	w.Write([]byte(jobs))
}

func logJobReceipt(r *http.Request, j *job.Job) {
	log.Printf("%s %v, callback: %s\n", j.Id(), requestInfo(r), j.Callback)
}

func requestInfo(r *http.Request) string {
	return fmt.Sprintf("%v %v from %v", r.Method, r.URL, r.RemoteAddr)
}

// http.ListenAndServe needs a string for the port.
func (c CombinerServer) portString() string {
	return ":" + strconv.Itoa(c.port)
}

// registerWorker increments the count of in-progress jobs
func (c CombinerServer) registerWorker() {
	c.pending.Add(1)
}

// workerDone decrements the count of in-progress jobs.
func (c CombinerServer) unregisterWorker() {
	c.pending.Done()
}

func (c CombinerServer) registerHandlers(listener net.Listener) {
	http.HandleFunc("/health_check", c.Ping)
	http.HandleFunc("/status", c.Status)
	http.HandleFunc("/", c.ProcessJob)
	handleSignals(listener)
}

// On OS shutdown or Ctrl-C, immediately close the tcp listener,
// but let background jobs finish before actually exiting.
func handleSignals(listener net.Listener) {
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, os.Interrupt)
	signal.Notify(sigs, syscall.SIGTERM)
	go func() {
		for _ = range sigs {
			listener.Close()
		}
	}()
}
<|endoftext|>


<commit_before>// Copyright 2011 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 template

import (
	"fmt"
	"html/template"
	"reflect"
)

type contentType uint8

const (
	contentTypePlain contentType = iota
	contentTypeCSS
	contentTypeHTML
	contentTypeHTMLAttr
	contentTypeJS
	contentTypeJSStr
	contentTypeURL
	// contentTypeUnsafe is used in attr.go for values that affect how
	// embedded content and network messages are formed, vetted,
	// or interpreted; or which credentials network messages carry.
	contentTypeUnsafe
)

// indirect returns the value, after dereferencing as many times
// as necessary to reach the base type (or nil).
func indirect(a interface{}) interface{} {
	if a == nil {
		return nil
	}
	if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr {
		// Avoid creating a reflect.Value if it's not a pointer.
		return a
	}
	v := reflect.ValueOf(a)
	for v.Kind() == reflect.Ptr && !v.IsNil() {
		v = v.Elem()
	}
	return v.Interface()
}

var (
	errorType       = reflect.TypeOf((*error)(nil)).Elem()
	fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
)

// indirectToStringerOrError returns the value, after dereferencing as many times
// as necessary to reach the base type (or nil) or an implementation of fmt.Stringer
// or error,
func indirectToStringerOrError(a interface{}) interface{} {
	if a == nil {
		return nil
	}
	v := reflect.ValueOf(a)
	for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() {
		v = v.Elem()
	}
	return v.Interface()
}

// stringify converts its arguments to a string and the type of the content.
// All pointers are dereferenced, as in the text/template package.
func stringify(args ...interface{}) (string, contentType) {
	if len(args) == 1 {
		switch s := indirect(args[0]).(type) {
		case string:
			return s, contentTypePlain
		case template.CSS:
			return string(s), contentTypeCSS
		case template.HTML:
			return string(s), contentTypeHTML
		case template.HTMLAttr:
			return string(s), contentTypeHTMLAttr
		case template.JS:
			return string(s), contentTypeJS
		case template.JSStr:
			return string(s), contentTypeJSStr
		case template.URL:
			return string(s), contentTypeURL
		}
	}
	for i, arg := range args {
		val := indirectToStringerOrError(arg)
		if val != nil {
			args[i] = val
		} else {
			args[i] = ""
		}
	}
	return fmt.Sprint(args...), contentTypePlain
}
<commit_msg>Add fast path for int and float64<commit_after>// Copyright 2011 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 template

import (
	"fmt"
	"html/template"
	"reflect"
	"strconv"
)

type contentType uint8

const (
	contentTypePlain contentType = iota
	contentTypeCSS
	contentTypeHTML
	contentTypeHTMLAttr
	contentTypeJS
	contentTypeJSStr
	contentTypeURL
	// contentTypeUnsafe is used in attr.go for values that affect how
	// embedded content and network messages are formed, vetted,
	// or interpreted; or which credentials network messages carry.
	contentTypeUnsafe
)

// indirect returns the value, after dereferencing as many times
// as necessary to reach the base type (or nil).
func indirect(a interface{}) interface{} {
	if a == nil {
		return nil
	}
	if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr {
		// Avoid creating a reflect.Value if it's not a pointer.
		return a
	}
	v := reflect.ValueOf(a)
	for v.Kind() == reflect.Ptr && !v.IsNil() {
		v = v.Elem()
	}
	return v.Interface()
}

var (
	errorType       = reflect.TypeOf((*error)(nil)).Elem()
	fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
)

// indirectToStringerOrError returns the value, after dereferencing as many times
// as necessary to reach the base type (or nil) or an implementation of fmt.Stringer
// or error,
func indirectToStringerOrError(a interface{}) interface{} {
	if a == nil {
		return nil
	}
	v := reflect.ValueOf(a)
	for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() {
		v = v.Elem()
	}
	return v.Interface()
}

// stringify converts its arguments to a string and the type of the content.
// All pointers are dereferenced, as in the text/template package.
func stringify(args ...interface{}) (string, contentType) {
	if len(args) == 1 {
		v := indirect(args[0])
		switch s := v.(type) {
		case string:
			return s, contentTypePlain
		case template.CSS:
			return string(s), contentTypeCSS
		case template.HTML:
			return string(s), contentTypeHTML
		case template.HTMLAttr:
			return string(s), contentTypeHTMLAttr
		case template.JS:
			return string(s), contentTypeJS
		case template.JSStr:
			return string(s), contentTypeJSStr
		case template.URL:
			return string(s), contentTypeURL
		case int:
			// return contentTypeHTML, since this does not
			// need escaping and is the most common context
			// in templates
			return strconv.Itoa(s), contentTypeHTML
		case float64:
			return strconv.FormatFloat(s, 'g', -1, 64), contentTypeHTML
		}
		return fmt.Sprint(indirectToStringerOrError(v)), contentTypePlain
	}
	for i, arg := range args {
		val := indirectToStringerOrError(arg)
		if val != nil {
			args[i] = val
		} else {
			args[i] = ""
		}
	}
	return fmt.Sprint(args...), contentTypePlain
}
<|endoftext|>


<commit_before>package main

// All actions under command marathon

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

// ping (todo ping all hosts)
type MarathonPing struct {
	client *Client
	format Formatter
}

func (p MarathonPing) Apply(args []string) {
	hosts := p.client.login.Hosts
	timings := make(map[string]time.Duration)
	for _, host := range hosts {
		request, e := http.NewRequest("GET", host+"/ping", nil)
		Check(e == nil, "could not create ping request", e)
		p.client.tweak(request)
		start := time.Now()
		_, err := p.client.client.Do(request)
		var elapsed time.Duration
		if err == nil {
			elapsed = time.Now().Sub(start)
		}
		timings[host] = elapsed
	}

	var b bytes.Buffer
	for host, duration := range timings {
		b.WriteString(host)
		b.WriteString(" ")
		if duration == 0 {
			b.WriteString("-")
		} else {
			b.WriteString(duration.String())
		}
		b.WriteString("\n")
	}
	fmt.Println(p.format.Format(strings.NewReader(b.String()), p.Humanize))
}

func (P MarathonPing) Humanize(body io.Reader) string {
	b, e := ioutil.ReadAll(body)
	Check(e == nil, "reading ping response failed", e)
	text := "HOST DURATION\n" + string(b)
	return Columnize(text)
}

// leader
type MarathonLeader struct {
	client *Client
	format Formatter
}

func (l MarathonLeader) Apply(args []string) {
	request := l.client.GET("/v2/leader")
	response, e := l.client.Do(request)
	Check(e == nil, "get leader failed", e)
	c := response.StatusCode
	Check(c == 200, "get leader bad status", c)
	defer response.Body.Close()
	fmt.Println(l.format.Format(response.Body, l.Humanize))
}

func (l MarathonLeader) Humanize(body io.Reader) string {
	dec := json.NewDecoder(body)
	var which Which
	e := dec.Decode(&which)
	Check(e == nil, "failed to decode response", e)
	text := "LEADER\n" + which.Leader
	return Columnize(text)
}

// abdicate
type MarathonAbdicate struct {
	client *Client
	format Formatter
}

func (a MarathonAbdicate) Apply(args []string) {
	request := a.client.DELETE("/v2/leader")
	response, e := a.client.Do(request)
	Check(e == nil, "abdicate request failed", e)
	c := response.StatusCode
	Check(c == 200, "abdicate bad status", c)
	defer response.Body.Close()
	fmt.Println(a.format.Format(response.Body, a.Humanize))
}

func (a MarathonAbdicate) Humanize(body io.Reader) string {
	dec := json.NewDecoder(body)
	var mess Message
	e := dec.Decode(&mess)
	Check(e == nil, "failed to decode response", e)
	return "MESSAGE\n" + mess.Message
}
<commit_msg>Make ping return JSON<commit_after>package main

// All actions under command marathon

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"
)

// ping (todo ping all hosts)
type MarathonPing struct {
	client *Client
	format Formatter
}

type MarathonPingResult struct {
	Host     string        `json:"host"`
	Duration time.Duration `json:"duration"`
}

type MarathonPingResultList []MarathonPingResult

func (p MarathonPing) Apply(args []string) {
	hosts := p.client.login.Hosts
	timings := make(map[string]time.Duration)
	for _, host := range hosts {
		request, e := http.NewRequest("GET", host+"/ping", nil)
		Check(e == nil, "could not create ping request", e)
		p.client.tweak(request)
		start := time.Now()
		_, err := p.client.client.Do(request)
		var elapsed time.Duration
		if err == nil {
			elapsed = time.Now().Sub(start)
		}
		timings[host] = elapsed
	}

	pingResultList := make([]MarathonPingResult, len(hosts))

	i := 0
	for host, duration := range timings {
		pingResultList[i] = MarathonPingResult{Host: host, Duration: duration}
		i += 1
	}
	jsonBytes, e := json.Marshal(pingResultList)
	Check(e == nil, "failed to marshal response", e)
	fmt.Println(p.format.Format(strings.NewReader(string(jsonBytes)), p.Humanize))
}

func (P MarathonPing) Humanize(body io.Reader) string {
	dec := json.NewDecoder(body)
	var pingResults MarathonPingResultList
	e := dec.Decode(&pingResults)
	Check(e == nil, "failed to unmarshal response", e)
	title := "HOST DURATION\n"
	var b bytes.Buffer
	for _, pingResult := range pingResults {
		b.WriteString(pingResult.Host)
		b.WriteString(" ")
		b.WriteString(pingResult.Duration.String())
		b.WriteString("\n")
	}
	text := title + b.String()
	return Columnize(text)
}

// leader
type MarathonLeader struct {
	client *Client
	format Formatter
}

func (l MarathonLeader) Apply(args []string) {
	request := l.client.GET("/v2/leader")
	response, e := l.client.Do(request)
	Check(e == nil, "get leader failed", e)
	c := response.StatusCode
	Check(c == 200, "get leader bad status", c)
	defer response.Body.Close()
	fmt.Println(l.format.Format(response.Body, l.Humanize))
}

func (l MarathonLeader) Humanize(body io.Reader) string {
	dec := json.NewDecoder(body)
	var which Which
	e := dec.Decode(&which)
	Check(e == nil, "failed to decode response", e)
	text := "LEADER\n" + which.Leader
	return Columnize(text)
}

// abdicate
type MarathonAbdicate struct {
	client *Client
	format Formatter
}

func (a MarathonAbdicate) Apply(args []string) {
	request := a.client.DELETE("/v2/leader")
	response, e := a.client.Do(request)
	Check(e == nil, "abdicate request failed", e)
	c := response.StatusCode
	Check(c == 200, "abdicate bad status", c)
	defer response.Body.Close()
	fmt.Println(a.format.Format(response.Body, a.Humanize))
}

func (a MarathonAbdicate) Humanize(body io.Reader) string {
	dec := json.NewDecoder(body)
	var mess Message
	e := dec.Decode(&mess)
	Check(e == nil, "failed to decode response", e)
	return "MESSAGE\n" + mess.Message
}
<|endoftext|>


<commit_before>/*
Copyright 2015 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 namespace

import (
	"fmt"
	"time"

	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/util/workqueue"
	"k8s.io/kubernetes/pkg/api/v1"
	"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
	coreinformers "k8s.io/kubernetes/pkg/client/informers/informers_generated/externalversions/core/v1"
	corelisters "k8s.io/kubernetes/pkg/client/listers/core/v1"
	"k8s.io/kubernetes/pkg/controller"
	"k8s.io/kubernetes/pkg/controller/namespace/deletion"
	"k8s.io/kubernetes/pkg/util/metrics"

	"github.com/golang/glog"
)

const (
	// namespaceDeletionGracePeriod is the time period to wait before processing a received namespace event.
	// This allows time for the following to occur:
	// * lifecycle admission plugins on HA apiservers to also observe a namespace
	//   deletion and prevent new objects from being created in the terminating namespace
	// * non-leader etcd servers to observe last-minute object creations in a namespace
	//   so this controller's cleanup can actually clean up all objects
	namespaceDeletionGracePeriod = 5 * time.Second
)

// NamespaceController is responsible for performing actions dependent upon a namespace phase
type NamespaceController struct {
	// lister that can list namespaces from a shared cache
	lister corelisters.NamespaceLister
	// returns true when the namespace cache is ready
	listerSynced cache.InformerSynced
	// namespaces that have been queued up for processing by workers
	queue workqueue.RateLimitingInterface
	// helper to delete all resources in the namespace when the namespace is deleted.
	namespacedResourcesDeleter deletion.NamespacedResourcesDeleterInterface
}

// NewNamespaceController creates a new NamespaceController
func NewNamespaceController(
	kubeClient clientset.Interface,
	clientPool dynamic.ClientPool,
	discoverResourcesFn func() ([]*metav1.APIResourceList, error),
	namespaceInformer coreinformers.NamespaceInformer,
	resyncPeriod time.Duration,
	finalizerToken v1.FinalizerName) *NamespaceController {

	// create the controller so we can inject the enqueue function
	namespaceController := &NamespaceController{
		queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "namespace"),
		namespacedResourcesDeleter: deletion.NewNamespacedResourcesDeleter(kubeClient.Core().Namespaces(), clientPool, kubeClient.Core(), discoverResourcesFn, finalizerToken, true),
	}

	if kubeClient != nil && kubeClient.Core().RESTClient().GetRateLimiter() != nil {
		metrics.RegisterMetricAndTrackRateLimiterUsage("namespace_controller", kubeClient.Core().RESTClient().GetRateLimiter())
	}

	// configure the namespace informer event handlers
	namespaceInformer.Informer().AddEventHandlerWithResyncPeriod(
		cache.ResourceEventHandlerFuncs{
			AddFunc: func(obj interface{}) {
				namespace := obj.(*v1.Namespace)
				namespaceController.enqueueNamespace(namespace)
			},
			UpdateFunc: func(oldObj, newObj interface{}) {
				namespace := newObj.(*v1.Namespace)
				namespaceController.enqueueNamespace(namespace)
			},
		},
		resyncPeriod,
	)
	namespaceController.lister = namespaceInformer.Lister()
	namespaceController.listerSynced = namespaceInformer.Informer().HasSynced

	return namespaceController
}

// enqueueNamespace adds an object to the controller work queue
// obj could be an *v1.Namespace, or a DeletionFinalStateUnknown item.
func (nm *NamespaceController) enqueueNamespace(obj interface{}) {
	key, err := controller.KeyFunc(obj)
	if err != nil {
		utilruntime.HandleError(fmt.Errorf("Couldn't get key for object %+v: %v", obj, err))
		return
	}
	// delay processing namespace events to allow HA api servers to observe namespace deletion,
	// and HA etcd servers to observe last minute object creations inside the namespace
	nm.queue.AddAfter(key, namespaceDeletionGracePeriod)
}

// worker processes the queue of namespace objects.
// Each namespace can be in the queue at most once.
// The system ensures that no two workers can process
// the same namespace at the same time.
func (nm *NamespaceController) worker() {
	workFunc := func() bool {
		key, quit := nm.queue.Get()
		if quit {
			return true
		}
		defer nm.queue.Done(key)

		err := nm.syncNamespaceFromKey(key.(string))
		if err == nil {
			// no error, forget this entry and return
			nm.queue.Forget(key)
			return false
		}

		if estimate, ok := err.(*deletion.ResourcesRemainingError); ok {
			t := estimate.Estimate/2 + 1
			glog.V(4).Infof("Content remaining in namespace %s, waiting %d seconds", key, t)
			nm.queue.AddAfter(key, time.Duration(t)*time.Second)
		} else {
			// rather than wait for a full resync, re-add the namespace to the queue to be processed
			nm.queue.AddRateLimited(key)
			utilruntime.HandleError(err)
		}
		return false
	}

	for {
		quit := workFunc()

		if quit {
			return
		}
	}
}

// syncNamespaceFromKey looks for a namespace with the specified key in its store and synchronizes it
func (nm *NamespaceController) syncNamespaceFromKey(key string) (err error) {
	startTime := time.Now()
	defer glog.V(4).Infof("Finished syncing namespace %q (%v)", key, time.Now().Sub(startTime))

	namespace, err := nm.lister.Get(key)
	if errors.IsNotFound(err) {
		glog.Infof("Namespace has been deleted %v", key)
		return nil
	}
	if err != nil {
		utilruntime.HandleError(fmt.Errorf("Unable to retrieve namespace %v from store: %v", key, err))
		return err
	}
	return nm.namespacedResourcesDeleter.Delete(namespace.Name)
}

// Run starts observing the system with the specified number of workers.
func (nm *NamespaceController) Run(workers int, stopCh <-chan struct{}) {
	defer utilruntime.HandleCrash()
	defer nm.queue.ShutDown()

	glog.Info("Starting the NamespaceController")

	if !cache.WaitForCacheSync(stopCh, nm.listerSynced) {
		utilruntime.HandleError(fmt.Errorf("timed out waiting for caches to sync"))
		return
	}

	for i := 0; i < workers; i++ {
		go wait.Until(nm.worker, time.Second, stopCh)
	}

	<-stopCh

	glog.Info("Shutting down NamespaceController")
}
<commit_msg>UPSTREAM: 46373: don't queue namespaces for deletion if the namespace isn't deleted<commit_after>/*
Copyright 2015 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 namespace

import (
	"fmt"
	"time"

	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/util/workqueue"
	"k8s.io/kubernetes/pkg/api/v1"
	"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
	coreinformers "k8s.io/kubernetes/pkg/client/informers/informers_generated/externalversions/core/v1"
	corelisters "k8s.io/kubernetes/pkg/client/listers/core/v1"
	"k8s.io/kubernetes/pkg/controller"
	"k8s.io/kubernetes/pkg/controller/namespace/deletion"
	"k8s.io/kubernetes/pkg/util/metrics"

	"github.com/golang/glog"
)

const (
	// namespaceDeletionGracePeriod is the time period to wait before processing a received namespace event.
	// This allows time for the following to occur:
	// * lifecycle admission plugins on HA apiservers to also observe a namespace
	//   deletion and prevent new objects from being created in the terminating namespace
	// * non-leader etcd servers to observe last-minute object creations in a namespace
	//   so this controller's cleanup can actually clean up all objects
	namespaceDeletionGracePeriod = 5 * time.Second
)

// NamespaceController is responsible for performing actions dependent upon a namespace phase
type NamespaceController struct {
	// lister that can list namespaces from a shared cache
	lister corelisters.NamespaceLister
	// returns true when the namespace cache is ready
	listerSynced cache.InformerSynced
	// namespaces that have been queued up for processing by workers
	queue workqueue.RateLimitingInterface
	// helper to delete all resources in the namespace when the namespace is deleted.
	namespacedResourcesDeleter deletion.NamespacedResourcesDeleterInterface
}

// NewNamespaceController creates a new NamespaceController
func NewNamespaceController(
	kubeClient clientset.Interface,
	clientPool dynamic.ClientPool,
	discoverResourcesFn func() ([]*metav1.APIResourceList, error),
	namespaceInformer coreinformers.NamespaceInformer,
	resyncPeriod time.Duration,
	finalizerToken v1.FinalizerName) *NamespaceController {

	// create the controller so we can inject the enqueue function
	namespaceController := &NamespaceController{
		queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "namespace"),
		namespacedResourcesDeleter: deletion.NewNamespacedResourcesDeleter(kubeClient.Core().Namespaces(), clientPool, kubeClient.Core(), discoverResourcesFn, finalizerToken, true),
	}

	if kubeClient != nil && kubeClient.Core().RESTClient().GetRateLimiter() != nil {
		metrics.RegisterMetricAndTrackRateLimiterUsage("namespace_controller", kubeClient.Core().RESTClient().GetRateLimiter())
	}

	// configure the namespace informer event handlers
	namespaceInformer.Informer().AddEventHandlerWithResyncPeriod(
		cache.ResourceEventHandlerFuncs{
			AddFunc: func(obj interface{}) {
				namespace := obj.(*v1.Namespace)
				namespaceController.enqueueNamespace(namespace)
			},
			UpdateFunc: func(oldObj, newObj interface{}) {
				namespace := newObj.(*v1.Namespace)
				namespaceController.enqueueNamespace(namespace)
			},
		},
		resyncPeriod,
	)
	namespaceController.lister = namespaceInformer.Lister()
	namespaceController.listerSynced = namespaceInformer.Informer().HasSynced

	return namespaceController
}

// enqueueNamespace adds an object to the controller work queue
// obj could be an *v1.Namespace, or a DeletionFinalStateUnknown item.
func (nm *NamespaceController) enqueueNamespace(obj interface{}) {
	key, err := controller.KeyFunc(obj)
	if err != nil {
		utilruntime.HandleError(fmt.Errorf("Couldn't get key for object %+v: %v", obj, err))
		return
	}

	namespace := obj.(*v1.Namespace)
	// don't queue if we aren't deleted
	if namespace.DeletionTimestamp == nil || namespace.DeletionTimestamp.IsZero() {
		return
	}

	// delay processing namespace events to allow HA api servers to observe namespace deletion,
	// and HA etcd servers to observe last minute object creations inside the namespace
	nm.queue.AddAfter(key, namespaceDeletionGracePeriod)
}

// worker processes the queue of namespace objects.
// Each namespace can be in the queue at most once.
// The system ensures that no two workers can process
// the same namespace at the same time.
func (nm *NamespaceController) worker() {
	workFunc := func() bool {
		key, quit := nm.queue.Get()
		if quit {
			return true
		}
		defer nm.queue.Done(key)

		err := nm.syncNamespaceFromKey(key.(string))
		if err == nil {
			// no error, forget this entry and return
			nm.queue.Forget(key)
			return false
		}

		if estimate, ok := err.(*deletion.ResourcesRemainingError); ok {
			t := estimate.Estimate/2 + 1
			glog.V(4).Infof("Content remaining in namespace %s, waiting %d seconds", key, t)
			nm.queue.AddAfter(key, time.Duration(t)*time.Second)
		} else {
			// rather than wait for a full resync, re-add the namespace to the queue to be processed
			nm.queue.AddRateLimited(key)
			utilruntime.HandleError(err)
		}
		return false
	}

	for {
		quit := workFunc()

		if quit {
			return
		}
	}
}

// syncNamespaceFromKey looks for a namespace with the specified key in its store and synchronizes it
func (nm *NamespaceController) syncNamespaceFromKey(key string) (err error) {
	startTime := time.Now()
	defer glog.V(4).Infof("Finished syncing namespace %q (%v)", key, time.Now().Sub(startTime))

	namespace, err := nm.lister.Get(key)
	if errors.IsNotFound(err) {
		glog.Infof("Namespace has been deleted %v", key)
		return nil
	}
	if err != nil {
		utilruntime.HandleError(fmt.Errorf("Unable to retrieve namespace %v from store: %v", key, err))
		return err
	}
	return nm.namespacedResourcesDeleter.Delete(namespace.Name)
}

// Run starts observing the system with the specified number of workers.
func (nm *NamespaceController) Run(workers int, stopCh <-chan struct{}) {
	defer utilruntime.HandleCrash()
	defer nm.queue.ShutDown()

	glog.Info("Starting the NamespaceController")

	if !cache.WaitForCacheSync(stopCh, nm.listerSynced) {
		utilruntime.HandleError(fmt.Errorf("timed out waiting for caches to sync"))
		return
	}

	for i := 0; i < workers; i++ {
		go wait.Until(nm.worker, time.Second, stopCh)
	}

	<-stopCh

	glog.Info("Shutting down NamespaceController")
}
<|endoftext|>


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

package main

import (
	"database/sql"
	"math/rand"

	"context"

	"github.com/cockroachdb/cockroach-go/crdb"
)

// 2.8 The Stock-Level Transaction
//
// The Stock-Level business transaction determines the number of recently sold
// items that have a stock level below a specified threshold. It represents a
// heavy read-only database transaction with a low frequency of execution, a
// relaxed response time requirement, and relaxed consistency requirements.

// 2.8.2.3 states:
// Full serializability and repeatable reads are not required for the
// Stock-Level business transaction. All data read must be committed and no
// older than the most recently committed data prior to the time this business
// transaction was initiated. All other ACID properties must be maintained.
// TODO(jordan): can we take advantage of this?

type stockLevelData struct {
	// This data must all be returned by the transaction. See 2.8.3.4.
	dID       int
	threshold int
	lowStock  int
}

type stockLevel struct{}

var _ tpccTx = stockLevel{}

func (s stockLevel) run(db *sql.DB, wID int) (interface{}, error) {
	// 2.8.1.2: The threshold of minimum quantity in stock is selected at random
	// within [10..20].
	d := stockLevelData{
		threshold: randInt(10, 20),
		dID:       rand.Intn(9) + 1,
	}

	if err := crdb.ExecuteTx(
		context.Background(),
		db,
		txOpts,
		func(tx *sql.Tx) error {
			var dNextOID int
			if err := tx.QueryRow(`
				SELECT d_next_o_id
				FROM district
				WHERE d_w_id = $1 AND d_id = $2`,
				wID, d.dID,
			).Scan(&dNextOID); err != nil {
				return err
			}

			// Count the number of recently sold items that have a stock level below
			// the threshold.
			return tx.QueryRow(`
				SELECT COUNT(DISTINCT(s_i_id))
				FROM order_line
				JOIN stock
				ON s_i_id=ol_i_id
				  AND s_w_id=ol_w_id
				WHERE ol_w_id = $1
				  AND ol_d_id = $2
				  AND ol_o_id BETWEEN $3 - 20 AND $3 - 1
				  AND s_quantity < $4`,
				wID, d.dID, dNextOID, d.threshold,
			).Scan(&d.lowStock)
		}); err != nil {
		return nil, err
	}
	return d, nil
}
<commit_msg>tpcc: use lookup join in stock level<commit_after>// Copyright 2017 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License. See the AUTHORS file
// for names of contributors.

package main

import (
	"database/sql"
	"math/rand"

	"context"

	"github.com/cockroachdb/cockroach-go/crdb"
)

// 2.8 The Stock-Level Transaction
//
// The Stock-Level business transaction determines the number of recently sold
// items that have a stock level below a specified threshold. It represents a
// heavy read-only database transaction with a low frequency of execution, a
// relaxed response time requirement, and relaxed consistency requirements.

// 2.8.2.3 states:
// Full serializability and repeatable reads are not required for the
// Stock-Level business transaction. All data read must be committed and no
// older than the most recently committed data prior to the time this business
// transaction was initiated. All other ACID properties must be maintained.
// TODO(jordan): can we take advantage of this?

type stockLevelData struct {
	// This data must all be returned by the transaction. See 2.8.3.4.
	dID       int
	threshold int
	lowStock  int
}

type stockLevel struct{}

var _ tpccTx = stockLevel{}

func (s stockLevel) run(db *sql.DB, wID int) (interface{}, error) {
	// 2.8.1.2: The threshold of minimum quantity in stock is selected at random
	// within [10..20].
	d := stockLevelData{
		threshold: randInt(10, 20),
		dID:       rand.Intn(9) + 1,
	}

	// This is the only join in the application, so we don't need to worry about
	// this setting persisting incorrectly across queries.
	if _, err := db.Exec(`set experimental_force_lookup_join=true`); err != nil {
		return nil, err
	}

	if err := crdb.ExecuteTx(
		context.Background(),
		db,
		txOpts,
		func(tx *sql.Tx) error {
			var dNextOID int
			if err := tx.QueryRow(`
				SELECT d_next_o_id
				FROM district
				WHERE d_w_id = $1 AND d_id = $2`,
				wID, d.dID,
			).Scan(&dNextOID); err != nil {
				return err
			}

			// Count the number of recently sold items that have a stock level below
			// the threshold.
			return tx.QueryRow(`
				SELECT COUNT(DISTINCT(s_i_id))
				FROM order_line
				JOIN stock
				ON s_i_id=ol_i_id
				  AND s_w_id=ol_w_id
				WHERE ol_w_id = $1
				  AND ol_d_id = $2
				  AND ol_o_id BETWEEN $3 - 20 AND $3 - 1
				  AND s_quantity < $4`,
				wID, d.dID, dNextOID, d.threshold,
			).Scan(&d.lowStock)
		}); err != nil {
		return nil, err
	}
	return d, nil
}
<|endoftext|>


<commit_before>package kite

import (
	"errors"
	"fmt"
	"github.com/op/go-logging"
	"koding/newkite/dnode"
	"koding/newkite/dnode/rpc"
	"koding/newkite/protocol"
	"strconv"
	"sync"
	"time"
)

// RemoteKite is the client for communicating with another Kite.
// It has Call() and Go() methods for calling methods sync/async way.
type RemoteKite struct {
	// The information about the kite that we are connecting to.
	protocol.Kite

	// A reference to the current Kite running.
	localKite *Kite

	// A reference to the Kite's logger for easy access.
	Log *logging.Logger

	// Credentials that we sent in each request.
	Authentication callAuthentication

	// dnode RPC client that processes messages.
	client *rpc.Client

	// To signal waiters of Go() on disconnect.
	disconnect chan bool
}

// NewRemoteKite returns a pointer to a new RemoteKite. The returned instance
// is not connected. You have to call Dial() or DialForever() before calling
// Call() and Go() methods.
func (k *Kite) NewRemoteKite(kite protocol.Kite, auth callAuthentication) *RemoteKite {
	r := &RemoteKite{
		Kite:           kite,
		localKite:      k,
		Log:            k.Log,
		Authentication: auth,
		client:         k.server.NewClientWithHandlers(),
		disconnect:     make(chan bool),
	}

	// We need a reference to the local kite when a method call is received.
	r.client.Properties()["localKite"] = k

	r.OnConnect(func() {
		if r.Authentication.ValidUntil == nil {
			return
		}

		// Start a goroutine that will renew the token before it expires.
		go r.tokenRenewer()
	})

	var m sync.Mutex
	r.OnDisconnect(func() {
		m.Lock()
		close(r.disconnect)
		r.disconnect = make(chan bool)
		m.Unlock()
	})

	return r
}

// newRemoteKiteWithClient returns a pointer to new RemoteKite instance.
// The client will be replaced with the given client.
// Used to give the Kite method handler a working RemoteKite to call methods
// on other side.
func (k *Kite) newRemoteKiteWithClient(kite protocol.Kite, auth callAuthentication, client *rpc.Client) *RemoteKite {
	r := k.NewRemoteKite(kite, auth)
	r.client = client
	r.client.Properties()["localKite"] = k
	return r
}

// Dial connects to the remote Kite. Returns error if it can't.
func (r *RemoteKite) Dial() (err error) {
	addr := r.Kite.Addr()
	r.Log.Info("Dialing remote kite: [%s %s]", r.Kite.Name, addr)
	return r.client.Dial("ws://" + addr + "/dnode")
}

// Dial connects to the remote Kite. If it can't connect, it retries indefinitely.
func (r *RemoteKite) DialForever() {
	addr := r.Kite.Addr()
	r.Log.Info("Dialing remote kite: [%s %s]", r.Kite.Name, addr)
	r.client.DialForever("ws://" + addr + "/dnode")
}

func (r *RemoteKite) Close() {
	r.client.Close()
}

// OnConnect registers a function to run on connect.
func (r *RemoteKite) OnConnect(handler func()) {
	r.client.OnConnect(handler)
}

// OnDisconnect registers a function to run on disconnect.
func (r *RemoteKite) OnDisconnect(handler func()) {
	r.client.OnDisconnect(handler)
}

func (r *RemoteKite) tokenRenewer() {
	for {
		renewTime := r.Authentication.ValidUntil.Add(-30 * time.Second)
		select {
		case <-time.After(renewTime.Sub(time.Now().UTC())):
			if err := r.renewTokenUntilDisconnect(); err != nil {
				return
			}
		case <-r.disconnect:
			return
		}
	}
}

// renewToken retries until the request is successful or disconnect.
func (r *RemoteKite) renewTokenUntilDisconnect() error {
	const retryInterval = 10 * time.Second

	if err := r.renewToken(); err == nil {
		return nil
	}

	for {
		select {
		case <-time.After(retryInterval):
			if err := r.renewToken(); err != nil {
				r.Log.Error("error: %s Cannot renew token for Kite: %s I will retry in %d seconds...", err.Error(), r.Kite.ID, retryInterval)
				continue
			}

			break
		case <-r.disconnect:
			return errors.New("disconnect")
		}
	}

	return nil
}

func (r *RemoteKite) renewToken() error {
	tkn, err := r.localKite.Kontrol.GetToken(&r.Kite)
	if err != nil {
		return err
	}

	validUntil := time.Now().UTC().Add(time.Duration(tkn.TTL) * time.Second)
	r.Authentication.Key = tkn.Key
	r.Authentication.ValidUntil = &validUntil

	return nil
}

// CallOptions is the type of first argument in the dnode message.
// Second argument is a callback function.
// It is used when unmarshalling a dnode message.
type CallOptions struct {
	// Arguments to the method
	WithArgs       *dnode.Partial     `json:"withArgs"`
	Kite           protocol.Kite      `json:"kite"`
	Authentication callAuthentication `json:"authentication"`
}

// callOptionsOut is the same structure with CallOptions.
// It is used when marshalling a dnode message.
type callOptionsOut struct {
	CallOptions
	// Override this when sending because args will not be a *dnode.Partial.
	WithArgs interface{} `json:"withArgs"`
}

// That's what we send as a first argument in dnode message.
func (r *RemoteKite) makeOptions(args interface{}) *callOptionsOut {
	return &callOptionsOut{
		WithArgs: args,
		CallOptions: CallOptions{
			Kite:           r.localKite.Kite,
			Authentication: r.Authentication,
		},
	}
}

type callAuthentication struct {
	// Type can be "kodingKey", "token" or "sessionID" for now.
	Type       string     `json:"type"`
	Key        string     `json:"key"`
	ValidUntil *time.Time `json:"-"`
}

type response struct {
	Result *dnode.Partial
	Err    error
}

// Call makes a blocking method call to the server.
// Waits until the callback function is called by the other side and
// returns the result and the error.
func (r *RemoteKite) Call(method string, args interface{}) (result *dnode.Partial, err error) {
	response := <-r.Go(method, args)
	return response.Result, response.Err
}

// Go makes an unblocking method call to the server.
// It returns a channel that the caller can wait on it to get the response.
func (r *RemoteKite) Go(method string, args interface{}) chan *response {
	// We will return this channel to the caller.
	// It can wait on this channel to get the response.
	r.Log.Debug("Calling method [%s] on kite [%s]", method, r.Name)
	responseChan := make(chan *response, 1)

	r.send(method, args, responseChan)

	return responseChan
}

// send sends the method with callback to the server.
func (r *RemoteKite) send(method string, args interface{}, responseChan chan *response) {
	// To clean the sent callback after response is received.
	// Send/Receive in a channel to prevent race condition because
	// the callback is run in a separate goroutine.
	removeCallback := make(chan uint64, 1)

	// When a callback is called it will send the response to this channel.
	doneChan := make(chan *response, 1)

	opts := r.makeOptions(args)
	cb := r.makeResponseCallback(doneChan, removeCallback)

	callbacks, err := r.client.Call(method, opts, cb)
	if err != nil {
		responseChan <- &response{
			Result: nil,
			Err: fmt.Errorf("Calling method [%s] on [%s] error: %s",
				method, r.Kite.Name, err),
		}
		return
	}

	// Waits until the response has came or the connection has disconnected.
	go func() {
		select {
		case <-r.disconnect:
			responseChan <- &response{nil, errors.New("Client disconnected")}
		case resp := <-doneChan:
			responseChan <- resp
		}
	}()

	sendCallbackID(callbacks, removeCallback)
}

// sendCallbackID send the callback number to be deleted after response is received.
func sendCallbackID(callbacks map[string]dnode.Path, ch chan uint64) {
	if len(callbacks) > 0 {
		// Find max callback ID.
		max := uint64(0)
		for id, _ := range callbacks {
			i, _ := strconv.ParseUint(id, 10, 64)
			if i > max {
				max = i
			}
		}

		ch <- max
	} else {
		close(ch)
	}
}

// makeResponseCallback prepares and returns a callback function sent to the server.
// The caller of the Call() is blocked until the server calls this callback function.
// Sets theResponse and notifies the caller by sending to done channel.
func (r *RemoteKite) makeResponseCallback(doneChan chan *response, removeCallback <-chan uint64) Callback {
	return Callback(func(request *Request) {
		var (
			err    error          // First argument
			result *dnode.Partial // Second argument
		)

		// Notify that the callback is finished.
		defer func() { doneChan <- &response{result, err} }()

		// Remove the callback function from the map so we do not
		// consume memory for unused callbacks.
		if id, ok := <-removeCallback; ok {
			r.client.RemoveCallback(id)
		}

		// Arguments to our response callback It is a slice of length 2.
		// The first argument is the error string,
		// the second argument is the result.
		responseArgs := request.Args.MustSliceOfLength(2)

		// The second argument is our result.
		result = responseArgs[1]

		// This is error argument. Unmarshal panics if it is null.
		if responseArgs[0] == nil {
			return
		}

		// Read the error argument in response.
		var kiteErr *Error
		err = responseArgs[0].Unmarshal(kiteErr)
		if err != nil {
			return
		}

		err = kiteErr
	})
}
<commit_msg>kite: put a timeout to Call()<commit_after>package kite

import (
	"errors"
	"fmt"
	"github.com/op/go-logging"
	"koding/newkite/dnode"
	"koding/newkite/dnode/rpc"
	"koding/newkite/protocol"
	"strconv"
	"sync"
	"time"
)

const DefaultCallTimeout = 4000 // milliseconds

// RemoteKite is the client for communicating with another Kite.
// It has Call() and Go() methods for calling methods sync/async way.
type RemoteKite struct {
	// The information about the kite that we are connecting to.
	protocol.Kite

	// A reference to the current Kite running.
	localKite *Kite

	// A reference to the Kite's logger for easy access.
	Log *logging.Logger

	// Credentials that we sent in each request.
	Authentication callAuthentication

	// dnode RPC client that processes messages.
	client *rpc.Client

	// To signal waiters of Go() on disconnect.
	disconnect chan bool

	// Duration to wait reply from remote when making a request with Call().
	callTimeout time.Duration
}

// NewRemoteKite returns a pointer to a new RemoteKite. The returned instance
// is not connected. You have to call Dial() or DialForever() before calling
// Call() and Go() methods.
func (k *Kite) NewRemoteKite(kite protocol.Kite, auth callAuthentication) *RemoteKite {
	r := &RemoteKite{
		Kite:           kite,
		localKite:      k,
		Log:            k.Log,
		Authentication: auth,
		client:         k.server.NewClientWithHandlers(),
		disconnect:     make(chan bool),
	}
	r.SetCallTimeout(DefaultCallTimeout)

	// We need a reference to the local kite when a method call is received.
	r.client.Properties()["localKite"] = k

	r.OnConnect(func() {
		if r.Authentication.ValidUntil == nil {
			return
		}

		// Start a goroutine that will renew the token before it expires.
		go r.tokenRenewer()
	})

	var m sync.Mutex
	r.OnDisconnect(func() {
		m.Lock()
		close(r.disconnect)
		r.disconnect = make(chan bool)
		m.Unlock()
	})

	return r
}

// newRemoteKiteWithClient returns a pointer to new RemoteKite instance.
// The client will be replaced with the given client.
// Used to give the Kite method handler a working RemoteKite to call methods
// on other side.
func (k *Kite) newRemoteKiteWithClient(kite protocol.Kite, auth callAuthentication, client *rpc.Client) *RemoteKite {
	r := k.NewRemoteKite(kite, auth)
	r.client = client
	r.client.Properties()["localKite"] = k
	return r
}

func (r *RemoteKite) SetCallTimeout(ms uint) {
	r.callTimeout = time.Duration(ms) * time.Millisecond
}

// Dial connects to the remote Kite. Returns error if it can't.
func (r *RemoteKite) Dial() (err error) {
	addr := r.Kite.Addr()
	r.Log.Info("Dialing remote kite: [%s %s]", r.Kite.Name, addr)
	return r.client.Dial("ws://" + addr + "/dnode")
}

// Dial connects to the remote Kite. If it can't connect, it retries indefinitely.
func (r *RemoteKite) DialForever() {
	addr := r.Kite.Addr()
	r.Log.Info("Dialing remote kite: [%s %s]", r.Kite.Name, addr)
	r.client.DialForever("ws://" + addr + "/dnode")
}

func (r *RemoteKite) Close() {
	r.client.Close()
}

// OnConnect registers a function to run on connect.
func (r *RemoteKite) OnConnect(handler func()) {
	r.client.OnConnect(handler)
}

// OnDisconnect registers a function to run on disconnect.
func (r *RemoteKite) OnDisconnect(handler func()) {
	r.client.OnDisconnect(handler)
}

func (r *RemoteKite) tokenRenewer() {
	for {
		renewTime := r.Authentication.ValidUntil.Add(-30 * time.Second)
		select {
		case <-time.After(renewTime.Sub(time.Now().UTC())):
			if err := r.renewTokenUntilDisconnect(); err != nil {
				return
			}
		case <-r.disconnect:
			return
		}
	}
}

// renewToken retries until the request is successful or disconnect.
func (r *RemoteKite) renewTokenUntilDisconnect() error {
	const retryInterval = 10 * time.Second

	if err := r.renewToken(); err == nil {
		return nil
	}

	for {
		select {
		case <-time.After(retryInterval):
			if err := r.renewToken(); err != nil {
				r.Log.Error("error: %s Cannot renew token for Kite: %s I will retry in %d seconds...", err.Error(), r.Kite.ID, retryInterval)
				continue
			}

			break
		case <-r.disconnect:
			return errors.New("disconnect")
		}
	}

	return nil
}

func (r *RemoteKite) renewToken() error {
	tkn, err := r.localKite.Kontrol.GetToken(&r.Kite)
	if err != nil {
		return err
	}

	validUntil := time.Now().UTC().Add(time.Duration(tkn.TTL) * time.Second)
	r.Authentication.Key = tkn.Key
	r.Authentication.ValidUntil = &validUntil

	return nil
}

// CallOptions is the type of first argument in the dnode message.
// Second argument is a callback function.
// It is used when unmarshalling a dnode message.
type CallOptions struct {
	// Arguments to the method
	WithArgs       *dnode.Partial     `json:"withArgs"`
	Kite           protocol.Kite      `json:"kite"`
	Authentication callAuthentication `json:"authentication"`
}

// callOptionsOut is the same structure with CallOptions.
// It is used when marshalling a dnode message.
type callOptionsOut struct {
	CallOptions
	// Override this when sending because args will not be a *dnode.Partial.
	WithArgs interface{} `json:"withArgs"`
}

// That's what we send as a first argument in dnode message.
func (r *RemoteKite) makeOptions(args interface{}) *callOptionsOut {
	return &callOptionsOut{
		WithArgs: args,
		CallOptions: CallOptions{
			Kite:           r.localKite.Kite,
			Authentication: r.Authentication,
		},
	}
}

type callAuthentication struct {
	// Type can be "kodingKey", "token" or "sessionID" for now.
	Type       string     `json:"type"`
	Key        string     `json:"key"`
	ValidUntil *time.Time `json:"-"`
}

type response struct {
	Result *dnode.Partial
	Err    error
}

// Call makes a blocking method call to the server.
// Waits until the callback function is called by the other side and
// returns the result and the error.
func (r *RemoteKite) Call(method string, args interface{}) (result *dnode.Partial, err error) {
	response := <-r.Go(method, args)
	return response.Result, response.Err
}

// Go makes an unblocking method call to the server.
// It returns a channel that the caller can wait on it to get the response.
func (r *RemoteKite) Go(method string, args interface{}) chan *response {
	// We will return this channel to the caller.
	// It can wait on this channel to get the response.
	r.Log.Debug("Calling method [%s] on kite [%s]", method, r.Name)
	responseChan := make(chan *response, 1)

	r.send(method, args, responseChan)

	return responseChan
}

// send sends the method with callback to the server.
func (r *RemoteKite) send(method string, args interface{}, responseChan chan *response) {
	// To clean the sent callback after response is received.
	// Send/Receive in a channel to prevent race condition because
	// the callback is run in a separate goroutine.
	removeCallback := make(chan uint64, 1)

	// When a callback is called it will send the response to this channel.
	doneChan := make(chan *response, 1)

	opts := r.makeOptions(args)
	cb := r.makeResponseCallback(doneChan, removeCallback)

	callbacks, err := r.client.Call(method, opts, cb)
	if err != nil {
		responseChan <- &response{
			Result: nil,
			Err: fmt.Errorf("Calling method [%s] on [%s] error: %s",
				method, r.Kite.Name, err),
		}
		return
	}

	// Waits until the response has came or the connection has disconnected.
	go func() {
		select {
		case <-r.disconnect:
			responseChan <- &response{nil, errors.New("Client disconnected")}
		case resp := <-doneChan:
			responseChan <- resp
		case <-time.After(r.callTimeout):
			responseChan <- &response{nil, errors.New("Timeout")}

			// Remove the callback function from the map so we do not
			// consume memory for unused callbacks.
			if id, ok := <-removeCallback; ok {
				r.client.RemoveCallback(id)
			}
		}
	}()

	sendCallbackID(callbacks, removeCallback)
}

// sendCallbackID send the callback number to be deleted after response is received.
func sendCallbackID(callbacks map[string]dnode.Path, ch chan uint64) {
	if len(callbacks) > 0 {
		// Find max callback ID.
		max := uint64(0)
		for id, _ := range callbacks {
			i, _ := strconv.ParseUint(id, 10, 64)
			if i > max {
				max = i
			}
		}

		ch <- max
	} else {
		close(ch)
	}
}

// makeResponseCallback prepares and returns a callback function sent to the server.
// The caller of the Call() is blocked until the server calls this callback function.
// Sets theResponse and notifies the caller by sending to done channel.
func (r *RemoteKite) makeResponseCallback(doneChan chan *response, removeCallback <-chan uint64) Callback {
	return Callback(func(request *Request) {
		var (
			err    error          // First argument
			result *dnode.Partial // Second argument
		)

		// Notify that the callback is finished.
		defer func() { doneChan <- &response{result, err} }()

		// Remove the callback function from the map so we do not
		// consume memory for unused callbacks.
		if id, ok := <-removeCallback; ok {
			r.client.RemoveCallback(id)
		}

		// Arguments to our response callback It is a slice of length 2.
		// The first argument is the error string,
		// the second argument is the result.
		responseArgs := request.Args.MustSliceOfLength(2)

		// The second argument is our result.
		result = responseArgs[1]

		// This is error argument. Unmarshal panics if it is null.
		if responseArgs[0] == nil {
			return
		}

		// Read the error argument in response.
		var kiteErr *Error
		err = responseArgs[0].Unmarshal(kiteErr)
		if err != nil {
			return
		}

		err = kiteErr
	})
}
<|endoftext|>


<commit_before>package server

import (
  "fmt"
  "net/http"

  "github.com/influxdata/chronograf"
)

type dashboardLinks struct {
  Self         string `json:"self"` // Self link mapping to this resource
}

type dashboardResponse struct {
  chronograf.Dashboard
  Links dashboardLinks `json:"links"`
}

type getDashboardsResponse struct {
	Dashboards []dashboardResponse `json:"dashboards"`
}

func newDashboardResponse(d chronograf.Dashboard) dashboardResponse {
  base := "/chronograf/v1/dashboards"
  return dashboardResponse{
    Dashboard: d,
    Links: dashboardLinks{
      Self: fmt.Sprintf("%s/%d", base, d.ID),
    },
  }
}

// Dashboards returns all dashboards within the store
func (s *Service) Dashboards(w http.ResponseWriter, r *http.Request) {
  ctx := r.Context()
  dashboards, err := s.DashboardsStore.All(ctx)
  if err != nil {
    Error(w, http.StatusInternalServerError, "Error loading layouts", s.Logger)
    return
  }

  res := getDashboardsResponse{
    Dashboards: []dashboardResponse{},
  }

  for _, dashboard := range dashboards {
    res.Dashboards = append(res.Dashboards, newDashboardResponse(dashboard))
  }

  encodeJSON(w, http.StatusOK, res, s.Logger)
}

// DashboardID returns a single specified dashboard
func (s *Service) DashboardID(w http.ResponseWriter, r *http.Request) {

}

// NewDashboard creates and returns a new dashboard object
func (s *Service) NewDashboard(w http.ResponseWriter, r *http.Request) {

}

// RemoveDashboard deletes a dashboard
func (s *Service) RemoveDashboard(w http.ResponseWriter, r *http.Request) {

}

// UpdateDashboard updates a dashboard
func (s *Service) UpdateDashboard(w http.ResponseWriter, r *http.Request) {

}
<commit_msg>add dashboard GET and DELETE handlers<commit_after>package server

import (
  "fmt"
  "net/http"

  "github.com/influxdata/chronograf"
)

type dashboardLinks struct {
  Self         string `json:"self"` // Self link mapping to this resource
}

type dashboardResponse struct {
  chronograf.Dashboard
  Links dashboardLinks `json:"links"`
}

type getDashboardsResponse struct {
	Dashboards []dashboardResponse `json:"dashboards"`
}

func newDashboardResponse(d chronograf.Dashboard) dashboardResponse {
  base := "/chronograf/v1/dashboards"
  return dashboardResponse{
    Dashboard: d,
    Links: dashboardLinks{
      Self: fmt.Sprintf("%s/%d", base, d.ID),
    },
  }
}

// Dashboards returns all dashboards within the store
func (s *Service) Dashboards(w http.ResponseWriter, r *http.Request) {
  ctx := r.Context()
  dashboards, err := s.DashboardsStore.All(ctx)
  if err != nil {
    Error(w, http.StatusInternalServerError, "Error loading layouts", s.Logger)
    return
  }

  res := getDashboardsResponse{
    Dashboards: []dashboardResponse{},
  }

  for _, dashboard := range dashboards {
    res.Dashboards = append(res.Dashboards, newDashboardResponse(dashboard))
  }

  encodeJSON(w, http.StatusOK, res, s.Logger)
}

// DashboardID returns a single specified dashboard
func (s *Service) DashboardID(w http.ResponseWriter, r *http.Request) {
  id, err := paramID("id", r)
  if err != nil {
    Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger)
    return
  }

  ctx := r.Context()
  e, err := s.DashboardsStore.Get(ctx, chronograf.DashboardID(id))
  if err != nil {
    notFound(w, id, s.Logger)
    return
  }

  res := newDashboardResponse(e)
  encodeJSON(w, http.StatusOK, res, s.Logger)
}

// type postDashboardRequest struct {
// 	Data interface{} `json:"data"`           // Serialization of config.
// 	Name string      `json:"name,omitempty"` // Exploration name given by user.
// }

// NewDashboard creates and returns a new dashboard object
func (s *Service) NewDashboard(w http.ResponseWriter, r *http.Request) {

}

// RemoveDashboard deletes a dashboard
func (s *Service) RemoveDashboard(w http.ResponseWriter, r *http.Request) {
  id, err := paramID("id", r)
	if err != nil {
		Error(w, http.StatusUnprocessableEntity, err.Error(), h.Logger)
		return
	}

	ctx := r.Context()
	e, err := s.DashboardsStore.Get(ctx, chronograf.DashboardID(id))
	if err != nil {
		notFound(w, id, s.Logger)
		return
	}

	if err := s.DashboardsStore.Delete(ctx, &chronograf.Dashboard{ID: chronograf.DashboardID(id)}); err != nil {
		unknownErrorWithMessage(w, err, s.Logger)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}

// UpdateDashboard updates a dashboard
func (s *Service) UpdateDashboard(w http.ResponseWriter, r *http.Request) {

}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/go.net/websocket"
	"fmt"
	"github.com/ActiveState/log"
	"io"
	"net/http"
)

func echoHandler(ws *websocket.Conn) {
	io.Copy(ws, ws)
}

func readArguments(ws *websocket.Conn) (token, appGUID string, err error) {
	q := ws.Config().Location.Query()
	appGUID = q.Get("appid")
	token = ws.Config().Header.Get("Authorization")
	if token == "" {
		token = q.Get("token")
	}
	if token == "" {
		err = fmt.Errorf("empty token")
	} else if appGUID == "" {
		err = fmt.Errorf("missing appGUID")
	}
	return
}

func tailHandler(ws *websocket.Conn) {
	log.Infof("tailHandler start")
	stream := &WebSocketStream{ws}
	token, appGUID, err := readArguments(ws)
	if err != nil {
		stream.Fatal(err)
		return
	}

	// First authorize with the CC by fetching something
	_, err = recentLogs(token, appGUID, 1)
	if err != nil {
		stream.Fatal(err)
		return
	}

	drain, err := NewAppLogDrain(appGUID)
	if err != nil {
		stream.Fatal(err)
		return
	}
	ch, err := drain.Start()
	if err != nil {
		stream.Fatal(err)
	}
	defer drain.Stop(nil)

	for line := range ch {
		if err := stream.Send(line); err != nil {
			log.Infof("Closing websocket because of write error: %v", err)
			return
		}
	}
	if err := drain.Wait(); err != nil {
		log.Warnf("Error from app log drain server: %v", err)
	}
	log.Infof("tailHandler done")
}

func serve() error {
	addr := fmt.Sprintf(":%d", PORT)
	http.Handle("/echo", websocket.Handler(echoHandler))
	http.Handle("/tail", websocket.Handler(tailHandler))
	return http.ListenAndServe(addr, nil)
}
<commit_msg>avoid double Stop<commit_after>package main

import (
	"code.google.com/p/go.net/websocket"
	"fmt"
	"github.com/ActiveState/log"
	"io"
	"net/http"
)

func echoHandler(ws *websocket.Conn) {
	io.Copy(ws, ws)
}

func readArguments(ws *websocket.Conn) (token, appGUID string, err error) {
	q := ws.Config().Location.Query()
	appGUID = q.Get("appid")
	token = ws.Config().Header.Get("Authorization")
	if token == "" {
		token = q.Get("token")
	}
	if token == "" {
		err = fmt.Errorf("empty token")
	} else if appGUID == "" {
		err = fmt.Errorf("missing appGUID")
	}
	return
}

func tailHandler(ws *websocket.Conn) {
	log.Infof("tailHandler start")
	stream := &WebSocketStream{ws}
	token, appGUID, err := readArguments(ws)
	if err != nil {
		stream.Fatal(err)
		return
	}

	// First authorize with the CC by fetching something
	_, err = recentLogs(token, appGUID, 1)
	if err != nil {
		stream.Fatal(err)
		return
	}

	drain, err := NewAppLogDrain(appGUID)
	if err != nil {
		stream.Fatal(err)
		return
	}
	ch, err := drain.Start()
	if err != nil {
		stream.Fatal(err)
	}

	for line := range ch {
		if err := stream.Send(line); err != nil {
			log.Infof("Closing websocket because of write error: %v", err)
			drain.Stop(err)
			return
		}
	}

	if err := drain.Wait(); err != nil {
		log.Warnf("Error from app log drain server: %v", err)
	}
	log.Infof("tailHandler done")
}

func serve() error {
	addr := fmt.Sprintf(":%d", PORT)
	http.Handle("/echo", websocket.Handler(echoHandler))
	http.Handle("/tail", websocket.Handler(tailHandler))
	return http.ListenAndServe(addr, nil)
}
<|endoftext|>


<commit_before>// +build !consulent

package state

import (
	"github.com/hashicorp/consul/agent/structs"
)

func testIndexerTableChecks() map[string]indexerTestCase {
	obj := &structs.HealthCheck{
		Node:      "NoDe",
		ServiceID: "SeRvIcE",
		CheckID:   "CheckID",
	}
	return map[string]indexerTestCase{
		indexID: {
			read: indexValue{
				source: NodeCheckQuery{
					Node:    "NoDe",
					CheckID: "CheckId",
				},
				expected: []byte("node\x00checkid\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("node\x00checkid\x00"),
			},
			prefix: []indexValue{
				{
					source:   structs.EnterpriseMeta{},
					expected: nil,
				},
				{
					source:   Query{Value: "nOdE"},
					expected: []byte("node\x00"),
				},
			},
		},
		indexNodeService: {
			read: indexValue{
				source: NodeServiceQuery{
					Node:    "NoDe",
					Service: "SeRvIcE",
				},
				expected: []byte("node\x00service\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("node\x00service\x00"),
			},
		},
		indexNode: {
			read: indexValue{
				source: Query{
					Value: "NoDe",
				},
				expected: []byte("node\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("node\x00"),
			},
		},
	}
}

func testIndexerTableMeshTopology() map[string]indexerTestCase {
	obj := upstreamDownstream{
		Upstream:   structs.ServiceName{Name: "UpStReAm"},
		Downstream: structs.ServiceName{Name: "DownStream"},
	}

	return map[string]indexerTestCase{
		indexID: {
			read: indexValue{
				source: []interface{}{
					structs.ServiceName{Name: "UpStReAm"},
					structs.ServiceName{Name: "DownStream"},
				},
				expected: []byte("upstream\x00downstream\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("upstream\x00downstream\x00"),
			},
		},
		indexUpstream: {
			read: indexValue{
				source:   structs.ServiceName{Name: "UpStReAm"},
				expected: []byte("upstream\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("upstream\x00"),
			},
		},
		indexDownstream: {
			read: indexValue{
				source:   structs.ServiceName{Name: "DownStream"},
				expected: []byte("downstream\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("downstream\x00"),
			},
		},
	}
}

func testIndexerTableGatewayServices() map[string]indexerTestCase {
	obj := &structs.GatewayService{
		Gateway: structs.ServiceName{Name: "GateWay"},
		Service: structs.ServiceName{Name: "SerVice"},
		Port:    50123,
	}
	encodedPort := string([]byte{0x96, 0x8f, 0x06, 0, 0, 0, 0, 0, 0, 0})
	return map[string]indexerTestCase{
		indexID: {
			read: indexValue{
				source: []interface{}{
					structs.ServiceName{Name: "GateWay"},
					structs.ServiceName{Name: "SerVice"},
					50123,
				},
				expected: []byte("gateway\x00service\x00" + encodedPort),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("gateway\x00service\x00" + encodedPort),
			},
		},
		indexGateway: {
			read: indexValue{
				source:   structs.ServiceName{Name: "GateWay"},
				expected: []byte("gateway\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("gateway\x00"),
			},
		},
		indexService: {
			read: indexValue{
				source:   structs.ServiceName{Name: "SerVice"},
				expected: []byte("service\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("service\x00"),
			},
		},
	}
}

func testIndexerTableNodes() map[string]indexerTestCase {
	return map[string]indexerTestCase{
		indexID: {
			read: indexValue{
				source:   Query{Value: "NoDeId"},
				expected: []byte("nodeid\x00"),
			},
			write: indexValue{
				source:   &structs.Node{Node: "NoDeId"},
				expected: []byte("nodeid\x00"),
			},
		},
	}
}

func testIndexerTableServices() map[string]indexerTestCase {
	obj := &structs.ServiceNode{
		Node:        "NoDeId",
		ServiceID:   "SeRviCe",
		ServiceName: "ServiceName",
	}

	return map[string]indexerTestCase{
		indexID: {
			read: indexValue{
				source: NodeServiceQuery{
					Node:    "NoDeId",
					Service: "SeRvIcE",
				},
				expected: []byte("nodeid\x00service\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("nodeid\x00service\x00"),
			},
			prefix: []indexValue{
				{
					source:   (*structs.EnterpriseMeta)(nil),
					expected: nil,
				},
				{
					source:   structs.EnterpriseMeta{},
					expected: nil,
				},
				{
					source:   Query{Value: "NoDeId"},
					expected: []byte("nodeid\x00"),
				},
			},
		},
		indexNode: {
			read: indexValue{
				source: Query{
					Value: "NoDeId",
				},
				expected: []byte("nodeid\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("nodeid\x00"),
			},
		},
		indexService: {
			read: indexValue{
				source:   Query{Value: "ServiceName"},
				expected: []byte("servicename\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("servicename\x00"),
			},
		},
		indexConnect: {
			read: indexValue{
				source:   Query{Value: "ConnectName"},
				expected: []byte("connectname\x00"),
			},
			write: indexValue{
				source: &structs.ServiceNode{
					ServiceName:    "ConnectName",
					ServiceConnect: structs.ServiceConnect{Native: true},
				},
				expected: []byte("connectname\x00"),
			},
		},
	}
}
<commit_msg>state: add tests for services.kind indexer<commit_after>// +build !consulent

package state

import (
	"github.com/hashicorp/consul/agent/structs"
)

func testIndexerTableChecks() map[string]indexerTestCase {
	obj := &structs.HealthCheck{
		Node:      "NoDe",
		ServiceID: "SeRvIcE",
		CheckID:   "CheckID",
	}
	return map[string]indexerTestCase{
		indexID: {
			read: indexValue{
				source: NodeCheckQuery{
					Node:    "NoDe",
					CheckID: "CheckId",
				},
				expected: []byte("node\x00checkid\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("node\x00checkid\x00"),
			},
			prefix: []indexValue{
				{
					source:   structs.EnterpriseMeta{},
					expected: nil,
				},
				{
					source:   Query{Value: "nOdE"},
					expected: []byte("node\x00"),
				},
			},
		},
		indexNodeService: {
			read: indexValue{
				source: NodeServiceQuery{
					Node:    "NoDe",
					Service: "SeRvIcE",
				},
				expected: []byte("node\x00service\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("node\x00service\x00"),
			},
		},
		indexNode: {
			read: indexValue{
				source: Query{
					Value: "NoDe",
				},
				expected: []byte("node\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("node\x00"),
			},
		},
	}
}

func testIndexerTableMeshTopology() map[string]indexerTestCase {
	obj := upstreamDownstream{
		Upstream:   structs.ServiceName{Name: "UpStReAm"},
		Downstream: structs.ServiceName{Name: "DownStream"},
	}

	return map[string]indexerTestCase{
		indexID: {
			read: indexValue{
				source: []interface{}{
					structs.ServiceName{Name: "UpStReAm"},
					structs.ServiceName{Name: "DownStream"},
				},
				expected: []byte("upstream\x00downstream\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("upstream\x00downstream\x00"),
			},
		},
		indexUpstream: {
			read: indexValue{
				source:   structs.ServiceName{Name: "UpStReAm"},
				expected: []byte("upstream\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("upstream\x00"),
			},
		},
		indexDownstream: {
			read: indexValue{
				source:   structs.ServiceName{Name: "DownStream"},
				expected: []byte("downstream\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("downstream\x00"),
			},
		},
	}
}

func testIndexerTableGatewayServices() map[string]indexerTestCase {
	obj := &structs.GatewayService{
		Gateway: structs.ServiceName{Name: "GateWay"},
		Service: structs.ServiceName{Name: "SerVice"},
		Port:    50123,
	}
	encodedPort := string([]byte{0x96, 0x8f, 0x06, 0, 0, 0, 0, 0, 0, 0})
	return map[string]indexerTestCase{
		indexID: {
			read: indexValue{
				source: []interface{}{
					structs.ServiceName{Name: "GateWay"},
					structs.ServiceName{Name: "SerVice"},
					50123,
				},
				expected: []byte("gateway\x00service\x00" + encodedPort),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("gateway\x00service\x00" + encodedPort),
			},
		},
		indexGateway: {
			read: indexValue{
				source:   structs.ServiceName{Name: "GateWay"},
				expected: []byte("gateway\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("gateway\x00"),
			},
		},
		indexService: {
			read: indexValue{
				source:   structs.ServiceName{Name: "SerVice"},
				expected: []byte("service\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("service\x00"),
			},
		},
	}
}

func testIndexerTableNodes() map[string]indexerTestCase {
	return map[string]indexerTestCase{
		indexID: {
			read: indexValue{
				source:   Query{Value: "NoDeId"},
				expected: []byte("nodeid\x00"),
			},
			write: indexValue{
				source:   &structs.Node{Node: "NoDeId"},
				expected: []byte("nodeid\x00"),
			},
		},
	}
}

func testIndexerTableServices() map[string]indexerTestCase {
	obj := &structs.ServiceNode{
		Node:        "NoDeId",
		ServiceID:   "SeRviCe",
		ServiceName: "ServiceName",
	}

	return map[string]indexerTestCase{
		indexID: {
			read: indexValue{
				source: NodeServiceQuery{
					Node:    "NoDeId",
					Service: "SeRvIcE",
				},
				expected: []byte("nodeid\x00service\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("nodeid\x00service\x00"),
			},
			prefix: []indexValue{
				{
					source:   (*structs.EnterpriseMeta)(nil),
					expected: nil,
				},
				{
					source:   structs.EnterpriseMeta{},
					expected: nil,
				},
				{
					source:   Query{Value: "NoDeId"},
					expected: []byte("nodeid\x00"),
				},
			},
		},
		indexNode: {
			read: indexValue{
				source: Query{
					Value: "NoDeId",
				},
				expected: []byte("nodeid\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("nodeid\x00"),
			},
		},
		indexService: {
			read: indexValue{
				source:   Query{Value: "ServiceName"},
				expected: []byte("servicename\x00"),
			},
			write: indexValue{
				source:   obj,
				expected: []byte("servicename\x00"),
			},
		},
		indexConnect: {
			read: indexValue{
				source:   Query{Value: "ConnectName"},
				expected: []byte("connectname\x00"),
			},
			write: indexValue{
				source: &structs.ServiceNode{
					ServiceName:    "ConnectName",
					ServiceConnect: structs.ServiceConnect{Native: true},
				},
				expected: []byte("connectname\x00"),
			},
		},
		indexKind: {
			read: indexValue{
				source:   "connect-proxy",
				expected: []byte("connect-proxy\x00"),
			},
			write: indexValue{
				source: &structs.ServiceNode{
					ServiceKind: structs.ServiceKindConnectProxy,
				},
				expected: []byte("connect-proxy\x00"),
			},
		},
	}
}
<|endoftext|>