<commit_before>// Commons for HTTP handling
package rpcserver

import (
	"bufio"
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"runtime/debug"
	"strings"
	"time"

	"github.com/pkg/errors"

	types "github.com/tendermint/tendermint/rpc/lib/types"
	"github.com/tendermint/tmlibs/log"
)

func StartHTTPServer(listenAddr string, handler http.Handler, logger log.Logger) (listener net.Listener, err error) {
	var proto, addr string
	parts := strings.SplitN(listenAddr, "://", 2)
	if len(parts) != 2 {
		return nil, errors.Errorf("Invalid listening address %s (use fully formed addresses, including the tcp:// or unix:// prefix)", listenAddr)
	}
	proto, addr = parts[0], parts[1]

	logger.Info(fmt.Sprintf("Starting RPC HTTP server on %s socket %v", proto, addr))
	listener, err = net.Listen(proto, addr)
	if err != nil {
		return nil, errors.Errorf("Failed to listen on %v: %v", listenAddr, err)
	}

	go func() {
		err := http.Serve(
			listener,
			RecoverAndLogHandler(handler, logger),
		)
		logger.Error("RPC HTTP server stopped", "err", err)
	}()
	return listener, nil
}

func StartHTTPAndTLSServer(listenAddr string, handler http.Handler, certFile, keyFile string, logger log.Logger) (listener net.Listener, err error) {
	var proto, addr string
	parts := strings.SplitN(listenAddr, "://", 2)
	if len(parts) != 2 {
		return nil, errors.Errorf("Invalid listening address %s (use fully formed addresses, including the tcp:// or unix:// prefix)", listenAddr)
	}
	proto, addr = parts[0], parts[1]

	logger.Info(fmt.Sprintf("Starting RPC HTTPS server on %s socket %v", proto, addr))
	listener, err = net.Listen(proto, addr)
	if err != nil {
		return nil, errors.Errorf("Failed to listen on %v: %v", listenAddr, err)
	}

	go func() {
		err := http.ServeTLS(
			listener,
			RecoverAndLogHandler(handler, logger),
			certFile,
			keyFile,
		)
		logger.Error("RPC HTTPS server stopped", "err", err)
	}()
	return listener, nil
}

func WriteRPCResponseHTTPError(w http.ResponseWriter, httpCode int, res types.RPCResponse) {
	jsonBytes, err := json.MarshalIndent(res, "", "  ")
	if err != nil {
		panic(err)
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(httpCode)
	w.Write(jsonBytes) // nolint: errcheck, gas
}

func WriteRPCResponseHTTP(w http.ResponseWriter, res types.RPCResponse) {
	jsonBytes, err := json.MarshalIndent(res, "", "  ")
	if err != nil {
		panic(err)
	}
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(200)
	w.Write(jsonBytes) // nolint: errcheck, gas
}

//-----------------------------------------------------------------------------

// Wraps an HTTP handler, adding error logging.
// If the inner function panics, the outer function recovers, logs, sends an
// HTTP 500 error response.
func RecoverAndLogHandler(handler http.Handler, logger log.Logger) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Wrap the ResponseWriter to remember the status
		rww := &ResponseWriterWrapper{-1, w}
		begin := time.Now()

		// Common headers
		origin := r.Header.Get("Origin")
		rww.Header().Set("Access-Control-Allow-Origin", origin)
		rww.Header().Set("Access-Control-Allow-Credentials", "true")
		rww.Header().Set("Access-Control-Expose-Headers", "X-Server-Time")
		rww.Header().Set("X-Server-Time", fmt.Sprintf("%v", begin.Unix()))

		defer func() {
			// Send a 500 error if a panic happens during a handler.
			// Without this, Chrome & Firefox were retrying aborted ajax requests,
			// at least to my localhost.
			if e := recover(); e != nil {

				// If RPCResponse
				if res, ok := e.(types.RPCResponse); ok {
					WriteRPCResponseHTTP(rww, res)
				} else {
					// For the rest,
					logger.Error("Panic in RPC HTTP handler", "err", e, "stack", string(debug.Stack()))
					rww.WriteHeader(http.StatusInternalServerError)
					WriteRPCResponseHTTP(rww, types.RPCInternalError("", e.(error)))
				}
			}

			// Finally, log.
			durationMS := time.Since(begin).Nanoseconds() / 1000000
			if rww.Status == -1 {
				rww.Status = 200
			}
			logger.Info("Served RPC HTTP response",
				"method", r.Method, "url", r.URL,
				"status", rww.Status, "duration", durationMS,
				"remoteAddr", r.RemoteAddr,
			)
		}()

		handler.ServeHTTP(rww, r)
	})
}

// Remember the status for logging
type ResponseWriterWrapper struct {
	Status int
	http.ResponseWriter
}

func (w *ResponseWriterWrapper) WriteHeader(status int) {
	w.Status = status
	w.ResponseWriter.WriteHeader(status)
}

// implements http.Hijacker
func (w *ResponseWriterWrapper) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	return w.ResponseWriter.(http.Hijacker).Hijack()
}
<commit_msg>[rpc/lib] log cert and key files in StartHTTPAndTLSServer<commit_after>// Commons for HTTP handling
package rpcserver

import (
	"bufio"
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"runtime/debug"
	"strings"
	"time"

	"github.com/pkg/errors"

	types "github.com/tendermint/tendermint/rpc/lib/types"
	"github.com/tendermint/tmlibs/log"
)

func StartHTTPServer(listenAddr string, handler http.Handler, logger log.Logger) (listener net.Listener, err error) {
	var proto, addr string
	parts := strings.SplitN(listenAddr, "://", 2)
	if len(parts) != 2 {
		return nil, errors.Errorf("Invalid listening address %s (use fully formed addresses, including the tcp:// or unix:// prefix)", listenAddr)
	}
	proto, addr = parts[0], parts[1]

	logger.Info(fmt.Sprintf("Starting RPC HTTP server on %s", listenAddr))
	listener, err = net.Listen(proto, addr)
	if err != nil {
		return nil, errors.Errorf("Failed to listen on %v: %v", listenAddr, err)
	}

	go func() {
		err := http.Serve(
			listener,
			RecoverAndLogHandler(handler, logger),
		)
		logger.Error("RPC HTTP server stopped", "err", err)
	}()
	return listener, nil
}

func StartHTTPAndTLSServer(listenAddr string, handler http.Handler, certFile, keyFile string, logger log.Logger) (listener net.Listener, err error) {
	var proto, addr string
	parts := strings.SplitN(listenAddr, "://", 2)
	if len(parts) != 2 {
		return nil, errors.Errorf("Invalid listening address %s (use fully formed addresses, including the tcp:// or unix:// prefix)", listenAddr)
	}
	proto, addr = parts[0], parts[1]

	logger.Info(fmt.Sprintf("Starting RPC HTTPS server on %s (cert: %q, key: %q)", listenAddr, certFile, keyFile))
	listener, err = net.Listen(proto, addr)
	if err != nil {
		return nil, errors.Errorf("Failed to listen on %v: %v", listenAddr, err)
	}

	go func() {
		err := http.ServeTLS(
			listener,
			RecoverAndLogHandler(handler, logger),
			certFile,
			keyFile,
		)
		logger.Error("RPC HTTPS server stopped", "err", err)
	}()
	return listener, nil
}

func WriteRPCResponseHTTPError(w http.ResponseWriter, httpCode int, res types.RPCResponse) {
	jsonBytes, err := json.MarshalIndent(res, "", "  ")
	if err != nil {
		panic(err)
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(httpCode)
	w.Write(jsonBytes) // nolint: errcheck, gas
}

func WriteRPCResponseHTTP(w http.ResponseWriter, res types.RPCResponse) {
	jsonBytes, err := json.MarshalIndent(res, "", "  ")
	if err != nil {
		panic(err)
	}
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(200)
	w.Write(jsonBytes) // nolint: errcheck, gas
}

//-----------------------------------------------------------------------------

// Wraps an HTTP handler, adding error logging.
// If the inner function panics, the outer function recovers, logs, sends an
// HTTP 500 error response.
func RecoverAndLogHandler(handler http.Handler, logger log.Logger) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Wrap the ResponseWriter to remember the status
		rww := &ResponseWriterWrapper{-1, w}
		begin := time.Now()

		// Common headers
		origin := r.Header.Get("Origin")
		rww.Header().Set("Access-Control-Allow-Origin", origin)
		rww.Header().Set("Access-Control-Allow-Credentials", "true")
		rww.Header().Set("Access-Control-Expose-Headers", "X-Server-Time")
		rww.Header().Set("X-Server-Time", fmt.Sprintf("%v", begin.Unix()))

		defer func() {
			// Send a 500 error if a panic happens during a handler.
			// Without this, Chrome & Firefox were retrying aborted ajax requests,
			// at least to my localhost.
			if e := recover(); e != nil {

				// If RPCResponse
				if res, ok := e.(types.RPCResponse); ok {
					WriteRPCResponseHTTP(rww, res)
				} else {
					// For the rest,
					logger.Error("Panic in RPC HTTP handler", "err", e, "stack", string(debug.Stack()))
					rww.WriteHeader(http.StatusInternalServerError)
					WriteRPCResponseHTTP(rww, types.RPCInternalError("", e.(error)))
				}
			}

			// Finally, log.
			durationMS := time.Since(begin).Nanoseconds() / 1000000
			if rww.Status == -1 {
				rww.Status = 200
			}
			logger.Info("Served RPC HTTP response",
				"method", r.Method, "url", r.URL,
				"status", rww.Status, "duration", durationMS,
				"remoteAddr", r.RemoteAddr,
			)
		}()

		handler.ServeHTTP(rww, r)
	})
}

// Remember the status for logging
type ResponseWriterWrapper struct {
	Status int
	http.ResponseWriter
}

func (w *ResponseWriterWrapper) WriteHeader(status int) {
	w.Status = status
	w.ResponseWriter.WriteHeader(status)
}

// implements http.Hijacker
func (w *ResponseWriterWrapper) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	return w.ResponseWriter.(http.Hijacker).Hijack()
}
<|endoftext|>


<commit_before>// Copyright 2017 tsuru 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 api

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

	"github.com/ajg/form"
	"github.com/pkg/errors"
	"github.com/tsuru/tsuru/auth"
	tsuruErrors "github.com/tsuru/tsuru/errors"
	"github.com/tsuru/tsuru/event"
	"github.com/tsuru/tsuru/iaas"
	"github.com/tsuru/tsuru/permission"
	"github.com/tsuru/tsuru/provision/cluster"
	"github.com/tsuru/tsuru/provision/pool"
)

func createClusterMachine(c *cluster.Cluster) error {
	if len(c.CreateData) == 0 {
		return nil
	}
	if templateName, ok := c.CreateData["template"]; ok {
		var err error
		c.CreateData, err = iaas.ExpandTemplate(templateName, c.CreateData)
		if err != nil {
			return err
		}
	}
	m, err := iaas.CreateMachine(c.CreateData)
	if err != nil {
		return err
	}
	c.Addresses = append(c.Addresses, m.FormatNodeAddress())
	c.CaCert = m.CaCert
	c.ClientCert = m.ClientCert
	c.ClientKey = m.ClientKey
	return nil
}

// title: create provisioner cluster
// path: /provisioner/clusters
// method: POST
// consume: application/x-www-form-urlencoded
// produce: application/json
// responses:
//   200: Ok
//   400: Invalid data
//   401: Unauthorized
//   404: Pool not does not exist
//   409: Cluster already exists
func createCluster(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	allowed := permission.Check(t, permission.PermClusterCreate)
	if !allowed {
		return permission.ErrUnauthorized
	}
	dec := form.NewDecoder(nil)
	dec.IgnoreCase(true)
	dec.IgnoreUnknownKeys(true)
	var provCluster cluster.Cluster
	err = r.ParseForm()
	if err == nil {
		err = dec.DecodeValues(&provCluster, r.Form)
	}
	if err != nil {
		return &tsuruErrors.HTTP{
			Code:    http.StatusBadRequest,
			Message: err.Error(),
		}
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeCluster, Value: provCluster.Name},
		Kind:       permission.PermClusterCreate,
		Owner:      t,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermClusterReadEvents),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	_, err = cluster.ByName(provCluster.Name)
	if err == nil {
		return &tsuruErrors.HTTP{
			Code:    http.StatusConflict,
			Message: "cluster already exists",
		}
	}
	for _, poolName := range provCluster.Pools {
		_, err = pool.GetPoolByName(poolName)
		if err != nil {
			if err == pool.ErrPoolNotFound {
				return &tsuruErrors.HTTP{
					Code:    http.StatusNotFound,
					Message: err.Error(),
				}
			}
			return err
		}
	}
	err = createClusterMachine(&provCluster)
	if err != nil {
		return err
	}
	err = provCluster.Save()
	if err != nil {
		return errors.WithStack(err)
	}
	w.WriteHeader(http.StatusOK)
	return nil
}

// title: update provisioner cluster
// path: /provisioner/clusters/{name}
// method: POST
// consume: application/x-www-form-urlencoded
// produce: application/json
// responses:
//   200: Ok
//   400: Invalid data
//   401: Unauthorized
//   404: Cluster not found
func updateCluster(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	allowed := permission.Check(t, permission.PermClusterUpdate)
	if !allowed {
		return permission.ErrUnauthorized
	}
	dec := form.NewDecoder(nil)
	dec.IgnoreCase(true)
	dec.IgnoreUnknownKeys(true)
	var provCluster cluster.Cluster
	err = r.ParseForm()
	if err == nil {
		err = dec.DecodeValues(&provCluster, r.Form)
	}
	provCluster.Name = r.URL.Query().Get(":name")
	if err != nil {
		return &tsuruErrors.HTTP{
			Code:    http.StatusBadRequest,
			Message: err.Error(),
		}
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeCluster, Value: provCluster.Name},
		Kind:       permission.PermClusterUpdate,
		Owner:      t,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermClusterReadEvents),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	_, err = cluster.ByName(provCluster.Name)
	if err != nil {
		if err == cluster.ErrClusterNotFound {
			return &tsuruErrors.HTTP{
				Code:    http.StatusNotFound,
				Message: err.Error(),
			}
		}
		return err
	}
	for _, poolName := range provCluster.Pools {
		_, err = pool.GetPoolByName(poolName)
		if err != nil {
			if err == pool.ErrPoolNotFound {
				return &tsuruErrors.HTTP{
					Code:    http.StatusBadRequest,
					Message: err.Error(),
				}
			}
			return err
		}
	}
	err = provCluster.Save()
	if err != nil {
		return errors.WithStack(err)
	}
	w.WriteHeader(http.StatusOK)
	return nil
}

// title: list provisioner clusters
// path: /provisioner/clusters
// method: GET
// consume: application/x-www-form-urlencoded
// produce: application/json
// responses:
//   200: Ok
//   204: No Content
//   401: Unauthorized
func listClusters(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	allowed := permission.Check(t, permission.PermClusterRead)
	if !allowed {
		return permission.ErrUnauthorized
	}
	clusters, err := cluster.AllClusters()
	if err != nil {
		if err == cluster.ErrNoCluster {
			w.WriteHeader(http.StatusNoContent)
			return nil
		}
		return err
	}
	return json.NewEncoder(w).Encode(clusters)
}

// title: delete provisioner cluster
// path: /provisioner/clusters/{name}
// method: GET
// consume: application/x-www-form-urlencoded
// produce: application/json
// responses:
//   200: Ok
//   401: Unauthorized
//   404: Cluster not found
func deleteCluster(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	allowed := permission.Check(t, permission.PermClusterDelete)
	if !allowed {
		return permission.ErrUnauthorized
	}
	r.ParseForm()
	clusterName := r.URL.Query().Get(":name")
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeCluster, Value: clusterName},
		Kind:       permission.PermClusterDelete,
		Owner:      t,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermClusterReadEvents),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	err = cluster.DeleteCluster(clusterName)
	if err != nil {
		if errors.Cause(err) == cluster.ErrClusterNotFound {
			return &tsuruErrors.HTTP{
				Code:    http.StatusNotFound,
				Message: err.Error(),
			}
		}
		return err
	}
	return nil
}
<commit_msg>Fixing typo in comment<commit_after>// Copyright 2017 tsuru 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 api

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

	"github.com/ajg/form"
	"github.com/pkg/errors"
	"github.com/tsuru/tsuru/auth"
	tsuruErrors "github.com/tsuru/tsuru/errors"
	"github.com/tsuru/tsuru/event"
	"github.com/tsuru/tsuru/iaas"
	"github.com/tsuru/tsuru/permission"
	"github.com/tsuru/tsuru/provision/cluster"
	"github.com/tsuru/tsuru/provision/pool"
)

func createClusterMachine(c *cluster.Cluster) error {
	if len(c.CreateData) == 0 {
		return nil
	}
	if templateName, ok := c.CreateData["template"]; ok {
		var err error
		c.CreateData, err = iaas.ExpandTemplate(templateName, c.CreateData)
		if err != nil {
			return err
		}
	}
	m, err := iaas.CreateMachine(c.CreateData)
	if err != nil {
		return err
	}
	c.Addresses = append(c.Addresses, m.FormatNodeAddress())
	c.CaCert = m.CaCert
	c.ClientCert = m.ClientCert
	c.ClientKey = m.ClientKey
	return nil
}

// title: create provisioner cluster
// path: /provisioner/clusters
// method: POST
// consume: application/x-www-form-urlencoded
// produce: application/json
// responses:
//   200: Ok
//   400: Invalid data
//   401: Unauthorized
//   404: Pool does not exist
//   409: Cluster already exists
func createCluster(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	allowed := permission.Check(t, permission.PermClusterCreate)
	if !allowed {
		return permission.ErrUnauthorized
	}
	dec := form.NewDecoder(nil)
	dec.IgnoreCase(true)
	dec.IgnoreUnknownKeys(true)
	var provCluster cluster.Cluster
	err = r.ParseForm()
	if err == nil {
		err = dec.DecodeValues(&provCluster, r.Form)
	}
	if err != nil {
		return &tsuruErrors.HTTP{
			Code:    http.StatusBadRequest,
			Message: err.Error(),
		}
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeCluster, Value: provCluster.Name},
		Kind:       permission.PermClusterCreate,
		Owner:      t,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermClusterReadEvents),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	_, err = cluster.ByName(provCluster.Name)
	if err == nil {
		return &tsuruErrors.HTTP{
			Code:    http.StatusConflict,
			Message: "cluster already exists",
		}
	}
	for _, poolName := range provCluster.Pools {
		_, err = pool.GetPoolByName(poolName)
		if err != nil {
			if err == pool.ErrPoolNotFound {
				return &tsuruErrors.HTTP{
					Code:    http.StatusNotFound,
					Message: err.Error(),
				}
			}
			return err
		}
	}
	err = createClusterMachine(&provCluster)
	if err != nil {
		return err
	}
	err = provCluster.Save()
	if err != nil {
		return errors.WithStack(err)
	}
	w.WriteHeader(http.StatusOK)
	return nil
}

// title: update provisioner cluster
// path: /provisioner/clusters/{name}
// method: POST
// consume: application/x-www-form-urlencoded
// produce: application/json
// responses:
//   200: Ok
//   400: Invalid data
//   401: Unauthorized
//   404: Cluster not found
func updateCluster(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	allowed := permission.Check(t, permission.PermClusterUpdate)
	if !allowed {
		return permission.ErrUnauthorized
	}
	dec := form.NewDecoder(nil)
	dec.IgnoreCase(true)
	dec.IgnoreUnknownKeys(true)
	var provCluster cluster.Cluster
	err = r.ParseForm()
	if err == nil {
		err = dec.DecodeValues(&provCluster, r.Form)
	}
	provCluster.Name = r.URL.Query().Get(":name")
	if err != nil {
		return &tsuruErrors.HTTP{
			Code:    http.StatusBadRequest,
			Message: err.Error(),
		}
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeCluster, Value: provCluster.Name},
		Kind:       permission.PermClusterUpdate,
		Owner:      t,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermClusterReadEvents),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	_, err = cluster.ByName(provCluster.Name)
	if err != nil {
		if err == cluster.ErrClusterNotFound {
			return &tsuruErrors.HTTP{
				Code:    http.StatusNotFound,
				Message: err.Error(),
			}
		}
		return err
	}
	for _, poolName := range provCluster.Pools {
		_, err = pool.GetPoolByName(poolName)
		if err != nil {
			if err == pool.ErrPoolNotFound {
				return &tsuruErrors.HTTP{
					Code:    http.StatusBadRequest,
					Message: err.Error(),
				}
			}
			return err
		}
	}
	err = provCluster.Save()
	if err != nil {
		return errors.WithStack(err)
	}
	w.WriteHeader(http.StatusOK)
	return nil
}

// title: list provisioner clusters
// path: /provisioner/clusters
// method: GET
// consume: application/x-www-form-urlencoded
// produce: application/json
// responses:
//   200: Ok
//   204: No Content
//   401: Unauthorized
func listClusters(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	allowed := permission.Check(t, permission.PermClusterRead)
	if !allowed {
		return permission.ErrUnauthorized
	}
	clusters, err := cluster.AllClusters()
	if err != nil {
		if err == cluster.ErrNoCluster {
			w.WriteHeader(http.StatusNoContent)
			return nil
		}
		return err
	}
	return json.NewEncoder(w).Encode(clusters)
}

// title: delete provisioner cluster
// path: /provisioner/clusters/{name}
// method: GET
// consume: application/x-www-form-urlencoded
// produce: application/json
// responses:
//   200: Ok
//   401: Unauthorized
//   404: Cluster not found
func deleteCluster(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	allowed := permission.Check(t, permission.PermClusterDelete)
	if !allowed {
		return permission.ErrUnauthorized
	}
	r.ParseForm()
	clusterName := r.URL.Query().Get(":name")
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeCluster, Value: clusterName},
		Kind:       permission.PermClusterDelete,
		Owner:      t,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermClusterReadEvents),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	err = cluster.DeleteCluster(clusterName)
	if err != nil {
		if errors.Cause(err) == cluster.ErrClusterNotFound {
			return &tsuruErrors.HTTP{
				Code:    http.StatusNotFound,
				Message: err.Error(),
			}
		}
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package api

import (
	"fmt"
	"net/http"
	"strings"

	"github.com/aptly-dev/aptly/aptly"
	"github.com/aptly-dev/aptly/deb"
	"github.com/aptly-dev/aptly/pgp"
	"github.com/aptly-dev/aptly/task"
	"github.com/aptly-dev/aptly/utils"
	"github.com/gin-gonic/gin"
)

// SigningOptions is a shared between publish API GPG options structure
type SigningOptions struct {
	Skip           bool
	Batch          bool
	GpgKey         string
	Keyring        string
	SecretKeyring  string
	Passphrase     string
	PassphraseFile string
}

func getSigner(options *SigningOptions) (pgp.Signer, error) {
	if options.Skip {
		return nil, nil
	}

	signer := context.GetSigner()
	signer.SetKey(options.GpgKey)
	signer.SetKeyRing(options.Keyring, options.SecretKeyring)
	signer.SetPassphrase(options.Passphrase, options.PassphraseFile)
	signer.SetBatch(options.Batch)

	err := signer.Init()
	if err != nil {
		return nil, err
	}

	return signer, nil
}

// Replace '_' with '/' and double '__' with single '_'
func parseEscapedPath(path string) string {
	result := strings.Replace(strings.Replace(path, "_", "/", -1), "//", "_", -1)
	if result == "" {
		result = "."
	}
	return result
}

// GET /publish
func apiPublishList(c *gin.Context) {
	collectionFactory := context.NewCollectionFactory()
	collection := collectionFactory.PublishedRepoCollection()

	result := make([]*deb.PublishedRepo, 0, collection.Len())

	err := collection.ForEach(func(repo *deb.PublishedRepo) error {
		err := collection.LoadComplete(repo, collectionFactory)
		if err != nil {
			return err
		}

		result = append(result, repo)

		return nil
	})

	if err != nil {
		c.AbortWithError(500, err)
		return
	}

	c.JSON(200, result)
}

// POST /publish/:prefix
func apiPublishRepoOrSnapshot(c *gin.Context) {
	param := parseEscapedPath(c.Params.ByName("prefix"))
	storage, prefix := deb.ParsePrefix(param)

	var b struct {
		SourceKind string `binding:"required"`
		Sources    []struct {
			Component string
			Name      string `binding:"required"`
		} `binding:"required"`
		Distribution         string
		Label                string
		Origin               string
		NotAutomatic         string
		ButAutomaticUpgrades string
		ForceOverwrite       bool
		SkipContents         *bool
		Architectures        []string
		Signing              SigningOptions
		AcquireByHash        *bool
	}

	if c.Bind(&b) != nil {
		return
	}

	signer, err := getSigner(&b.Signing)
	if err != nil {
		c.AbortWithError(500, fmt.Errorf("unable to initialize GPG signer: %s", err))
		return
	}

	if len(b.Sources) == 0 {
		c.AbortWithError(400, fmt.Errorf("unable to publish: soures are empty"))
		return
	}

	var components []string
	var names []string
	var sources []interface{}
	var resources []string
	collectionFactory := context.NewCollectionFactory()

	if b.SourceKind == "snapshot" {
		var snapshot *deb.Snapshot

		snapshotCollection := collectionFactory.SnapshotCollection()

		for _, source := range b.Sources {
			components = append(components, source.Component)
			names = append(names, source.Name)

			snapshot, err = snapshotCollection.ByName(source.Name)
			if err != nil {
				c.AbortWithError(404, fmt.Errorf("unable to publish: %s", err))
				return
			}

			resources = append(resources, string(snapshot.ResourceKey()))
			err = snapshotCollection.LoadComplete(snapshot)
			if err != nil {
				c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err))
				return
			}

			sources = append(sources, snapshot)
		}
	} else if b.SourceKind == deb.SourceLocalRepo {
		var localRepo *deb.LocalRepo

		localCollection := collectionFactory.LocalRepoCollection()

		for _, source := range b.Sources {
			components = append(components, source.Component)
			names = append(names, source.Name)

			localRepo, err = localCollection.ByName(source.Name)
			if err != nil {
				c.AbortWithError(404, fmt.Errorf("unable to publish: %s", err))
				return
			}

			resources = append(resources, string(localRepo.Key()))
			err = localCollection.LoadComplete(localRepo)
			if err != nil {
				c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err))
			}

			sources = append(sources, localRepo)
		}
	} else {
		c.AbortWithError(400, fmt.Errorf("unknown SourceKind"))
		return
	}

	published, err := deb.NewPublishedRepo(storage, prefix, b.Distribution, b.Architectures, components, sources, collectionFactory)
	if err != nil {
		c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err))
		return
	}

	resources = append(resources, string(published.Key()))
	collection := collectionFactory.PublishedRepoCollection()

	taskName := fmt.Sprintf("Publish %s: %s", b.SourceKind, strings.Join(names, ", "))
	maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) {
		taskDetail := task.PublishDetail{
			Detail: detail,
		}
		publishOutput := &task.PublishOutput{
			Progress:      out,
			PublishDetail: taskDetail,
		}

		if b.Origin != "" {
			published.Origin = b.Origin
		}
		if b.NotAutomatic != "" {
			published.NotAutomatic = b.NotAutomatic
		}
		if b.ButAutomaticUpgrades != "" {
			published.ButAutomaticUpgrades = b.ButAutomaticUpgrades
		}
		published.Label = b.Label

		published.SkipContents = context.Config().SkipContentsPublishing
		if b.SkipContents != nil {
			published.SkipContents = *b.SkipContents
		}

		if b.AcquireByHash != nil {
			published.AcquireByHash = *b.AcquireByHash
		}

		duplicate := collection.CheckDuplicate(published)
		if duplicate != nil {
			collectionFactory.PublishedRepoCollection().LoadComplete(duplicate, collectionFactory)
			return &task.ProcessReturnValue{http.StatusBadRequest, nil}, fmt.Errorf("prefix/distribution already used by another published repo: %s", duplicate)
		}

		err := published.Publish(context.PackagePool(), context, collectionFactory, signer, publishOutput, b.ForceOverwrite)
		if err != nil {
			return &task.ProcessReturnValue{http.StatusInternalServerError, nil}, fmt.Errorf("unable to publish: %s", err)
		}

		err = collection.Add(published)
		if err != nil {
			return &task.ProcessReturnValue{http.StatusInternalServerError, nil}, fmt.Errorf("unable to save to DB: %s", err)
		}

		return &task.ProcessReturnValue{http.StatusCreated, published}, nil
	})
}

// PUT /publish/:prefix/:distribution
func apiPublishUpdateSwitch(c *gin.Context) {
	param := parseEscapedPath(c.Params.ByName("prefix"))
	storage, prefix := deb.ParsePrefix(param)
	distribution := c.Params.ByName("distribution")

	var b struct {
		ForceOverwrite bool
		Signing        SigningOptions
		SkipContents   *bool
		SkipCleanup    *bool
		Snapshots      []struct {
			Component string `binding:"required"`
			Name      string `binding:"required"`
		}
		AcquireByHash *bool
	}

	if c.Bind(&b) != nil {
		return
	}

	signer, err := getSigner(&b.Signing)
	if err != nil {
		c.AbortWithError(500, fmt.Errorf("unable to initialize GPG signer: %s", err))
		return
	}

	collectionFactory := context.NewCollectionFactory()
	collection := collectionFactory.PublishedRepoCollection()

	published, err := collection.ByStoragePrefixDistribution(storage, prefix, distribution)
	if err != nil {
		c.AbortWithError(404, fmt.Errorf("unable to update: %s", err))
		return
	}
	err = collection.LoadComplete(published, collectionFactory)
	if err != nil {
		c.AbortWithError(500, fmt.Errorf("unable to update: %s", err))
		return
	}

	var updatedComponents []string
	var updatedSnapshots []string
	var resources []string

	if published.SourceKind == deb.SourceLocalRepo {
		if len(b.Snapshots) > 0 {
			c.AbortWithError(400, fmt.Errorf("snapshots shouldn't be given when updating local repo"))
			return
		}
		updatedComponents = published.Components()
		for _, component := range updatedComponents {
			published.UpdateLocalRepo(component)
		}
	} else if published.SourceKind == "snapshot" {
		publishedComponents := published.Components()
		for _, snapshotInfo := range b.Snapshots {
			if !utils.StrSliceHasItem(publishedComponents, snapshotInfo.Component) {
				c.AbortWithError(404, fmt.Errorf("component %s is not in published repository", snapshotInfo.Component))
				return
			}

			snapshotCollection := collectionFactory.SnapshotCollection()
			snapshot, err2 := snapshotCollection.ByName(snapshotInfo.Name)
			if err2 != nil {
				c.AbortWithError(404, err2)
				return
			}

			err2 = snapshotCollection.LoadComplete(snapshot)
			if err2 != nil {
				c.AbortWithError(500, err2)
				return
			}

			published.UpdateSnapshot(snapshotInfo.Component, snapshot)
			updatedComponents = append(updatedComponents, snapshotInfo.Component)
			updatedSnapshots = append(updatedSnapshots, snapshot.Name)
		}
	} else {
		c.AbortWithError(500, fmt.Errorf("unknown published repository type"))
		return
	}

	if b.SkipContents != nil {
		published.SkipContents = *b.SkipContents
	}

	if b.AcquireByHash != nil {
		published.AcquireByHash = *b.AcquireByHash
	}

	resources = append(resources, string(published.Key()))
	taskName := fmt.Sprintf("Update published %s (%s): %s", published.SourceKind, strings.Join(updatedComponents, " "), strings.Join(updatedSnapshots, ", "))
	maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) {
		err := published.Publish(context.PackagePool(), context, collectionFactory, signer, out, b.ForceOverwrite)
		if err != nil {
			return &task.ProcessReturnValue{http.StatusInternalServerError, nil}, fmt.Errorf("unable to update: %s", err)
		}

		err = collection.Update(published)
		if err != nil {
			return &task.ProcessReturnValue{http.StatusInternalServerError, nil}, fmt.Errorf("unable to save to DB: %s", err)
		}

		if b.SkipCleanup == nil || !*b.SkipCleanup {
			err = collection.CleanupPrefixComponentFiles(published.Prefix, updatedComponents,
				context.GetPublishedStorage(storage), collectionFactory, out)
			if err != nil {
				return &task.ProcessReturnValue{http.StatusInternalServerError, nil}, fmt.Errorf("unable to update: %s", err)
			}
		}

		return &task.ProcessReturnValue{http.StatusOK, published}, nil
	})
}

// DELETE /publish/:prefix/:distribution
func apiPublishDrop(c *gin.Context) {
	force := c.Request.URL.Query().Get("force") == "1"
	skipCleanup := c.Request.URL.Query().Get("SkipCleanup") == "1"

	param := parseEscapedPath(c.Params.ByName("prefix"))
	storage, prefix := deb.ParsePrefix(param)
	distribution := c.Params.ByName("distribution")

	collectionFactory := context.NewCollectionFactory()
	collection := collectionFactory.PublishedRepoCollection()

	published, err := collection.ByStoragePrefixDistribution(storage, prefix, distribution)
	if err != nil {
		c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("unable to drop: %s", err))
		return
	}

	resources := []string{string(published.Key())}

	taskName := fmt.Sprintf("Delete published %s (%s)", prefix, distribution)
	maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) {
		err := collection.Remove(context, storage, prefix, distribution,
			collectionFactory, out, force, skipCleanup)
		if err != nil {
			return &task.ProcessReturnValue{http.StatusInternalServerError, nil}, fmt.Errorf("unable to drop: %s", err)
		}

		return &task.ProcessReturnValue{http.StatusOK, gin.H{}}, nil
	})
}
<commit_msg>govet: compose literal uses unkeyed fields<commit_after>package api

import (
	"fmt"
	"net/http"
	"strings"

	"github.com/aptly-dev/aptly/aptly"
	"github.com/aptly-dev/aptly/deb"
	"github.com/aptly-dev/aptly/pgp"
	"github.com/aptly-dev/aptly/task"
	"github.com/aptly-dev/aptly/utils"
	"github.com/gin-gonic/gin"
)

// SigningOptions is a shared between publish API GPG options structure
type SigningOptions struct {
	Skip           bool
	Batch          bool
	GpgKey         string
	Keyring        string
	SecretKeyring  string
	Passphrase     string
	PassphraseFile string
}

func getSigner(options *SigningOptions) (pgp.Signer, error) {
	if options.Skip {
		return nil, nil
	}

	signer := context.GetSigner()
	signer.SetKey(options.GpgKey)
	signer.SetKeyRing(options.Keyring, options.SecretKeyring)
	signer.SetPassphrase(options.Passphrase, options.PassphraseFile)
	signer.SetBatch(options.Batch)

	err := signer.Init()
	if err != nil {
		return nil, err
	}

	return signer, nil
}

// Replace '_' with '/' and double '__' with single '_'
func parseEscapedPath(path string) string {
	result := strings.Replace(strings.Replace(path, "_", "/", -1), "//", "_", -1)
	if result == "" {
		result = "."
	}
	return result
}

// GET /publish
func apiPublishList(c *gin.Context) {
	collectionFactory := context.NewCollectionFactory()
	collection := collectionFactory.PublishedRepoCollection()

	result := make([]*deb.PublishedRepo, 0, collection.Len())

	err := collection.ForEach(func(repo *deb.PublishedRepo) error {
		err := collection.LoadComplete(repo, collectionFactory)
		if err != nil {
			return err
		}

		result = append(result, repo)

		return nil
	})

	if err != nil {
		c.AbortWithError(500, err)
		return
	}

	c.JSON(200, result)
}

// POST /publish/:prefix
func apiPublishRepoOrSnapshot(c *gin.Context) {
	param := parseEscapedPath(c.Params.ByName("prefix"))
	storage, prefix := deb.ParsePrefix(param)

	var b struct {
		SourceKind string `binding:"required"`
		Sources    []struct {
			Component string
			Name      string `binding:"required"`
		} `binding:"required"`
		Distribution         string
		Label                string
		Origin               string
		NotAutomatic         string
		ButAutomaticUpgrades string
		ForceOverwrite       bool
		SkipContents         *bool
		Architectures        []string
		Signing              SigningOptions
		AcquireByHash        *bool
	}

	if c.Bind(&b) != nil {
		return
	}

	signer, err := getSigner(&b.Signing)
	if err != nil {
		c.AbortWithError(500, fmt.Errorf("unable to initialize GPG signer: %s", err))
		return
	}

	if len(b.Sources) == 0 {
		c.AbortWithError(400, fmt.Errorf("unable to publish: soures are empty"))
		return
	}

	var components []string
	var names []string
	var sources []interface{}
	var resources []string
	collectionFactory := context.NewCollectionFactory()

	if b.SourceKind == "snapshot" {
		var snapshot *deb.Snapshot

		snapshotCollection := collectionFactory.SnapshotCollection()

		for _, source := range b.Sources {
			components = append(components, source.Component)
			names = append(names, source.Name)

			snapshot, err = snapshotCollection.ByName(source.Name)
			if err != nil {
				c.AbortWithError(404, fmt.Errorf("unable to publish: %s", err))
				return
			}

			resources = append(resources, string(snapshot.ResourceKey()))
			err = snapshotCollection.LoadComplete(snapshot)
			if err != nil {
				c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err))
				return
			}

			sources = append(sources, snapshot)
		}
	} else if b.SourceKind == deb.SourceLocalRepo {
		var localRepo *deb.LocalRepo

		localCollection := collectionFactory.LocalRepoCollection()

		for _, source := range b.Sources {
			components = append(components, source.Component)
			names = append(names, source.Name)

			localRepo, err = localCollection.ByName(source.Name)
			if err != nil {
				c.AbortWithError(404, fmt.Errorf("unable to publish: %s", err))
				return
			}

			resources = append(resources, string(localRepo.Key()))
			err = localCollection.LoadComplete(localRepo)
			if err != nil {
				c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err))
			}

			sources = append(sources, localRepo)
		}
	} else {
		c.AbortWithError(400, fmt.Errorf("unknown SourceKind"))
		return
	}

	published, err := deb.NewPublishedRepo(storage, prefix, b.Distribution, b.Architectures, components, sources, collectionFactory)
	if err != nil {
		c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err))
		return
	}

	resources = append(resources, string(published.Key()))
	collection := collectionFactory.PublishedRepoCollection()

	taskName := fmt.Sprintf("Publish %s: %s", b.SourceKind, strings.Join(names, ", "))
	maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) {
		taskDetail := task.PublishDetail{
			Detail: detail,
		}
		publishOutput := &task.PublishOutput{
			Progress:      out,
			PublishDetail: taskDetail,
		}

		if b.Origin != "" {
			published.Origin = b.Origin
		}
		if b.NotAutomatic != "" {
			published.NotAutomatic = b.NotAutomatic
		}
		if b.ButAutomaticUpgrades != "" {
			published.ButAutomaticUpgrades = b.ButAutomaticUpgrades
		}
		published.Label = b.Label

		published.SkipContents = context.Config().SkipContentsPublishing
		if b.SkipContents != nil {
			published.SkipContents = *b.SkipContents
		}

		if b.AcquireByHash != nil {
			published.AcquireByHash = *b.AcquireByHash
		}

		duplicate := collection.CheckDuplicate(published)
		if duplicate != nil {
			collectionFactory.PublishedRepoCollection().LoadComplete(duplicate, collectionFactory)
			return &task.ProcessReturnValue{Code: http.StatusBadRequest, Value: nil}, fmt.Errorf("prefix/distribution already used by another published repo: %s", duplicate)
		}

		err := published.Publish(context.PackagePool(), context, collectionFactory, signer, publishOutput, b.ForceOverwrite)
		if err != nil {
			return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to publish: %s", err)
		}

		err = collection.Add(published)
		if err != nil {
			return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to save to DB: %s", err)
		}

		return &task.ProcessReturnValue{Code: http.StatusCreated, Value: published}, nil
	})
}

// PUT /publish/:prefix/:distribution
func apiPublishUpdateSwitch(c *gin.Context) {
	param := parseEscapedPath(c.Params.ByName("prefix"))
	storage, prefix := deb.ParsePrefix(param)
	distribution := c.Params.ByName("distribution")

	var b struct {
		ForceOverwrite bool
		Signing        SigningOptions
		SkipContents   *bool
		SkipCleanup    *bool
		Snapshots      []struct {
			Component string `binding:"required"`
			Name      string `binding:"required"`
		}
		AcquireByHash *bool
	}

	if c.Bind(&b) != nil {
		return
	}

	signer, err := getSigner(&b.Signing)
	if err != nil {
		c.AbortWithError(500, fmt.Errorf("unable to initialize GPG signer: %s", err))
		return
	}

	collectionFactory := context.NewCollectionFactory()
	collection := collectionFactory.PublishedRepoCollection()

	published, err := collection.ByStoragePrefixDistribution(storage, prefix, distribution)
	if err != nil {
		c.AbortWithError(404, fmt.Errorf("unable to update: %s", err))
		return
	}
	err = collection.LoadComplete(published, collectionFactory)
	if err != nil {
		c.AbortWithError(500, fmt.Errorf("unable to update: %s", err))
		return
	}

	var updatedComponents []string
	var updatedSnapshots []string
	var resources []string

	if published.SourceKind == deb.SourceLocalRepo {
		if len(b.Snapshots) > 0 {
			c.AbortWithError(400, fmt.Errorf("snapshots shouldn't be given when updating local repo"))
			return
		}
		updatedComponents = published.Components()
		for _, component := range updatedComponents {
			published.UpdateLocalRepo(component)
		}
	} else if published.SourceKind == "snapshot" {
		publishedComponents := published.Components()
		for _, snapshotInfo := range b.Snapshots {
			if !utils.StrSliceHasItem(publishedComponents, snapshotInfo.Component) {
				c.AbortWithError(404, fmt.Errorf("component %s is not in published repository", snapshotInfo.Component))
				return
			}

			snapshotCollection := collectionFactory.SnapshotCollection()
			snapshot, err2 := snapshotCollection.ByName(snapshotInfo.Name)
			if err2 != nil {
				c.AbortWithError(404, err2)
				return
			}

			err2 = snapshotCollection.LoadComplete(snapshot)
			if err2 != nil {
				c.AbortWithError(500, err2)
				return
			}

			published.UpdateSnapshot(snapshotInfo.Component, snapshot)
			updatedComponents = append(updatedComponents, snapshotInfo.Component)
			updatedSnapshots = append(updatedSnapshots, snapshot.Name)
		}
	} else {
		c.AbortWithError(500, fmt.Errorf("unknown published repository type"))
		return
	}

	if b.SkipContents != nil {
		published.SkipContents = *b.SkipContents
	}

	if b.AcquireByHash != nil {
		published.AcquireByHash = *b.AcquireByHash
	}

	resources = append(resources, string(published.Key()))
	taskName := fmt.Sprintf("Update published %s (%s): %s", published.SourceKind, strings.Join(updatedComponents, " "), strings.Join(updatedSnapshots, ", "))
	maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) {
		err := published.Publish(context.PackagePool(), context, collectionFactory, signer, out, b.ForceOverwrite)
		if err != nil {
			return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to update: %s", err)
		}

		err = collection.Update(published)
		if err != nil {
			return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to save to DB: %s", err)
		}

		if b.SkipCleanup == nil || !*b.SkipCleanup {
			err = collection.CleanupPrefixComponentFiles(published.Prefix, updatedComponents,
				context.GetPublishedStorage(storage), collectionFactory, out)
			if err != nil {
				return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to update: %s", err)
			}
		}

		return &task.ProcessReturnValue{Code: http.StatusOK, Value: published}, nil
	})
}

// DELETE /publish/:prefix/:distribution
func apiPublishDrop(c *gin.Context) {
	force := c.Request.URL.Query().Get("force") == "1"
	skipCleanup := c.Request.URL.Query().Get("SkipCleanup") == "1"

	param := parseEscapedPath(c.Params.ByName("prefix"))
	storage, prefix := deb.ParsePrefix(param)
	distribution := c.Params.ByName("distribution")

	collectionFactory := context.NewCollectionFactory()
	collection := collectionFactory.PublishedRepoCollection()

	published, err := collection.ByStoragePrefixDistribution(storage, prefix, distribution)
	if err != nil {
		c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("unable to drop: %s", err))
		return
	}

	resources := []string{string(published.Key())}

	taskName := fmt.Sprintf("Delete published %s (%s)", prefix, distribution)
	maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) {
		err := collection.Remove(context, storage, prefix, distribution,
			collectionFactory, out, force, skipCleanup)
		if err != nil {
			return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to drop: %s", err)
		}

		return &task.ProcessReturnValue{Code: http.StatusOK, Value: gin.H{}}, nil
	})
}
<|endoftext|>


<commit_before>// khan
// https://github.com/topfreegames/khan
//
// Licensed under the MIT license:
// http://www.opensource.org/licenses/mit-license
// Copyright © 2016 Top Free Games <backend@tfgco.com>

package api

// VERSION identifies Khan's current version
var VERSION = "1.1.2"
<commit_msg>Release v1.1.3<commit_after>// khan
// https://github.com/topfreegames/khan
//
// Licensed under the MIT license:
// http://www.opensource.org/licenses/mit-license
// Copyright © 2016 Top Free Games <backend@tfgco.com>

package api

// VERSION identifies Khan's current version
var VERSION = "1.1.3"
<|endoftext|>


<commit_before>package election

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"syscall"

	"github.com/Sirupsen/logrus"
	"github.com/rancher/go-rancher-metadata/metadata"
)

type Watcher struct {
	leader  metadata.Container
	command []string
	port    int
	dstPort int
	client  *metadata.Client
	forward *TcpProxy
}

func New(client *metadata.Client, port int, command []string) *Watcher {
	return &Watcher{
		command: command,
		port:    port,
		client:  client,
	}
}

func NewSrcDstWatcher(client *metadata.Client, srcPort, dstPort int) *Watcher {
	return &Watcher{
		command: []string{},
		port:    srcPort,
		dstPort: dstPort,
		client:  client,
	}
}

func (w *Watcher) GetSelfServiceLeader() (metadata.Container, bool, error) {
	return w.getLeader()
}

func (w *Watcher) getLeader() (metadata.Container, bool, error) {
	selfContainer, err := w.client.GetSelfContainer()
	if err != nil {
		return metadata.Container{}, false, err
	}

	index := selfContainer.CreateIndex
	leader := selfContainer

	containers, err := w.client.GetServiceContainers(
		selfContainer.ServiceName,
		selfContainer.StackName,
	)
	if err != nil {
		return metadata.Container{}, false, err
	}

	for _, container := range containers {
		if container.CreateIndex < index {
			index = container.CreateIndex
			leader = container
		}
	}

	w.leader = leader
	return leader, leader.PrimaryIp == selfContainer.PrimaryIp, nil
}

func (w *Watcher) Forwarder() error {
	//initialize leader
	if _, _, err := w.getLeader(); err != nil {
		return err
	}

	w.forward = NewTcpProxy(w.port, func() string {
		return fmt.Sprintf("%s:%d", w.leader.PrimaryIp, w.dstPort)
	})

	go w.client.OnChange(1, func(version string) {
		currentLeaderIp := w.leader.PrimaryIp
		if _, _, err := w.getLeader(); err != nil {
			logrus.Error("Error getting leader: %s", err)
		}

		if w.leader.PrimaryIp != currentLeaderIp {
			if err := w.forward.Close(); err == nil {
				w.forward.Reset()
			}
		}
	})

	for {
		if w.port > 0 && w.dstPort > 0 {
			if err := w.forward.Forward(); err != nil {
				return err
			}
		} else {
			return errors.New("Ports not specified: src:" + string(w.port) + ", dst:" + string(w.dstPort))
		}
	}

	return errors.New("Unexpected loop termination")
}

func (w *Watcher) Watch() error {
	w.forward = NewTcpProxy(w.port, func() string {
		return w.leader.PrimaryIp
	})

	go w.client.OnChange(2, func(version string) {
		if w.IsLeader() {
			w.forward.Close()
		}
	})

	if w.port > 0 {
		if err := w.forward.Forward(); err != nil {
			return err
		}
	}

	if w.IsLeader() {
		if len(w.command) == 0 {
			return errors.New("No command")
		}

		prog, err := exec.LookPath(w.command[0])
		if err != nil {
			return err
		}
		return syscall.Exec(prog, w.command, os.Environ())
	}

	return errors.New("Unexpected loop termination")
}

func (w *Watcher) IsLeader() bool {
	_, leader, err := w.getLeader()
	return leader && err == nil
}
<commit_msg>Set port for forwarding traffic to leader<commit_after>package election

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"syscall"

	"github.com/Sirupsen/logrus"
	"github.com/rancher/go-rancher-metadata/metadata"
)

type Watcher struct {
	leader  metadata.Container
	command []string
	port    int
	dstPort int
	client  *metadata.Client
	forward *TcpProxy
}

func New(client *metadata.Client, port int, command []string) *Watcher {
	return &Watcher{
		command: command,
		port:    port,
		client:  client,
	}
}

func NewSrcDstWatcher(client *metadata.Client, srcPort, dstPort int) *Watcher {
	return &Watcher{
		command: []string{},
		port:    srcPort,
		dstPort: dstPort,
		client:  client,
	}
}

func (w *Watcher) GetSelfServiceLeader() (metadata.Container, bool, error) {
	return w.getLeader()
}

func (w *Watcher) getLeader() (metadata.Container, bool, error) {
	selfContainer, err := w.client.GetSelfContainer()
	if err != nil {
		return metadata.Container{}, false, err
	}

	index := selfContainer.CreateIndex
	leader := selfContainer

	containers, err := w.client.GetServiceContainers(
		selfContainer.ServiceName,
		selfContainer.StackName,
	)
	if err != nil {
		return metadata.Container{}, false, err
	}

	for _, container := range containers {
		if container.CreateIndex < index {
			index = container.CreateIndex
			leader = container
		}
	}

	w.leader = leader
	return leader, leader.PrimaryIp == selfContainer.PrimaryIp, nil
}

func (w *Watcher) Forwarder() error {
	//initialize leader
	if _, _, err := w.getLeader(); err != nil {
		return err
	}

	w.forward = NewTcpProxy(w.port, func() string {
		return fmt.Sprintf("%s:%d", w.leader.PrimaryIp, w.dstPort)
	})

	go w.client.OnChange(1, func(version string) {
		currentLeaderIp := w.leader.PrimaryIp
		if _, _, err := w.getLeader(); err != nil {
			logrus.Error("Error getting leader: %s", err)
		}

		if w.leader.PrimaryIp != currentLeaderIp {
			if err := w.forward.Close(); err == nil {
				w.forward.Reset()
			}
		}
	})

	for {
		if w.port > 0 && w.dstPort > 0 {
			if err := w.forward.Forward(); err != nil {
				return err
			}
		} else {
			return errors.New("Ports not specified: src:" + string(w.port) + ", dst:" + string(w.dstPort))
		}
	}

	return errors.New("Unexpected loop termination")
}

func (w *Watcher) Watch() error {
	w.forward = NewTcpProxy(w.port, func() string {
		return fmt.Sprintf("%s:%d", w.leader.PrimaryIp, w.port)
	})

	go w.client.OnChange(2, func(version string) {
		if w.IsLeader() {
			w.forward.Close()
		}
	})

	if w.port > 0 {
		if err := w.forward.Forward(); err != nil {
			return err
		}
	}

	if w.IsLeader() {
		if len(w.command) == 0 {
			return errors.New("No command")
		}

		prog, err := exec.LookPath(w.command[0])
		if err != nil {
			return err
		}
		return syscall.Exec(prog, w.command, os.Environ())
	}

	return errors.New("Unexpected loop termination")
}

func (w *Watcher) IsLeader() bool {
	_, leader, err := w.getLeader()
	return leader && err == nil
}
<|endoftext|>


<commit_before>package enum

import (
	"github.com/workfit/tester/assert"
	"testing"
)

func TestBasicTree(t *testing.T) {

	set := NewSet()

	/*

		A (1)
			AA (4)
		B (2)
			BA (5)
			BB (6)
				BBA (10)
				BBB (11)
			BC (7)
		C (3)
			CA (8)
			CB (9)

	*/

	values := map[int]string{
		1:  "A",
		2:  "B",
		3:  "C",
		4:  "AA",
		5:  "BA",
		6:  "BB",
		7:  "BC",
		8:  "CA",
		9:  "CB",
		10: "BBA",
		11: "BBB",
	}

	parents := map[int]int{
		1:  0,
		2:  0,
		3:  0,
		4:  1,
		5:  2,
		6:  2,
		7:  2,
		8:  3,
		9:  3,
		10: 6,
		11: 6,
	}

	tree, err := set.AddTree("test", values, parents)

	assert.For(t).ThatActual(err).IsNil()
	assert.For(t).ThatActual(tree).IsNotNil()

	assert.For(t).ThatActual(tree.Parent(0)).Equals(0)
	assert.For(t).ThatActual(tree.String(0)).Equals("")

	assert.For(t).ThatActual(tree.Parent(10)).Equals(6)

	assert.For(t).ThatActual(tree.Ancestors(11)).Equals([]int{0, 2, 6, 11})

	assert.For(t).ThatActual(tree.Children(2, false)).Equals([]int{5, 7})
	assert.For(t).ThatActual(tree.Children(2, true)).Equals([]int{5, 6, 7})

	assert.For(t).ThatActual(tree.IsLeaf(10)).IsTrue()
	assert.For(t).ThatActual(tree.IsLeaf(0)).IsFalse()
	assert.For(t).ThatActual(tree.IsLeaf(2)).IsFalse()

	assert.For(t).ThatActual(tree.Descendants(2, false)).Equals([]int{5, 10, 11, 7})
	assert.For(t).ThatActual(tree.Descendants(2, true)).Equals([]int{5, 6, 10, 11, 7})

}
<commit_msg>Started doing bad config tests for set.AddTree. Part of #628.<commit_after>package enum

import (
	"github.com/workfit/tester/assert"
	"testing"
)

func TestBasicTree(t *testing.T) {

	set := NewSet()

	/*

		A (1)
			AA (4)
		B (2)
			BA (5)
			BB (6)
				BBA (10)
				BBB (11)
			BC (7)
		C (3)
			CA (8)
			CB (9)

	*/

	values := map[int]string{
		1:  "A",
		2:  "B",
		3:  "C",
		4:  "AA",
		5:  "BA",
		6:  "BB",
		7:  "BC",
		8:  "CA",
		9:  "CB",
		10: "BBA",
		11: "BBB",
	}

	parents := map[int]int{
		1:  0,
		2:  0,
		3:  0,
		4:  1,
		5:  2,
		6:  2,
		7:  2,
		8:  3,
		9:  3,
		10: 6,
		11: 6,
	}

	tree, err := set.AddTree("test", values, parents)

	assert.For(t).ThatActual(err).IsNil()
	assert.For(t).ThatActual(tree).IsNotNil()

	assert.For(t).ThatActual(tree.Parent(0)).Equals(0)
	assert.For(t).ThatActual(tree.String(0)).Equals("")

	assert.For(t).ThatActual(tree.Parent(10)).Equals(6)

	assert.For(t).ThatActual(tree.Ancestors(11)).Equals([]int{0, 2, 6, 11})

	assert.For(t).ThatActual(tree.Children(2, false)).Equals([]int{5, 7})
	assert.For(t).ThatActual(tree.Children(2, true)).Equals([]int{5, 6, 7})

	assert.For(t).ThatActual(tree.IsLeaf(10)).IsTrue()
	assert.For(t).ThatActual(tree.IsLeaf(0)).IsFalse()
	assert.For(t).ThatActual(tree.IsLeaf(2)).IsFalse()

	assert.For(t).ThatActual(tree.Descendants(2, false)).Equals([]int{5, 10, 11, 7})
	assert.For(t).ThatActual(tree.Descendants(2, true)).Equals([]int{5, 6, 10, 11, 7})

}

func TestBadTreeConfig(t *testing.T) {
	tests := []struct {
		values              map[int]string
		parents             map[int]int
		expectedErrorString string
	}{
		{
			map[int]string{
				0: "not ''",
				1: "foo",
			},
			map[int]int{
				0: 0,
				1: 0,
			},
			"The root node's value must be ''",
		},
	}

	for i, test := range tests {

		set := NewSet()

		tree, err := set.AddTree("test", test.values, test.parents)

		if test.expectedErrorString != "" {
			assert.For(t, i).ThatActual(err).IsNotNil()
			assert.For(t, i).ThatActual(tree).IsNil()
			assert.For(t, i).ThatActual(err.Error()).Equals(test.expectedErrorString)
		} else {
			assert.For(t, i).ThatActual(err).IsNil()
			assert.For(t, i).ThatActual(tree).IsNotNil()
		}

	}

}
<|endoftext|>


<commit_before>package apns

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"time"

	"golang.org/x/net/http2"
)

const (
	// HTTP2 client timeout
	HTTP2ClientTimeout = time.Second * 10
)

var ClientTransport = func(cert tls.Certificate) *http.Transport {
	return &http.Transport{
		TLSClientConfig: &tls.Config{
			Certificates: []tls.Certificate{cert},
		},
	}
}

// Client is apns client
type Client struct {
	Host   string
	client *http.Client
}

// Send sends notifications to apns
func (ac *Client) Send(n Notification) ([]Result, error) {
	req, err := ac.NewRequest(n.Token, &n.Header, n.Payload)
	if err != nil {
		return nil, err
	}

	res, err := ac.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	ret := []Result{
		Result{
			APNsID:     res.Header.Get("apns-id"),
			StatusCode: res.StatusCode,
			Token:      n.Token,
		},
	}

	if res.StatusCode != http.StatusOK {
		var er ErrorResponse
		err := json.NewDecoder(res.Body).Decode(&er)
		if err != nil {
			ret[0].Reason = err.Error()
		} else {
			ret[0].Reason = er.Reason
		}
	}

	return ret, nil
}

// NewRequest creates request for apns
func (ac *Client) NewRequest(token string, h *Header, payload Payload) (*http.Request, error) {
	u, err := url.Parse(fmt.Sprintf("%s/3/device/%s", ac.Host, token))
	if err != nil {
		return nil, err
	}

	data, err := payload.MarshalJSON()
	if err != nil {
		return nil, err
	}

	nreq, err := http.NewRequest("POST", u.String(), bytes.NewReader(data))
	if err != nil {
		return nil, err
	}

	if h != nil {
		if h.ApnsID != "" {
			nreq.Header.Set("apns-id", h.ApnsID)
		}
		if h.ApnsExpiration != "" {
			nreq.Header.Set("apns-expiration", h.ApnsExpiration)
		}
		if h.ApnsPriority != "" {
			nreq.Header.Set("apns-priority", h.ApnsPriority)
		}
		if h.ApnsTopic != "" {
			nreq.Header.Set("apns-topic", h.ApnsTopic)
		}
	}

	return nreq, err
}

func NewClient(host, certFile, keyFile string) (*Client, error) {
	certPEMBlock, err := ioutil.ReadFile(certFile)
	if err != nil {
		return nil, err
	}

	keyPEMBlock, err := ioutil.ReadFile(keyFile)
	if err != nil {
		return nil, err
	}

	cert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock)
	if err != nil {
		return nil, err
	}

	tr := ClientTransport(cert)
	if err := http2.ConfigureTransport(tr); err != nil {
		return nil, err
	}

	return &Client{
		Host: host,
		client: &http.Client{
			Timeout:   HTTP2ClientTimeout,
			Transport: tr,
		},
	}, nil
}
<commit_msg>support to send with provider authentication token (apns)<commit_after>package apns

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"time"

	"github.com/kayac/Gunfish/config"
	"golang.org/x/net/http2"
)

const (
	// HTTP2 client timeout
	HTTP2ClientTimeout = time.Second * 10
)

var ClientTransport = func(cert tls.Certificate) *http.Transport {
	return &http.Transport{
		TLSClientConfig: &tls.Config{
			Certificates: []tls.Certificate{cert},
		},
	}
}

type authToken struct {
	jwt      string
	issuedAt time.Time
}

// Client is apns client
type Client struct {
	Host         string
	client       *http.Client
	authToken    authToken
	kid          string
	teamID       string
	keyFile      string
	useAuthToken bool
}

// Send sends notifications to apns
func (ac *Client) Send(n Notification) ([]Result, error) {
	req, err := ac.NewRequest(n.Token, &n.Header, n.Payload)
	if err != nil {
		return nil, err
	}

	res, err := ac.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	ret := []Result{
		Result{
			APNsID:     res.Header.Get("apns-id"),
			StatusCode: res.StatusCode,
			Token:      n.Token,
		},
	}

	if res.StatusCode != http.StatusOK {
		var er ErrorResponse
		err := json.NewDecoder(res.Body).Decode(&er)
		if err != nil {
			ret[0].Reason = err.Error()
		} else {
			ret[0].Reason = er.Reason
		}
	}

	return ret, nil
}

// NewRequest creates request for apns
func (ac *Client) NewRequest(token string, h *Header, payload Payload) (*http.Request, error) {
	u, err := url.Parse(fmt.Sprintf("%s/3/device/%s", ac.Host, token))
	if err != nil {
		return nil, err
	}

	data, err := payload.MarshalJSON()
	if err != nil {
		return nil, err
	}

	nreq, err := http.NewRequest("POST", u.String(), bytes.NewReader(data))
	if err != nil {
		return nil, err
	}

	if h != nil {
		if h.ApnsID != "" {
			nreq.Header.Set("apns-id", h.ApnsID)
		}
		if h.ApnsExpiration != "" {
			nreq.Header.Set("apns-expiration", h.ApnsExpiration)
		}
		if h.ApnsPriority != "" {
			nreq.Header.Set("apns-priority", h.ApnsPriority)
		}
		if h.ApnsTopic != "" {
			nreq.Header.Set("apns-topic", h.ApnsTopic)
		}
	}

	// APNs provider token authenticaton
	if ac.useAuthToken {
		// If iat of jwt is more than 1 hour ago, returns 403 InvalidProviderToken.
		// So, recreate jwt earlier than 1 hour.
		if ac.authToken.issuedAt.Add(time.Hour - time.Minute).Before(time.Now()) {
			if err := ac.issueToken(); err != nil {
				return nil, err
			}
		}
		nreq.Header.Set("Authorization", "bearer "+ac.authToken.jwt)
	}

	return nreq, err
}

func (ac *Client) issueToken() error {
	var err error
	now := time.Now()

	ac.authToken.jwt, err = CreateJWT(ac.keyFile, ac.kid, ac.teamID, now)
	if err != nil {
		return err
	}
	ac.authToken.issuedAt = now
	return nil
}

func NewClient(conf config.SectionApns) (*Client, error) {
	useAuthToken := conf.Kid != "" && conf.TeamID != ""
	tr := &http.Transport{}
	if !useAuthToken {
		certPEMBlock, err := ioutil.ReadFile(conf.CertFile)
		if err != nil {
			return nil, err
		}

		keyPEMBlock, err := ioutil.ReadFile(conf.KeyFile)
		if err != nil {
			return nil, err
		}

		cert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock)
		if err != nil {
			return nil, err
		}
		tr = ClientTransport(cert)
	}

	if err := http2.ConfigureTransport(tr); err != nil {
		return nil, err
	}

	client := &Client{
		Host: conf.Host,
		client: &http.Client{
			Timeout:   HTTP2ClientTimeout,
			Transport: tr,
		},
		kid:          conf.Kid,
		teamID:       conf.TeamID,
		keyFile:      conf.KeyFile,
		useAuthToken: useAuthToken,
	}
	if client.useAuthToken {
		if err := client.issueToken(); err != nil {
			return nil, err
		}
	}

	return client, nil
}
<|endoftext|>


<commit_before>package equalfile

import (
	"fmt"
	"io"
	"os"
	"strings"
	"testing"
)

const (
	expectError   = 0
	expectEqual   = 1
	expectUnequal = 2
)

func TestReader1(t *testing.T) {
	debug := os.Getenv("DEBUG") != ""
	c := New(make([]byte, 4000), Options{MaxSize: int64(50000), Debug: debug})
	r1 := strings.NewReader("wow")
	r2 := strings.NewReader("somethingthatlong")
	equal, err := c.CompareReader(r1, r2)
	if equal {
		t.Fatal("CompareReader should return false")
	}
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
}

func TestReader2(t *testing.T) {
	debug := os.Getenv("DEBUG") != ""
	c := New(make([]byte, 2), Options{MaxSize: int64(50000), Debug: debug})
	r1 := strings.NewReader("wow")
	r2 := strings.NewReader("somethingthatlong")
	equal, err := c.CompareReader(r1, r2)
	if equal {
		t.Fatal("CompareReader should return false")
	}
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
}

func TestBrokenReaders(t *testing.T) {
	limit := int64(50000)
	buf := make([]byte, 4000)
	chunk := int64(1000)
	total := int64(10000)
	debug := os.Getenv("DEBUG") != ""

	r1 := &testReader{label: "test1 r1", chunkSize: chunk, totalSize: total, debug: debug}
	r2 := &testReader{label: "test1 r2", chunkSize: chunk + 1, totalSize: total, debug: debug}
	compareReader(t, limit, buf, r1, r2, expectEqual, debug)

	r1 = &testReader{label: "test2 r1", chunkSize: chunk + 2, totalSize: total, debug: debug}
	r2 = &testReader{label: "test2 r2", chunkSize: chunk, totalSize: total, debug: debug}
	compareReader(t, limit, buf, r1, r2, expectEqual, debug)

	r1 = &testReader{label: "test3 r1", chunkSize: chunk, totalSize: total, debug: debug}
	r2 = &testReader{label: "test3 r2", chunkSize: chunk, totalSize: total, debug: debug}
	compareReader(t, limit, buf, r1, r2, expectEqual, debug)

	r1 = &testReader{label: "test4 r1", chunkSize: chunk, totalSize: total, lastByte: '0', debug: debug}
	r2 = &testReader{label: "test4 r2", chunkSize: chunk, totalSize: total, lastByte: '1', debug: debug}
	compareReader(t, limit, buf, r1, r2, expectUnequal, debug)

	r1 = &testReader{label: "test5 r1", chunkSize: chunk, totalSize: total, debug: debug}
	r2 = &testReader{label: "test5 r2", chunkSize: chunk + 1, totalSize: total, debug: debug}
	compareReader(t, limit, buf, r1, r2, expectUnequal, debug)

	r1 = &testReader{label: "test6 r1", chunkSize: chunk + 2, totalSize: total, debug: debug}
	r2 = &testReader{label: "test6 r2", chunkSize: chunk, totalSize: total, debug: debug}
	compareReader(t, limit, buf, r1, r2, expectUnequal, debug)

	r1 = &testReader{label: "test7 r1", chunkSize: chunk, totalSize: total, debug: debug}
	r2 = &testReader{label: "test7 r2", chunkSize: chunk, totalSize: total + 1, debug: debug}
	compareReader(t, limit, buf, r1, r2, expectUnequal, debug)
}

type testReader struct {
	label     string
	chunkSize int64
	totalSize int64
	lastByte  byte
	debug     bool
}

func (r *testReader) Read(buf []byte) (int, error) {

	n, err := testRead(r, buf)

	if r.debug {
		fmt.Printf("DEBUG testReader.Read: label=%s chunk=%d buf=%d total=%d last=%q size=%d error=%v\n", r.label, r.chunkSize, len(buf), r.totalSize, r.lastByte, n, err)
	}

	return n, err
}

func testRead(r *testReader, buf []byte) (int, error) {

	bufSize := int64(len(buf))
	if bufSize < 1 {
		return 0, fmt.Errorf("insufficient buffer size")
	}
	if r.totalSize < 1 {
		return 0, io.EOF
	}

	drainSize := r.totalSize // want to deliver all
	if r.chunkSize < drainSize {
		drainSize = r.chunkSize // cant deliver larger than chunk
	}
	if bufSize < drainSize {
		drainSize = bufSize // cant deliver larger than buf
	}

	r.totalSize -= drainSize

	if r.totalSize == 0 {
		buf[drainSize-1] = r.lastByte
	}

	return int(drainSize), nil
}

func compareReader(t *testing.T, limit int64, buf []byte, r1, r2 *testReader, expect int, debug bool) {
	c := New(buf, Options{MaxSize: limit, Debug: debug})
	equal, err := c.CompareReader(r1, r2)
	if err != nil {
		if expect != expectError {
			t.Errorf("compare: r1=%s r2=%s unexpected error: CompareReader(%d,%d): %v", r1.label, r2.label, c.Opt.MaxSize, len(c.buf), err)
		}
		return
	}
	if equal {
		if expect != expectEqual {
			t.Errorf("compare: r1=%s r2=%s unexpected equal: CompareReader(%d,%d)", r1.label, r2.label, c.Opt.MaxSize, len(c.buf))
		}
		return
	}
	if expect != expectUnequal {
		t.Errorf("compare: r1=%s r2=%s unexpected unequal: CompareReader(%d,%d)", r1.label, r2.label, c.Opt.MaxSize, len(c.buf))
	}
}
<commit_msg>Add test for a broken usage of hash for comparison<commit_after>package equalfile

import (
	"crypto/sha256"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"testing"
)

const (
	expectError   = 0
	expectEqual   = 1
	expectUnequal = 2
)

func cleanupTmpFiles(files []*os.File) {
	for _, f := range files {
		_ = f.Close()
		_ = os.Remove(f.Name())
	}
}

// Make tmp files each filled with the corresponding bytes of the contents slice.
func makeTmpFiles(t *testing.T, pat string, contents [][]byte) []*os.File {
	tmpFiles := []*os.File{}
	for i, v := range contents {
		tmpPat := pat + strconv.Itoa(i) + "_*"
		tmpfile, err := ioutil.TempFile("", tmpPat)
		if err != nil {
			cleanupTmpFiles(tmpFiles)
			t.Fatal("couldn't open tmpfile")
		}
		if _, err := tmpfile.Write(v); err != nil {
			tmpfile.Close()
			cleanupTmpFiles(tmpFiles)
			t.Fatal(err)
		}
		tmpFiles = append(tmpFiles, tmpfile)
	}
	return tmpFiles
}

// Determine if hash usage is so broken that it allows two arbitrarily
// different files to compare equal (such as if the hash input is truncated to
// length zero, or ignored in the hash result).
func TestCompareBrokenHashMultiple(t *testing.T) {
	pat := "equalfiles_test_brokenhash"
	contents := [][]byte{[]byte("a"), []byte("b")}
	tmpFiles := makeTmpFiles(t, pat, contents)
	defer cleanupTmpFiles(tmpFiles)

	c := NewMultiple(nil, Options{}, sha256.New(), false) // Matching hash will determine equality
	compare(t, c, tmpFiles[0].Name(), tmpFiles[1].Name(), expectUnequal)
}

func TestReader1(t *testing.T) {
	debug := os.Getenv("DEBUG") != ""
	c := New(make([]byte, 4000), Options{MaxSize: int64(50000), Debug: debug})
	r1 := strings.NewReader("wow")
	r2 := strings.NewReader("somethingthatlong")
	equal, err := c.CompareReader(r1, r2)
	if equal {
		t.Fatal("CompareReader should return false")
	}
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
}

func TestReader2(t *testing.T) {
	debug := os.Getenv("DEBUG") != ""
	c := New(make([]byte, 2), Options{MaxSize: int64(50000), Debug: debug})
	r1 := strings.NewReader("wow")
	r2 := strings.NewReader("somethingthatlong")
	equal, err := c.CompareReader(r1, r2)
	if equal {
		t.Fatal("CompareReader should return false")
	}
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
}

func TestBrokenReaders(t *testing.T) {
	limit := int64(50000)
	buf := make([]byte, 4000)
	chunk := int64(1000)
	total := int64(10000)
	debug := os.Getenv("DEBUG") != ""

	r1 := &testReader{label: "test1 r1", chunkSize: chunk, totalSize: total, debug: debug}
	r2 := &testReader{label: "test1 r2", chunkSize: chunk + 1, totalSize: total, debug: debug}
	compareReader(t, limit, buf, r1, r2, expectEqual, debug)

	r1 = &testReader{label: "test2 r1", chunkSize: chunk + 2, totalSize: total, debug: debug}
	r2 = &testReader{label: "test2 r2", chunkSize: chunk, totalSize: total, debug: debug}
	compareReader(t, limit, buf, r1, r2, expectEqual, debug)

	r1 = &testReader{label: "test3 r1", chunkSize: chunk, totalSize: total, debug: debug}
	r2 = &testReader{label: "test3 r2", chunkSize: chunk, totalSize: total, debug: debug}
	compareReader(t, limit, buf, r1, r2, expectEqual, debug)

	r1 = &testReader{label: "test4 r1", chunkSize: chunk, totalSize: total, lastByte: '0', debug: debug}
	r2 = &testReader{label: "test4 r2", chunkSize: chunk, totalSize: total, lastByte: '1', debug: debug}
	compareReader(t, limit, buf, r1, r2, expectUnequal, debug)

	r1 = &testReader{label: "test5 r1", chunkSize: chunk, totalSize: total, debug: debug}
	r2 = &testReader{label: "test5 r2", chunkSize: chunk + 1, totalSize: total, debug: debug}
	compareReader(t, limit, buf, r1, r2, expectUnequal, debug)

	r1 = &testReader{label: "test6 r1", chunkSize: chunk + 2, totalSize: total, debug: debug}
	r2 = &testReader{label: "test6 r2", chunkSize: chunk, totalSize: total, debug: debug}
	compareReader(t, limit, buf, r1, r2, expectUnequal, debug)

	r1 = &testReader{label: "test7 r1", chunkSize: chunk, totalSize: total, debug: debug}
	r2 = &testReader{label: "test7 r2", chunkSize: chunk, totalSize: total + 1, debug: debug}
	compareReader(t, limit, buf, r1, r2, expectUnequal, debug)
}

type testReader struct {
	label     string
	chunkSize int64
	totalSize int64
	lastByte  byte
	debug     bool
}

func (r *testReader) Read(buf []byte) (int, error) {

	n, err := testRead(r, buf)

	if r.debug {
		fmt.Printf("DEBUG testReader.Read: label=%s chunk=%d buf=%d total=%d last=%q size=%d error=%v\n", r.label, r.chunkSize, len(buf), r.totalSize, r.lastByte, n, err)
	}

	return n, err
}

func testRead(r *testReader, buf []byte) (int, error) {

	bufSize := int64(len(buf))
	if bufSize < 1 {
		return 0, fmt.Errorf("insufficient buffer size")
	}
	if r.totalSize < 1 {
		return 0, io.EOF
	}

	drainSize := r.totalSize // want to deliver all
	if r.chunkSize < drainSize {
		drainSize = r.chunkSize // cant deliver larger than chunk
	}
	if bufSize < drainSize {
		drainSize = bufSize // cant deliver larger than buf
	}

	r.totalSize -= drainSize

	if r.totalSize == 0 {
		buf[drainSize-1] = r.lastByte
	}

	return int(drainSize), nil
}

func compareReader(t *testing.T, limit int64, buf []byte, r1, r2 *testReader, expect int, debug bool) {
	c := New(buf, Options{MaxSize: limit, Debug: debug})
	equal, err := c.CompareReader(r1, r2)
	if err != nil {
		if expect != expectError {
			t.Errorf("compare: r1=%s r2=%s unexpected error: CompareReader(%d,%d): %v", r1.label, r2.label, c.Opt.MaxSize, len(c.buf), err)
		}
		return
	}
	if equal {
		if expect != expectEqual {
			t.Errorf("compare: r1=%s r2=%s unexpected equal: CompareReader(%d,%d)", r1.label, r2.label, c.Opt.MaxSize, len(c.buf))
		}
		return
	}
	if expect != expectUnequal {
		t.Errorf("compare: r1=%s r2=%s unexpected unequal: CompareReader(%d,%d)", r1.label, r2.label, c.Opt.MaxSize, len(c.buf))
	}
}
<|endoftext|>


<commit_before>package eth

import (
	"math/big"

	"github.com/ethereum/go-ethereum/accounts"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/ethclient"
	lpTypes "github.com/livepeer/go-livepeer/eth/types"
)

type StubClient struct {
	StrmID            string
	TOpts             string
	MaxPrice          *big.Int
	Jid               *big.Int
	SegSeqNum         *big.Int
	VeriRate          uint64
	DStorageHash      string
	DHash             [32]byte
	TDHash            [32]byte
	BSig              []byte
	Proof             []byte
	VerifyCounter     int
	ClaimJid          []*big.Int
	ClaimStart        []*big.Int
	ClaimEnd          []*big.Int
	ClaimRoot         map[[32]byte]bool
	ClaimCounter      int
	SubLogsCh         chan types.Log
	JobsMap           map[string]*lpTypes.Job
	BlockNum          *big.Int
	BlockHashToReturn common.Hash
	Claims            map[int]*lpTypes.Claim
}

func (e *StubClient) Setup(password string, gasLimit uint64, gasPrice *big.Int) error { return nil }
func (e *StubClient) Account() accounts.Account                                       { return accounts.Account{} }
func (e *StubClient) Backend() (*ethclient.Client, error)                             { return nil, ErrMissingBackend }

// Rounds

func (e *StubClient) InitializeRound() (*types.Transaction, error) { return nil, nil }
func (e *StubClient) CurrentRound() (*big.Int, error)              { return big.NewInt(0), nil }
func (e *StubClient) LastInitializedRound() (*big.Int, error)      { return big.NewInt(0), nil }
func (e *StubClient) CurrentRoundInitialized() (bool, error)       { return false, nil }
func (e *StubClient) CurrentRoundLocked() (bool, error)            { return false, nil }
func (e *StubClient) Paused() (bool, error)                        { return false, nil }

// Token

func (e *StubClient) Transfer(toAddr common.Address, amount *big.Int) (*types.Transaction, error) {
	return nil, nil
}
func (e *StubClient) Request() (*types.Transaction, error)            { return nil, nil }
func (e *StubClient) BalanceOf(addr common.Address) (*big.Int, error) { return big.NewInt(0), nil }
func (e *StubClient) TotalSupply() (*big.Int, error)                  { return big.NewInt(0), nil }

// Service Registry

func (e *StubClient) SetServiceURI(serviceURI string) (*types.Transaction, error) { return nil, nil }
func (e *StubClient) GetServiceURI(addr common.Address) (string, error)           { return "", nil }

// Staking

func (e *StubClient) Transcoder(blockRewardCut *big.Int, feeShare *big.Int, pricePerSegment *big.Int) (*types.Transaction, error) {
	return nil, nil
}
func (e *StubClient) Reward() (*types.Transaction, error) { return nil, nil }
func (e *StubClient) Bond(amount *big.Int, toAddr common.Address) (*types.Transaction, error) {
	return nil, nil
}
func (e *StubClient) Unbond() (*types.Transaction, error)        { return nil, nil }
func (e *StubClient) WithdrawStake() (*types.Transaction, error) { return nil, nil }
func (e *StubClient) WithdrawFees() (*types.Transaction, error)  { return nil, nil }
func (e *StubClient) ClaimEarnings(endRound *big.Int) error {
	return nil
}
func (e *StubClient) GetTranscoder(addr common.Address) (*lpTypes.Transcoder, error) { return nil, nil }
func (e *StubClient) GetDelegator(addr common.Address) (*lpTypes.Delegator, error)   { return nil, nil }
func (e *StubClient) GetTranscoderEarningsPoolForRound(addr common.Address, round *big.Int) (*lpTypes.TokenPools, error) {
	return nil, nil
}
func (e *StubClient) RegisteredTranscoders() ([]*lpTypes.Transcoder, error) { return nil, nil }
func (e *StubClient) IsActiveTranscoder() (bool, error)                     { return false, nil }
func (e *StubClient) AssignedTranscoder(jobID *big.Int) (common.Address, error) {
	return common.Address{}, nil
}
func (e *StubClient) GetTotalBonded() (*big.Int, error) { return big.NewInt(0), nil }

// Jobs

func (e *StubClient) Job(streamId string, transcodingOptions string, maxPricePerSegment *big.Int, endBlock *big.Int) (*types.Transaction, error) {
	return nil, nil
}
func (e *StubClient) ClaimWork(jobId *big.Int, segmentRange [2]*big.Int, claimRoot [32]byte) (*types.Transaction, error) {
	e.ClaimCounter++
	e.ClaimJid = append(e.ClaimJid, jobId)
	e.ClaimStart = append(e.ClaimStart, segmentRange[0])
	e.ClaimEnd = append(e.ClaimEnd, segmentRange[1])
	e.ClaimRoot[claimRoot] = true
	e.Claims[e.ClaimCounter-1] = &lpTypes.Claim{
		SegmentRange: segmentRange,
		ClaimRoot:    claimRoot,
	}
	return nil, nil
}
func (e *StubClient) Verify(jobId *big.Int, claimId *big.Int, segmentNumber *big.Int, dataStorageHash string, dataHashes [2][32]byte, broadcasterSig []byte, proof []byte) (*types.Transaction, error) {
	e.Jid = jobId
	e.SegSeqNum = segmentNumber
	e.DStorageHash = dataStorageHash
	e.DHash = dataHashes[0]
	e.TDHash = dataHashes[1]
	e.BSig = broadcasterSig
	e.Proof = proof
	e.VerifyCounter++

	return nil, nil
}
func (e *StubClient) DistributeFees(jobId *big.Int, claimId *big.Int) (*types.Transaction, error) {
	return nil, nil
}
func (c *StubClient) Deposit(amount *big.Int) (*types.Transaction, error) {
	return nil, nil
}
func (c *StubClient) Withdraw() (*types.Transaction, error) { return nil, nil }
func (c *StubClient) BroadcasterDeposit(broadcaster common.Address) (*big.Int, error) {
	return big.NewInt(0), nil
}
func (e *StubClient) GetJob(jobID *big.Int) (*lpTypes.Job, error) {
	return nil, nil
}
func (c *StubClient) GetClaim(jobID *big.Int, claimID *big.Int) (*lpTypes.Claim, error) {
	return c.Claims[int(claimID.Int64())], nil
}
func (c *StubClient) NumJobs() (*big.Int, error) { return big.NewInt(0), nil }

// Parameters

func (c *StubClient) NumActiveTranscoders() (*big.Int, error)          { return big.NewInt(0), nil }
func (c *StubClient) RoundLength() (*big.Int, error)                   { return big.NewInt(0), nil }
func (c *StubClient) RoundLockAmount() (*big.Int, error)               { return big.NewInt(0), nil }
func (c *StubClient) UnbondingPeriod() (uint64, error)                 { return 0, nil }
func (c *StubClient) VerificationRate() (uint64, error)                { return 0, nil }
func (c *StubClient) VerificationPeriod() (*big.Int, error)            { return big.NewInt(0), nil }
func (c *StubClient) VerificationSlashingPeriod() (*big.Int, error)    { return big.NewInt(0), nil }
func (c *StubClient) FailedVerificationSlashAmount() (*big.Int, error) { return big.NewInt(0), nil }
func (c *StubClient) MissedVerificationSlashAmount() (*big.Int, error) { return big.NewInt(0), nil }
func (c *StubClient) DoubleClaimSegmentSlashAmount() (*big.Int, error) { return big.NewInt(0), nil }
func (c *StubClient) FinderFee() (*big.Int, error)                     { return big.NewInt(0), nil }
func (c *StubClient) Inflation() (*big.Int, error)                     { return big.NewInt(0), nil }
func (c *StubClient) InflationChange() (*big.Int, error)               { return big.NewInt(0), nil }
func (c *StubClient) TargetBondingRate() (*big.Int, error)             { return big.NewInt(0), nil }
func (c *StubClient) VerificationCodeHash() (string, error)            { return "", nil }

// Helpers

func (c *StubClient) ContractAddresses() map[string]common.Address { return nil }
func (c *StubClient) CheckTx(tx *types.Transaction) error          { return nil }
func (c *StubClient) ReplaceTransaction(tx *types.Transaction, method string, gasPrice *big.Int) (*types.Transaction, error) {
	return nil, nil
}
func (c *StubClient) Sign(msg []byte) ([]byte, error)   { return nil, nil }
func (c *StubClient) LatestBlockNum() (*big.Int, error) { return big.NewInt(0), nil }
func (c *StubClient) GetGasInfo() (uint64, *big.Int)    { return 0, nil }
func (c *StubClient) SetGasInfo(uint64, *big.Int) error { return nil }
func (c *StubClient) WatchForJob(string) (*lpTypes.Job, error) { return nil, nil }
<commit_msg>stubclient: Cosmetics.<commit_after>package eth

import (
	"math/big"

	"github.com/ethereum/go-ethereum/accounts"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/ethclient"
	lpTypes "github.com/livepeer/go-livepeer/eth/types"
)

type StubClient struct {
	StrmID            string
	TOpts             string
	MaxPrice          *big.Int
	Jid               *big.Int
	SegSeqNum         *big.Int
	VeriRate          uint64
	DStorageHash      string
	DHash             [32]byte
	TDHash            [32]byte
	BSig              []byte
	Proof             []byte
	VerifyCounter     int
	ClaimJid          []*big.Int
	ClaimStart        []*big.Int
	ClaimEnd          []*big.Int
	ClaimRoot         map[[32]byte]bool
	ClaimCounter      int
	SubLogsCh         chan types.Log
	JobsMap           map[string]*lpTypes.Job
	BlockNum          *big.Int
	BlockHashToReturn common.Hash
	Claims            map[int]*lpTypes.Claim
}

func (e *StubClient) Setup(password string, gasLimit uint64, gasPrice *big.Int) error { return nil }
func (e *StubClient) Account() accounts.Account                                       { return accounts.Account{} }
func (e *StubClient) Backend() (*ethclient.Client, error)                             { return nil, ErrMissingBackend }

// Rounds

func (e *StubClient) InitializeRound() (*types.Transaction, error) { return nil, nil }
func (e *StubClient) CurrentRound() (*big.Int, error)              { return big.NewInt(0), nil }
func (e *StubClient) LastInitializedRound() (*big.Int, error)      { return big.NewInt(0), nil }
func (e *StubClient) CurrentRoundInitialized() (bool, error)       { return false, nil }
func (e *StubClient) CurrentRoundLocked() (bool, error)            { return false, nil }
func (e *StubClient) Paused() (bool, error)                        { return false, nil }

// Token

func (e *StubClient) Transfer(toAddr common.Address, amount *big.Int) (*types.Transaction, error) {
	return nil, nil
}
func (e *StubClient) Request() (*types.Transaction, error)            { return nil, nil }
func (e *StubClient) BalanceOf(addr common.Address) (*big.Int, error) { return big.NewInt(0), nil }
func (e *StubClient) TotalSupply() (*big.Int, error)                  { return big.NewInt(0), nil }

// Service Registry

func (e *StubClient) SetServiceURI(serviceURI string) (*types.Transaction, error) { return nil, nil }
func (e *StubClient) GetServiceURI(addr common.Address) (string, error)           { return "", nil }

// Staking

func (e *StubClient) Transcoder(blockRewardCut *big.Int, feeShare *big.Int, pricePerSegment *big.Int) (*types.Transaction, error) {
	return nil, nil
}
func (e *StubClient) Reward() (*types.Transaction, error) { return nil, nil }
func (e *StubClient) Bond(amount *big.Int, toAddr common.Address) (*types.Transaction, error) {
	return nil, nil
}
func (e *StubClient) Unbond() (*types.Transaction, error)        { return nil, nil }
func (e *StubClient) WithdrawStake() (*types.Transaction, error) { return nil, nil }
func (e *StubClient) WithdrawFees() (*types.Transaction, error)  { return nil, nil }
func (e *StubClient) ClaimEarnings(endRound *big.Int) error {
	return nil
}
func (e *StubClient) GetTranscoder(addr common.Address) (*lpTypes.Transcoder, error) { return nil, nil }
func (e *StubClient) GetDelegator(addr common.Address) (*lpTypes.Delegator, error)   { return nil, nil }
func (e *StubClient) GetTranscoderEarningsPoolForRound(addr common.Address, round *big.Int) (*lpTypes.TokenPools, error) {
	return nil, nil
}
func (e *StubClient) RegisteredTranscoders() ([]*lpTypes.Transcoder, error) { return nil, nil }
func (e *StubClient) IsActiveTranscoder() (bool, error)                     { return false, nil }
func (e *StubClient) AssignedTranscoder(jobID *big.Int) (common.Address, error) {
	return common.Address{}, nil
}
func (e *StubClient) GetTotalBonded() (*big.Int, error) { return big.NewInt(0), nil }

// Jobs

func (e *StubClient) Job(streamId string, transcodingOptions string, maxPricePerSegment *big.Int, endBlock *big.Int) (*types.Transaction, error) {
	return nil, nil
}
func (e *StubClient) ClaimWork(jobId *big.Int, segmentRange [2]*big.Int, claimRoot [32]byte) (*types.Transaction, error) {
	e.ClaimCounter++
	e.ClaimJid = append(e.ClaimJid, jobId)
	e.ClaimStart = append(e.ClaimStart, segmentRange[0])
	e.ClaimEnd = append(e.ClaimEnd, segmentRange[1])
	e.ClaimRoot[claimRoot] = true
	e.Claims[e.ClaimCounter-1] = &lpTypes.Claim{
		SegmentRange: segmentRange,
		ClaimRoot:    claimRoot,
	}
	return nil, nil
}
func (e *StubClient) Verify(jobId *big.Int, claimId *big.Int, segmentNumber *big.Int, dataStorageHash string, dataHashes [2][32]byte, broadcasterSig []byte, proof []byte) (*types.Transaction, error) {
	e.Jid = jobId
	e.SegSeqNum = segmentNumber
	e.DStorageHash = dataStorageHash
	e.DHash = dataHashes[0]
	e.TDHash = dataHashes[1]
	e.BSig = broadcasterSig
	e.Proof = proof
	e.VerifyCounter++

	return nil, nil
}
func (e *StubClient) DistributeFees(jobId *big.Int, claimId *big.Int) (*types.Transaction, error) {
	return nil, nil
}
func (c *StubClient) Deposit(amount *big.Int) (*types.Transaction, error) {
	return nil, nil
}
func (c *StubClient) Withdraw() (*types.Transaction, error) { return nil, nil }
func (c *StubClient) BroadcasterDeposit(broadcaster common.Address) (*big.Int, error) {
	return big.NewInt(0), nil
}
func (e *StubClient) GetJob(jobID *big.Int) (*lpTypes.Job, error) {
	return nil, nil
}
func (c *StubClient) GetClaim(jobID *big.Int, claimID *big.Int) (*lpTypes.Claim, error) {
	return c.Claims[int(claimID.Int64())], nil
}
func (c *StubClient) NumJobs() (*big.Int, error) { return big.NewInt(0), nil }

// Parameters

func (c *StubClient) NumActiveTranscoders() (*big.Int, error)          { return big.NewInt(0), nil }
func (c *StubClient) RoundLength() (*big.Int, error)                   { return big.NewInt(0), nil }
func (c *StubClient) RoundLockAmount() (*big.Int, error)               { return big.NewInt(0), nil }
func (c *StubClient) UnbondingPeriod() (uint64, error)                 { return 0, nil }
func (c *StubClient) VerificationRate() (uint64, error)                { return 0, nil }
func (c *StubClient) VerificationPeriod() (*big.Int, error)            { return big.NewInt(0), nil }
func (c *StubClient) VerificationSlashingPeriod() (*big.Int, error)    { return big.NewInt(0), nil }
func (c *StubClient) FailedVerificationSlashAmount() (*big.Int, error) { return big.NewInt(0), nil }
func (c *StubClient) MissedVerificationSlashAmount() (*big.Int, error) { return big.NewInt(0), nil }
func (c *StubClient) DoubleClaimSegmentSlashAmount() (*big.Int, error) { return big.NewInt(0), nil }
func (c *StubClient) FinderFee() (*big.Int, error)                     { return big.NewInt(0), nil }
func (c *StubClient) Inflation() (*big.Int, error)                     { return big.NewInt(0), nil }
func (c *StubClient) InflationChange() (*big.Int, error)               { return big.NewInt(0), nil }
func (c *StubClient) TargetBondingRate() (*big.Int, error)             { return big.NewInt(0), nil }
func (c *StubClient) VerificationCodeHash() (string, error)            { return "", nil }

// Helpers

func (c *StubClient) ContractAddresses() map[string]common.Address { return nil }
func (c *StubClient) CheckTx(tx *types.Transaction) error          { return nil }
func (c *StubClient) ReplaceTransaction(tx *types.Transaction, method string, gasPrice *big.Int) (*types.Transaction, error) {
	return nil, nil
}
func (c *StubClient) Sign(msg []byte) ([]byte, error)          { return nil, nil }
func (c *StubClient) LatestBlockNum() (*big.Int, error)        { return big.NewInt(0), nil }
func (c *StubClient) GetGasInfo() (uint64, *big.Int)           { return 0, nil }
func (c *StubClient) SetGasInfo(uint64, *big.Int) error        { return nil }
func (c *StubClient) WatchForJob(string) (*lpTypes.Job, error) { return nil, nil }
<|endoftext|>


<commit_before>package eval

import (
	"bytes"
	"syscall"
	"testing"
	"time"
)

func TestExecCmd(t *testing.T) {
	var in, out, err bytes.Buffer
	e := New(&in, &out, &err)
	if err := e.execCmd("echo", []string{"aaa"}); err != nil {
		t.Errorf("execute command: %v", err)
	}
	if got, want := out.String(), "aaa\n"; got != want {
		t.Errorf("output: got %q, want %q", got, want)
	}
	if got := err.String(); got != "" {
		t.Errorf("error should be blank; got %q", got)
	}
}

func TestExecPipe(t *testing.T) {
	var in, out, err bytes.Buffer
	e := New(&in, &out, &err)
	if err := e.execPipe([][]string{
		{
			"echo",
			"aaa",
		},
		{
			"tr",
			"a",
			"A",
		},
	}); err != nil {
		t.Errorf("execute pipe: %v", err)
	}
	if got, want := out.String(), "AAA\n"; got != want {
		t.Errorf("output: got %q, want %q", got, want)
	}
	if got := err.String(); got != "" {
		t.Errorf("error should be blank; got %q", got)
	}
}

type myReader struct{}

func (r *myReader) Read(_ []byte) (int, error) {
	return 0, nil
}

func TestInterrupt(t *testing.T) {
	in := myReader{}
	var out, err bytes.Buffer
	e := New(&in, &out, &err)
	done := make(chan struct{})
	go func() {
		if err := e.execCmd("cat", nil); err == nil {
			t.Error("cat: error should not be nil because the command must have been interrupted")
		} else if err != ErrInterrupted {
			t.Errorf("cat: %v", err)
		}
		done <- struct{}{}
	}()
	time.Sleep(50 * time.Millisecond)
	syscall.Kill(syscall.Getpid(), syscall.SIGINT)
	<-done
}
<commit_msg>Remove unused variables, in<commit_after>package eval

import (
	"bytes"
	"syscall"
	"testing"
	"time"
)

func TestExecCmd(t *testing.T) {
	var out, err bytes.Buffer
	e := New(nil, &out, &err)
	if err := e.execCmd("echo", []string{"aaa"}); err != nil {
		t.Errorf("execute command: %v", err)
	}
	if got, want := out.String(), "aaa\n"; got != want {
		t.Errorf("output: got %q, want %q", got, want)
	}
	if got := err.String(); got != "" {
		t.Errorf("error should be blank; got %q", got)
	}
}

func TestExecPipe(t *testing.T) {
	var out, err bytes.Buffer
	e := New(nil, &out, &err)
	if err := e.execPipe([][]string{
		{
			"echo",
			"aaa",
		},
		{
			"tr",
			"a",
			"A",
		},
	}); err != nil {
		t.Errorf("execute pipe: %v", err)
	}
	if got, want := out.String(), "AAA\n"; got != want {
		t.Errorf("output: got %q, want %q", got, want)
	}
	if got := err.String(); got != "" {
		t.Errorf("error should be blank; got %q", got)
	}
}

type myReader struct{}

func (r *myReader) Read(_ []byte) (int, error) {
	return 0, nil
}

func TestInterrupt(t *testing.T) {
	in := myReader{}
	var out, err bytes.Buffer
	e := New(&in, &out, &err)
	done := make(chan struct{})
	go func() {
		if err := e.execCmd("cat", nil); err == nil {
			t.Error("cat: error should not be nil because the command must have been interrupted")
		} else if err != ErrInterrupted {
			t.Errorf("cat: %v", err)
		}
		done <- struct{}{}
	}()
	time.Sleep(50 * time.Millisecond)
	syscall.Kill(syscall.Getpid(), syscall.SIGINT)
	<-done
}
<|endoftext|>


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

//go:generate ./hooks/run_extpoints.sh

package main

import (
	"flag"
	"fmt"
	"os"
	"runtime"
	"strings"
	"time"

	"github.com/golang/glog"
	"k8s.io/apiserver/pkg/util/logs"
	"k8s.io/heapster/common/flags"
	"k8s.io/heapster/events/manager"
	"k8s.io/heapster/events/sinks"
	"k8s.io/heapster/events/sources"
	"k8s.io/heapster/version"
)

var (
	argFrequency = flag.Duration("frequency", 30*time.Second, "The resolution at which Eventer pushes events to sinks")
	argMaxProcs  = flag.Int("max_procs", 0, "max number of CPUs that can be used simultaneously. Less than 1 for default (number of cores)")
	argSources   flags.Uris
	argSinks     flags.Uris
	argVersion   bool
)

func main() {
	quitChannel := make(chan struct{}, 0)

	flag.Var(&argSources, "source", "source(s) to read events from")
	flag.Var(&argSinks, "sink", "external sink(s) that receive events")
	flag.BoolVar(&argVersion, "version", false, "print version info and exit")
	flag.Parse()

	if argVersion {
		fmt.Println(version.VersionInfo())
		os.Exit(0)
	}

	logs.InitLogs()
	defer logs.FlushLogs()

	setMaxProcs()

	glog.Infof(strings.Join(os.Args, " "))
	glog.Infof("Eventer version %v", version.HeapsterVersion)
	if err := validateFlags(); err != nil {
		glog.Fatal(err)
	}

	// sources
	if len(argSources) != 1 {
		glog.Fatal("Wrong number of sources specified")
	}
	sourceFactory := sources.NewSourceFactory()
	sources, err := sourceFactory.BuildAll(argSources)
	if err != nil {
		glog.Fatalf("Failed to create sources: %v", err)
	}
	if len(sources) != 1 {
		glog.Fatal("Requires exactly 1 source")
	}

	// sinks
	sinksFactory := sinks.NewSinkFactory()
	sinkList := sinksFactory.BuildAll(argSinks)
	if len([]flags.Uri(argSinks)) != 0 && len(sinkList) == 0 {
		glog.Fatal("No available sink to use")
	}

	for _, sink := range sinkList {
		glog.Infof("Starting with %s sink", sink.Name())
	}
	sinkManager, err := sinks.NewEventSinkManager(sinkList, sinks.DefaultSinkExportEventsTimeout, sinks.DefaultSinkStopTimeout)
	if err != nil {
		glog.Fatalf("Failed to create sink manager: %v", err)
	}

	// main manager
	manager, err := manager.NewManager(sources[0], sinkManager, *argFrequency)
	if err != nil {
		glog.Fatalf("Failed to create main manager: %v", err)
	}
	manager.Start()

	glog.Infof("Starting eventer")
	<-quitChannel
}

func validateFlags() error {
	if *argFrequency < 5*time.Second {
		return fmt.Errorf("frequency needs to be greater than 5 seconds - %d", *argFrequency)
	}
	return nil
}

func setMaxProcs() {
	// Allow as many threads as we have cores unless the user specified a value.
	var numProcs int
	if *argMaxProcs < 1 {
		numProcs = runtime.NumCPU()
	} else {
		numProcs = *argMaxProcs
	}
	runtime.GOMAXPROCS(numProcs)

	// Check if the setting was successful.
	actualNumProcs := runtime.GOMAXPROCS(0)
	if actualNumProcs != numProcs {
		glog.Warningf("Specified max procs of %d but using %d", numProcs, actualNumProcs)
	}
}
<commit_msg>fix and improve arguments' description<commit_after>// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:generate ./hooks/run_extpoints.sh

package main

import (
	"flag"
	"fmt"
	"os"
	"runtime"
	"strings"
	"time"

	"github.com/golang/glog"
	"k8s.io/apiserver/pkg/util/logs"
	"k8s.io/heapster/common/flags"
	"k8s.io/heapster/events/manager"
	"k8s.io/heapster/events/sinks"
	"k8s.io/heapster/events/sources"
	"k8s.io/heapster/version"
)

var (
	argFrequency = flag.Duration("frequency", 30*time.Second, "The frequency at which Eventer pushes events to sinks")
	argMaxProcs  = flag.Int("max_procs", 0, "Max number of logical CPUs that can be used simultaneously, default to number of logical CPUs available on the machine when not specified or less than 1")
	argSources   flags.Uris
	argSinks     flags.Uris
	argVersion   bool
)

func main() {
	quitChannel := make(chan struct{}, 0)

	flag.Var(&argSources, "source", "source(s) to read events from")
	flag.Var(&argSinks, "sink", "external sink(s) that receive events")
	flag.BoolVar(&argVersion, "version", false, "print version info and exit")
	flag.Parse()

	if argVersion {
		fmt.Println(version.VersionInfo())
		os.Exit(0)
	}

	logs.InitLogs()
	defer logs.FlushLogs()

	setMaxProcs()

	glog.Infof(strings.Join(os.Args, " "))
	glog.Infof("Eventer version %v", version.HeapsterVersion)
	if err := validateFlags(); err != nil {
		glog.Fatal(err)
	}

	// sources
	if len(argSources) != 1 {
		glog.Fatal("Wrong number of sources specified")
	}
	sourceFactory := sources.NewSourceFactory()
	sources, err := sourceFactory.BuildAll(argSources)
	if err != nil {
		glog.Fatalf("Failed to create sources: %v", err)
	}
	if len(sources) != 1 {
		glog.Fatal("Requires exactly 1 source")
	}

	// sinks
	sinksFactory := sinks.NewSinkFactory()
	sinkList := sinksFactory.BuildAll(argSinks)
	if len([]flags.Uri(argSinks)) != 0 && len(sinkList) == 0 {
		glog.Fatal("No available sink to use")
	}

	for _, sink := range sinkList {
		glog.Infof("Starting with %s sink", sink.Name())
	}
	sinkManager, err := sinks.NewEventSinkManager(sinkList, sinks.DefaultSinkExportEventsTimeout, sinks.DefaultSinkStopTimeout)
	if err != nil {
		glog.Fatalf("Failed to create sink manager: %v", err)
	}

	// main manager
	manager, err := manager.NewManager(sources[0], sinkManager, *argFrequency)
	if err != nil {
		glog.Fatalf("Failed to create main manager: %v", err)
	}
	manager.Start()

	glog.Infof("Starting eventer")
	<-quitChannel
}

func validateFlags() error {
	if *argFrequency < 5*time.Second {
		return fmt.Errorf("frequency needs to be greater than 5 seconds - %d", *argFrequency)
	}
	return nil
}

func setMaxProcs() {
	// Allow as many threads as we have cores unless the user specified a value.
	var numProcs int
	if *argMaxProcs < 1 {
		numProcs = runtime.NumCPU()
	} else {
		numProcs = *argMaxProcs
	}
	runtime.GOMAXPROCS(numProcs)

	// Check if the setting was successful.
	actualNumProcs := runtime.GOMAXPROCS(0)
	if actualNumProcs != numProcs {
		glog.Warningf("Specified max procs of %d but using %d", numProcs, actualNumProcs)
	}
}
<|endoftext|>