<commit_before>package restapi

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

	errors "github.com/go-openapi/errors"
	runtime "github.com/go-openapi/runtime"
	middleware "github.com/go-openapi/runtime/middleware"
	"github.com/go-openapi/swag"
	"golang.org/x/net/context"

	"github.com/influxdata/mrfusion"
	"github.com/influxdata/mrfusion/bolt"
	"github.com/influxdata/mrfusion/canned"
	"github.com/influxdata/mrfusion/dist"
	"github.com/influxdata/mrfusion/handlers"
	"github.com/influxdata/mrfusion/influx"
	"github.com/influxdata/mrfusion/kapacitor"
	"github.com/influxdata/mrfusion/layouts"
	fusionlog "github.com/influxdata/mrfusion/log"
	"github.com/influxdata/mrfusion/mock"
	op "github.com/influxdata/mrfusion/restapi/operations"
	"github.com/influxdata/mrfusion/uuid"
)

// This file is safe to edit. Once it exists it will not be overwritten

//go:generate swagger generate server --target .. --name  --spec ../swagger.yaml --with-context

var logger = fusionlog.New()

var devFlags = struct {
	Develop bool `short:"d" long:"develop" description:"Run server in develop mode."`
}{}

var storeFlags = struct {
	BoltPath string `short:"b" long:"bolt-path" description:"Full path to boltDB file (/Users/somebody/mrfusion.db)" env:"BOLT_PATH" default:"chronograf.db"`
}{}

var cannedFlags = struct {
	CannedPath string `short:"c" long:"canned-path" description:"Path to directory of pre-canned application layouts" env:"CANNED_PATH" default:"canned"`
}{}

func configureFlags(api *op.MrFusionAPI) {
	api.CommandLineOptionsGroups = []swag.CommandLineOptionsGroup{
		swag.CommandLineOptionsGroup{
			ShortDescription: "Develop Mode server",
			LongDescription:  "Server will use the ui/build directory directly.",
			Options:          &devFlags,
		},
		swag.CommandLineOptionsGroup{
			ShortDescription: "Default Store Backend",
			LongDescription:  "Specify the path to a BoltDB file",
			Options:          &storeFlags,
		},
		swag.CommandLineOptionsGroup{
			ShortDescription: "Directory of pre-canned layouts",
			LongDescription:  "Specify the path to a directory of pre-canned application layout files.",
			Options:          &cannedFlags,
		},
	}
}

func assets() mrfusion.Assets {
	if devFlags.Develop {
		return &dist.DebugAssets{
			Dir:     "ui/build",
			Default: "ui/build/index.html",
		}
	}
	return &dist.BindataAssets{
		Prefix:  "ui/build",
		Default: "ui/build/index.html",
	}
}

func configureAPI(api *op.MrFusionAPI) http.Handler {
	// configure the api here
	api.ServeError = errors.ServeError

	// Set your custom logger if needed. Default one is log.Printf
	// Expected interface func(string, ...interface{})
	//
	// Example:
	api.Logger = func(msg string, args ...interface{}) {
		logger.
			WithField("component", "api").
			Info(fmt.Sprintf(msg, args))
	}

	api.JSONConsumer = runtime.JSONConsumer()

	api.JSONProducer = runtime.JSONProducer()

	mockHandler := mock.NewHandler()

	api.GetHandler = op.GetHandlerFunc(mockHandler.AllRoutes)

	if len(storeFlags.BoltPath) > 0 {
		c := bolt.NewClient()
		c.Path = storeFlags.BoltPath
		if err := c.Open(); err != nil {
			panic(err)
		}

		apps := canned.NewApps(cannedFlags.CannedPath, &uuid.V4{})

		// allLayouts acts as a front-end to both the bolt layouts and the filesystem layouts.
		allLayouts := &layouts.MultiLayoutStore{
			Stores: []mrfusion.LayoutStore{
				c.LayoutStore,
				apps,
			},
		}
		h := handlers.Store{
			ExplorationStore: c.ExplorationStore,
			SourcesStore:     c.SourcesStore,
			ServersStore:     c.ServersStore,
			LayoutStore:      allLayouts,
		}

		api.DeleteSourcesIDUsersUserIDExplorationsExplorationIDHandler = op.DeleteSourcesIDUsersUserIDExplorationsExplorationIDHandlerFunc(h.DeleteExploration)
		api.GetSourcesIDUsersUserIDExplorationsExplorationIDHandler = op.GetSourcesIDUsersUserIDExplorationsExplorationIDHandlerFunc(h.Exploration)
		api.GetSourcesIDUsersUserIDExplorationsHandler = op.GetSourcesIDUsersUserIDExplorationsHandlerFunc(h.Explorations)
		api.PatchSourcesIDUsersUserIDExplorationsExplorationIDHandler = op.PatchSourcesIDUsersUserIDExplorationsExplorationIDHandlerFunc(h.UpdateExploration)
		api.PostSourcesIDUsersUserIDExplorationsHandler = op.PostSourcesIDUsersUserIDExplorationsHandlerFunc(h.NewExploration)

		api.DeleteSourcesIDHandler = op.DeleteSourcesIDHandlerFunc(h.RemoveSource)
		api.PatchSourcesIDHandler = op.PatchSourcesIDHandlerFunc(h.UpdateSource)

		api.GetSourcesHandler = op.GetSourcesHandlerFunc(h.Sources)
		api.GetSourcesIDHandler = op.GetSourcesIDHandlerFunc(h.SourcesID)
		api.PostSourcesHandler = op.PostSourcesHandlerFunc(h.NewSource)

		api.GetSourcesIDKapacitorsHandler = op.GetSourcesIDKapacitorsHandlerFunc(h.Kapacitors)
		api.PostSourcesIDKapacitorsHandler = op.PostSourcesIDKapacitorsHandlerFunc(h.NewKapacitor)

		api.GetSourcesIDKapacitorsKapaIDHandler = op.GetSourcesIDKapacitorsKapaIDHandlerFunc(h.KapacitorsID)
		api.DeleteSourcesIDKapacitorsKapaIDHandler = op.DeleteSourcesIDKapacitorsKapaIDHandlerFunc(h.RemoveKapacitor)
		api.PatchSourcesIDKapacitorsKapaIDHandler = op.PatchSourcesIDKapacitorsKapaIDHandlerFunc(h.UpdateKapacitor)

		p := handlers.InfluxProxy{
			Srcs:           c.SourcesStore,
			TimeSeries:     &influx.Client{},
			KapacitorProxy: &kapacitor.Proxy{},
			ServersStore:   c.ServersStore,
		}
		api.PostSourcesIDProxyHandler = op.PostSourcesIDProxyHandlerFunc(p.Proxy)

		api.PostSourcesIDKapacitorsKapaIDProxyHandler = op.PostSourcesIDKapacitorsKapaIDProxyHandlerFunc(p.KapacitorProxyPost)
		api.PatchSourcesIDKapacitorsKapaIDProxyHandler = op.PatchSourcesIDKapacitorsKapaIDProxyHandlerFunc(p.KapacitorProxyPatch)
		api.GetSourcesIDKapacitorsKapaIDProxyHandler = op.GetSourcesIDKapacitorsKapaIDProxyHandlerFunc(p.KapacitorProxyGet)
		api.DeleteSourcesIDKapacitorsKapaIDProxyHandler = op.DeleteSourcesIDKapacitorsKapaIDProxyHandlerFunc(p.KapacitorProxyDelete)

		api.DeleteLayoutsIDHandler = op.DeleteLayoutsIDHandlerFunc(h.RemoveLayout)
		api.GetLayoutsHandler = op.GetLayoutsHandlerFunc(h.Layouts)
		api.GetLayoutsIDHandler = op.GetLayoutsIDHandlerFunc(h.LayoutsID)
		api.PostLayoutsHandler = op.PostLayoutsHandlerFunc(h.NewLayout)
		api.PutLayoutsIDHandler = op.PutLayoutsIDHandlerFunc(h.UpdateLayout)
	} else {
		api.DeleteSourcesIDUsersUserIDExplorationsExplorationIDHandler = op.DeleteSourcesIDUsersUserIDExplorationsExplorationIDHandlerFunc(mockHandler.DeleteExploration)
		api.GetSourcesIDUsersUserIDExplorationsExplorationIDHandler = op.GetSourcesIDUsersUserIDExplorationsExplorationIDHandlerFunc(mockHandler.Exploration)
		api.GetSourcesIDUsersUserIDExplorationsHandler = op.GetSourcesIDUsersUserIDExplorationsHandlerFunc(mockHandler.Explorations)
		api.PatchSourcesIDUsersUserIDExplorationsExplorationIDHandler = op.PatchSourcesIDUsersUserIDExplorationsExplorationIDHandlerFunc(mockHandler.UpdateExploration)
		api.PostSourcesIDUsersUserIDExplorationsHandler = op.PostSourcesIDUsersUserIDExplorationsHandlerFunc(mockHandler.NewExploration)

		api.DeleteSourcesIDHandler = op.DeleteSourcesIDHandlerFunc(mockHandler.RemoveSource)
		api.PatchSourcesIDHandler = op.PatchSourcesIDHandlerFunc(mockHandler.UpdateSource)

		api.GetSourcesHandler = op.GetSourcesHandlerFunc(mockHandler.Sources)
		api.GetSourcesIDHandler = op.GetSourcesIDHandlerFunc(mockHandler.SourcesID)
		api.PostSourcesHandler = op.PostSourcesHandlerFunc(mockHandler.NewSource)
		api.PostSourcesIDProxyHandler = op.PostSourcesIDProxyHandlerFunc(mockHandler.Proxy)
	}

	api.DeleteSourcesIDRolesRoleIDHandler = op.DeleteSourcesIDRolesRoleIDHandlerFunc(func(ctx context.Context, params op.DeleteSourcesIDRolesRoleIDParams) middleware.Responder {
		return middleware.NotImplemented("operation .DeleteSourcesIDRolesRoleID has not yet been implemented")
	})

	api.DeleteSourcesIDUsersUserIDHandler = op.DeleteSourcesIDUsersUserIDHandlerFunc(func(ctx context.Context, params op.DeleteSourcesIDUsersUserIDParams) middleware.Responder {
		return middleware.NotImplemented("operation .DeleteSourcesIDUsersUserID has not yet been implemented")
	})

	api.GetSourcesIDPermissionsHandler = op.GetSourcesIDPermissionsHandlerFunc(func(ctx context.Context, params op.GetSourcesIDPermissionsParams) middleware.Responder {
		return middleware.NotImplemented("operation .GetSourcesIDPermissions has not yet been implemented")
	})
	api.GetSourcesIDRolesHandler = op.GetSourcesIDRolesHandlerFunc(func(ctx context.Context, params op.GetSourcesIDRolesParams) middleware.Responder {
		return middleware.NotImplemented("operation .GetSourcesIDRoles has not yet been implemented")
	})
	api.GetSourcesIDRolesRoleIDHandler = op.GetSourcesIDRolesRoleIDHandlerFunc(func(ctx context.Context, params op.GetSourcesIDRolesRoleIDParams) middleware.Responder {
		return middleware.NotImplemented("operation .GetSourcesIDRolesRoleID has not yet been implemented")
	})

	api.GetSourcesIDUsersHandler = op.GetSourcesIDUsersHandlerFunc(func(ctx context.Context, params op.GetSourcesIDUsersParams) middleware.Responder {
		return middleware.NotImplemented("operation .GetSourcesIDUsers has not yet been implemented")
	})
	api.GetSourcesIDUsersUserIDHandler = op.GetSourcesIDUsersUserIDHandlerFunc(func(ctx context.Context, params op.GetSourcesIDUsersUserIDParams) middleware.Responder {
		return middleware.NotImplemented("operation .GetSourcesIDUsersUserID has not yet been implemented")
	})

	api.PatchSourcesIDRolesRoleIDHandler = op.PatchSourcesIDRolesRoleIDHandlerFunc(func(ctx context.Context, params op.PatchSourcesIDRolesRoleIDParams) middleware.Responder {
		return middleware.NotImplemented("operation .PatchSourcesIDRolesRoleID has not yet been implemented")
	})

	api.PatchSourcesIDUsersUserIDHandler = op.PatchSourcesIDUsersUserIDHandlerFunc(func(ctx context.Context, params op.PatchSourcesIDUsersUserIDParams) middleware.Responder {
		return middleware.NotImplemented("operation .PatchSourcesIDUsersUserID has not yet been implemented")
	})
	api.PostSourcesIDRolesHandler = op.PostSourcesIDRolesHandlerFunc(func(ctx context.Context, params op.PostSourcesIDRolesParams) middleware.Responder {
		return middleware.NotImplemented("operation .PostSourcesIDRoles has not yet been implemented")
	})
	api.PostSourcesIDUsersHandler = op.PostSourcesIDUsersHandlerFunc(func(ctx context.Context, params op.PostSourcesIDUsersParams) middleware.Responder {
		return middleware.NotImplemented("operation .PostSourcesIDUsers has not yet been implemented")
	})

	api.GetMappingsHandler = op.GetMappingsHandlerFunc(mockHandler.GetMappings)
	api.GetSourcesIDMonitoredHandler = op.GetSourcesIDMonitoredHandlerFunc(mockHandler.MonitoredServices)

	api.ServerShutdown = func() {}

	handler := setupGlobalMiddleware(api.Serve(setupMiddlewares))
	return handler
}

// The TLS configuration before HTTPS server starts.
func configureTLS(tlsConfig *tls.Config) {
	// Make all necessary changes to the TLS configuration here.
}

// The middleware configuration is for the handler executors. These do not apply to the swagger.json document.
// The middleware executes after routing but before authentication, binding and validation
func setupMiddlewares(handler http.Handler) http.Handler {
	return handler
}

// The middleware configuration happens before anything, this middleware also applies to serving the swagger.json document.
// So this is a good place to plug in a panic handling middleware, logging and metrics
func setupGlobalMiddleware(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		logger.
			WithField("component", "server").
			WithField("remote_addr", r.RemoteAddr).
			WithField("method", r.Method).
			WithField("url", r.URL).
			Info("Serving request")

		if strings.Contains(r.URL.Path, "/chronograf/v1") {
			handler.ServeHTTP(w, r)
			return
		} else if r.URL.Path == "//" {
			http.Redirect(w, r, "/index.html", http.StatusFound)
		} else {
			assets().Handler().ServeHTTP(w, r)
			return
		}
	})
}
<commit_msg>Finer-grained logging<commit_after>package restapi

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

	errors "github.com/go-openapi/errors"
	runtime "github.com/go-openapi/runtime"
	middleware "github.com/go-openapi/runtime/middleware"
	"github.com/go-openapi/swag"
	"golang.org/x/net/context"

	"github.com/influxdata/mrfusion"
	"github.com/influxdata/mrfusion/bolt"
	"github.com/influxdata/mrfusion/canned"
	"github.com/influxdata/mrfusion/dist"
	"github.com/influxdata/mrfusion/handlers"
	"github.com/influxdata/mrfusion/influx"
	"github.com/influxdata/mrfusion/kapacitor"
	"github.com/influxdata/mrfusion/layouts"
	fusionlog "github.com/influxdata/mrfusion/log"
	"github.com/influxdata/mrfusion/mock"
	op "github.com/influxdata/mrfusion/restapi/operations"
	"github.com/influxdata/mrfusion/uuid"
)

// This file is safe to edit. Once it exists it will not be overwritten

//go:generate swagger generate server --target .. --name  --spec ../swagger.yaml --with-context

var logger = fusionlog.New()

var devFlags = struct {
	Develop bool `short:"d" long:"develop" description:"Run server in develop mode."`
}{}

var storeFlags = struct {
	BoltPath string `short:"b" long:"bolt-path" description:"Full path to boltDB file (/Users/somebody/mrfusion.db)" env:"BOLT_PATH" default:"chronograf.db"`
}{}

var cannedFlags = struct {
	CannedPath string `short:"c" long:"canned-path" description:"Path to directory of pre-canned application layouts" env:"CANNED_PATH" default:"canned"`
}{}

func configureFlags(api *op.MrFusionAPI) {
	api.CommandLineOptionsGroups = []swag.CommandLineOptionsGroup{
		swag.CommandLineOptionsGroup{
			ShortDescription: "Develop Mode server",
			LongDescription:  "Server will use the ui/build directory directly.",
			Options:          &devFlags,
		},
		swag.CommandLineOptionsGroup{
			ShortDescription: "Default Store Backend",
			LongDescription:  "Specify the path to a BoltDB file",
			Options:          &storeFlags,
		},
		swag.CommandLineOptionsGroup{
			ShortDescription: "Directory of pre-canned layouts",
			LongDescription:  "Specify the path to a directory of pre-canned application layout files.",
			Options:          &cannedFlags,
		},
	}
}

func assets() mrfusion.Assets {
	if devFlags.Develop {
		return &dist.DebugAssets{
			Dir:     "ui/build",
			Default: "ui/build/index.html",
		}
	}
	return &dist.BindataAssets{
		Prefix:  "ui/build",
		Default: "ui/build/index.html",
	}
}

func configureAPI(api *op.MrFusionAPI) http.Handler {
	// configure the api here
	api.ServeError = errors.ServeError

	// Set your custom logger if needed. Default one is log.Printf
	// Expected interface func(string, ...interface{})
	//
	// Example:
	api.Logger = func(msg string, args ...interface{}) {
		logger.
			WithField("component", "api").
			Info(fmt.Sprintf(msg, args))
	}

	api.JSONConsumer = runtime.JSONConsumer()

	api.JSONProducer = runtime.JSONProducer()

	mockHandler := mock.NewHandler()

	api.GetHandler = op.GetHandlerFunc(mockHandler.AllRoutes)

	if len(storeFlags.BoltPath) > 0 {
		c := bolt.NewClient()
		c.Path = storeFlags.BoltPath
		if err := c.Open(); err != nil {
			panic(err)
		}

		apps := canned.NewApps(cannedFlags.CannedPath, &uuid.V4{})

		// allLayouts acts as a front-end to both the bolt layouts and the filesystem layouts.
		allLayouts := &layouts.MultiLayoutStore{
			Stores: []mrfusion.LayoutStore{
				c.LayoutStore,
				apps,
			},
		}
		h := handlers.Store{
			ExplorationStore: c.ExplorationStore,
			SourcesStore:     c.SourcesStore,
			ServersStore:     c.ServersStore,
			LayoutStore:      allLayouts,
		}

		api.DeleteSourcesIDUsersUserIDExplorationsExplorationIDHandler = op.DeleteSourcesIDUsersUserIDExplorationsExplorationIDHandlerFunc(h.DeleteExploration)
		api.GetSourcesIDUsersUserIDExplorationsExplorationIDHandler = op.GetSourcesIDUsersUserIDExplorationsExplorationIDHandlerFunc(h.Exploration)
		api.GetSourcesIDUsersUserIDExplorationsHandler = op.GetSourcesIDUsersUserIDExplorationsHandlerFunc(h.Explorations)
		api.PatchSourcesIDUsersUserIDExplorationsExplorationIDHandler = op.PatchSourcesIDUsersUserIDExplorationsExplorationIDHandlerFunc(h.UpdateExploration)
		api.PostSourcesIDUsersUserIDExplorationsHandler = op.PostSourcesIDUsersUserIDExplorationsHandlerFunc(h.NewExploration)

		api.DeleteSourcesIDHandler = op.DeleteSourcesIDHandlerFunc(h.RemoveSource)
		api.PatchSourcesIDHandler = op.PatchSourcesIDHandlerFunc(h.UpdateSource)

		api.GetSourcesHandler = op.GetSourcesHandlerFunc(h.Sources)
		api.GetSourcesIDHandler = op.GetSourcesIDHandlerFunc(h.SourcesID)
		api.PostSourcesHandler = op.PostSourcesHandlerFunc(h.NewSource)

		api.GetSourcesIDKapacitorsHandler = op.GetSourcesIDKapacitorsHandlerFunc(h.Kapacitors)
		api.PostSourcesIDKapacitorsHandler = op.PostSourcesIDKapacitorsHandlerFunc(h.NewKapacitor)

		api.GetSourcesIDKapacitorsKapaIDHandler = op.GetSourcesIDKapacitorsKapaIDHandlerFunc(h.KapacitorsID)
		api.DeleteSourcesIDKapacitorsKapaIDHandler = op.DeleteSourcesIDKapacitorsKapaIDHandlerFunc(h.RemoveKapacitor)
		api.PatchSourcesIDKapacitorsKapaIDHandler = op.PatchSourcesIDKapacitorsKapaIDHandlerFunc(h.UpdateKapacitor)

		p := handlers.InfluxProxy{
			Srcs:           c.SourcesStore,
			TimeSeries:     &influx.Client{},
			KapacitorProxy: &kapacitor.Proxy{},
			ServersStore:   c.ServersStore,
		}
		api.PostSourcesIDProxyHandler = op.PostSourcesIDProxyHandlerFunc(p.Proxy)

		api.PostSourcesIDKapacitorsKapaIDProxyHandler = op.PostSourcesIDKapacitorsKapaIDProxyHandlerFunc(p.KapacitorProxyPost)
		api.PatchSourcesIDKapacitorsKapaIDProxyHandler = op.PatchSourcesIDKapacitorsKapaIDProxyHandlerFunc(p.KapacitorProxyPatch)
		api.GetSourcesIDKapacitorsKapaIDProxyHandler = op.GetSourcesIDKapacitorsKapaIDProxyHandlerFunc(p.KapacitorProxyGet)
		api.DeleteSourcesIDKapacitorsKapaIDProxyHandler = op.DeleteSourcesIDKapacitorsKapaIDProxyHandlerFunc(p.KapacitorProxyDelete)

		api.DeleteLayoutsIDHandler = op.DeleteLayoutsIDHandlerFunc(h.RemoveLayout)
		api.GetLayoutsHandler = op.GetLayoutsHandlerFunc(h.Layouts)
		api.GetLayoutsIDHandler = op.GetLayoutsIDHandlerFunc(h.LayoutsID)
		api.PostLayoutsHandler = op.PostLayoutsHandlerFunc(h.NewLayout)
		api.PutLayoutsIDHandler = op.PutLayoutsIDHandlerFunc(h.UpdateLayout)
	} else {
		api.DeleteSourcesIDUsersUserIDExplorationsExplorationIDHandler = op.DeleteSourcesIDUsersUserIDExplorationsExplorationIDHandlerFunc(mockHandler.DeleteExploration)
		api.GetSourcesIDUsersUserIDExplorationsExplorationIDHandler = op.GetSourcesIDUsersUserIDExplorationsExplorationIDHandlerFunc(mockHandler.Exploration)
		api.GetSourcesIDUsersUserIDExplorationsHandler = op.GetSourcesIDUsersUserIDExplorationsHandlerFunc(mockHandler.Explorations)
		api.PatchSourcesIDUsersUserIDExplorationsExplorationIDHandler = op.PatchSourcesIDUsersUserIDExplorationsExplorationIDHandlerFunc(mockHandler.UpdateExploration)
		api.PostSourcesIDUsersUserIDExplorationsHandler = op.PostSourcesIDUsersUserIDExplorationsHandlerFunc(mockHandler.NewExploration)

		api.DeleteSourcesIDHandler = op.DeleteSourcesIDHandlerFunc(mockHandler.RemoveSource)
		api.PatchSourcesIDHandler = op.PatchSourcesIDHandlerFunc(mockHandler.UpdateSource)

		api.GetSourcesHandler = op.GetSourcesHandlerFunc(mockHandler.Sources)
		api.GetSourcesIDHandler = op.GetSourcesIDHandlerFunc(mockHandler.SourcesID)
		api.PostSourcesHandler = op.PostSourcesHandlerFunc(mockHandler.NewSource)
		api.PostSourcesIDProxyHandler = op.PostSourcesIDProxyHandlerFunc(mockHandler.Proxy)
	}

	api.DeleteSourcesIDRolesRoleIDHandler = op.DeleteSourcesIDRolesRoleIDHandlerFunc(func(ctx context.Context, params op.DeleteSourcesIDRolesRoleIDParams) middleware.Responder {
		return middleware.NotImplemented("operation .DeleteSourcesIDRolesRoleID has not yet been implemented")
	})

	api.DeleteSourcesIDUsersUserIDHandler = op.DeleteSourcesIDUsersUserIDHandlerFunc(func(ctx context.Context, params op.DeleteSourcesIDUsersUserIDParams) middleware.Responder {
		return middleware.NotImplemented("operation .DeleteSourcesIDUsersUserID has not yet been implemented")
	})

	api.GetSourcesIDPermissionsHandler = op.GetSourcesIDPermissionsHandlerFunc(func(ctx context.Context, params op.GetSourcesIDPermissionsParams) middleware.Responder {
		return middleware.NotImplemented("operation .GetSourcesIDPermissions has not yet been implemented")
	})
	api.GetSourcesIDRolesHandler = op.GetSourcesIDRolesHandlerFunc(func(ctx context.Context, params op.GetSourcesIDRolesParams) middleware.Responder {
		return middleware.NotImplemented("operation .GetSourcesIDRoles has not yet been implemented")
	})
	api.GetSourcesIDRolesRoleIDHandler = op.GetSourcesIDRolesRoleIDHandlerFunc(func(ctx context.Context, params op.GetSourcesIDRolesRoleIDParams) middleware.Responder {
		return middleware.NotImplemented("operation .GetSourcesIDRolesRoleID has not yet been implemented")
	})

	api.GetSourcesIDUsersHandler = op.GetSourcesIDUsersHandlerFunc(func(ctx context.Context, params op.GetSourcesIDUsersParams) middleware.Responder {
		return middleware.NotImplemented("operation .GetSourcesIDUsers has not yet been implemented")
	})
	api.GetSourcesIDUsersUserIDHandler = op.GetSourcesIDUsersUserIDHandlerFunc(func(ctx context.Context, params op.GetSourcesIDUsersUserIDParams) middleware.Responder {
		return middleware.NotImplemented("operation .GetSourcesIDUsersUserID has not yet been implemented")
	})

	api.PatchSourcesIDRolesRoleIDHandler = op.PatchSourcesIDRolesRoleIDHandlerFunc(func(ctx context.Context, params op.PatchSourcesIDRolesRoleIDParams) middleware.Responder {
		return middleware.NotImplemented("operation .PatchSourcesIDRolesRoleID has not yet been implemented")
	})

	api.PatchSourcesIDUsersUserIDHandler = op.PatchSourcesIDUsersUserIDHandlerFunc(func(ctx context.Context, params op.PatchSourcesIDUsersUserIDParams) middleware.Responder {
		return middleware.NotImplemented("operation .PatchSourcesIDUsersUserID has not yet been implemented")
	})
	api.PostSourcesIDRolesHandler = op.PostSourcesIDRolesHandlerFunc(func(ctx context.Context, params op.PostSourcesIDRolesParams) middleware.Responder {
		return middleware.NotImplemented("operation .PostSourcesIDRoles has not yet been implemented")
	})
	api.PostSourcesIDUsersHandler = op.PostSourcesIDUsersHandlerFunc(func(ctx context.Context, params op.PostSourcesIDUsersParams) middleware.Responder {
		return middleware.NotImplemented("operation .PostSourcesIDUsers has not yet been implemented")
	})

	api.GetMappingsHandler = op.GetMappingsHandlerFunc(mockHandler.GetMappings)
	api.GetSourcesIDMonitoredHandler = op.GetSourcesIDMonitoredHandlerFunc(mockHandler.MonitoredServices)

	api.ServerShutdown = func() {}

	handler := setupGlobalMiddleware(api.Serve(setupMiddlewares))
	return handler
}

// The TLS configuration before HTTPS server starts.
func configureTLS(tlsConfig *tls.Config) {
	// Make all necessary changes to the TLS configuration here.
}

// The middleware configuration is for the handler executors. These do not apply to the swagger.json document.
// The middleware executes after routing but before authentication, binding and validation
func setupMiddlewares(handler http.Handler) http.Handler {
	return handler
}

// The middleware configuration happens before anything, this middleware also applies to serving the swagger.json document.
// So this is a good place to plug in a panic handling middleware, logging and metrics
func setupGlobalMiddleware(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		l := logger.
			WithField("component", "server").
			WithField("remote_addr", r.RemoteAddr).
			WithField("method", r.Method).
			WithField("url", r.URL)

		if strings.Contains(r.URL.Path, "/chronograf/v1") {
			l.Info("Serving API Request")
			handler.ServeHTTP(w, r)
			return
		} else if r.URL.Path == "//" {
			l.Info("Serving root redirect")
			http.Redirect(w, r, "/index.html", http.StatusFound)
		} else {
			l.Info("Serving assets")
			assets().Handler().ServeHTTP(w, r)
			return
		}
	})
}
<|endoftext|>


<commit_before>// chris 090115

// TODO Test on Linux and Windows.

// Package lockfile implements convenient lock file utilities for
// Unix-based systems.
//
// Removable Lock Files - The Difficulty
//
// Removable lock files are notoriously difficult to get right.  On BSD
// systems, doing this in a race-free manner is trivial, via O_EXLOCK in
// an open(2) call, but this is generally unavailable on Unix-like
// systems due to Linux's lack of support for this option.
//
// Consider several processes' hypothetical sequences of open, lock,
// close (thus implicitly removing the kernel advisory lock), and
// unlink.
//
//	A       B       C
//	open
//	        open
//	lock
//	close
//	        lock
//	unlink
//	                open
//	                lock
//
// Now B thinks it's got a lock, but its lock file has been removed.  C
// has opened the same lock file name, thus creating a new file, and
// locked it.  So now B and C both think they've got the lock.  Game
// over.
//
// You might attempt re-arranging the close and unlink calls, but the
// problem remains.  In general, if B opens the same file as A, and B
// locks after A closes, then B can have a lock on a dangling file
// descriptor.
//
// The general problem is that the close and unlink steps are not
// atomic.
//
// Removable Lock Files - A Solution
//
// One solution is to guard the two halves of the removable lock file
// operations, open and lock, and close and unlink, with another lock
// file that is itself not removed.  This is the approach that this
// package takes with LockRm.  Using this approach, removable lock files
// may be implemented with in a race-free manner.
package lockfile

// Close calls' errors are not handled explicitly.  The error conditions
// all end up with the file descriptor being closed anyway, so there is
// nothing special to handle.

import (
	"os"

	"golang.org/x/sys/unix"
)

const mode = 0666

// Obtain a LockContext by calling Lock or LockNb.  It represents a
// locked file.
type LockContext struct {
	f *os.File
}

// Obtain a LockRmContext by calling LockRm.  It represents a locked
// file that can be removed on Unlock.
type LockRmContext struct {
	globalname string

	local *LockContext
}

// lock is the internal implementation for Lock and LockNb.  You merely
// specify whether or not you want the flock call to block by passing
// the block boolean.
func lock(filename string, block bool) (*LockContext, error) {
	f, err := os.OpenFile(filename, os.O_CREATE, mode)
	if err != nil {
		return nil, err
	}

	how := unix.LOCK_EX
	if !block {
		how = how | unix.LOCK_NB
	}
	if err := unix.Flock(int(f.Fd()), how); err != nil {
		f.Close()
		return nil, err
	}

	return &LockContext{f}, nil
}

// Lock locks on the filename given and returns a new LockContext, on
// which you can later call Unlock.  This implementation blocks, and
// does not clean up the lock file on Unlock.
func Lock(filename string) (*LockContext, error) {
	return lock(filename, true)
}

// LockNb locks on the filename given and returns a new LockContext, on
// which you can later call Unlock.  This implementation does not block,
// and does not clean up the lock file on Unlock.
func LockNb(filename string) (*LockContext, error) {
	return lock(filename, false)
}

// Unlock unlocks the lock file represented by the LockContext.
func (lc *LockContext) Unlock() {
	// Close implicitly releases any kernel advisory locks.
	lc.f.Close()
}

// globalCtx wraps an inner function with a blocking Lock on a global
// lock file.  This is race-free since the global lock file is not
// removed.
func globalCtx(globalname string, inner func() error) error {
	glc, err := Lock(globalname)
	if err != nil {
		return err
	}
	defer glc.Unlock()
	return inner()
}

// LockRm implements a removable lock file, specified by localname.
// This implementation does not block, and removes the lock file on
// Unlock.
//
// On BSD systems, doing this in a race-free manner is trivial, via
// O_EXLOCK in an open(2) call, but this is generally unavailable on
// Unix-like systems due to Linux's lack of support for this option.
//
// With the normal facilities provided, removing a lock file on unlock
// creates race conditions.  However, if the "local" lock file
// operations are secured by use of a "global" lock file, which is
// itself not removed, this can be implemented in a race-free manner.
func LockRm(globalname, localname string) (*LockRmContext, error) {
	var lrc *LockRmContext
	err := globalCtx(globalname, func() error {
		llc, err := LockNb(localname)
		if err != nil {
			return err
		}
		lrc = &LockRmContext{
			globalname: globalname,
			local:      llc,
		}
		return nil
	})
	return lrc, err
}

// Unlock unlocks and removes the lock file represented by the
// LockRmContext.
func (lrc *LockRmContext) Unlock() error {
	return globalCtx(lrc.globalname, func() error {
		lrc.local.Unlock()
		return os.Remove(lrc.local.f.Name())
	})
}
<commit_msg>lockfile: Removes unnecessary mode constant.<commit_after>// chris 090115

// TODO Test on Linux and Windows.

// Package lockfile implements convenient lock file utilities for
// Unix-based systems.
//
// Removable Lock Files - The Difficulty
//
// Removable lock files are notoriously difficult to get right.  On BSD
// systems, doing this in a race-free manner is trivial, via O_EXLOCK in
// an open(2) call, but this is generally unavailable on Unix-like
// systems due to Linux's lack of support for this option.
//
// Consider several processes' hypothetical sequences of open, lock,
// close (thus implicitly removing the kernel advisory lock), and
// unlink.
//
//	A       B       C
//	open
//	        open
//	lock
//	close
//	        lock
//	unlink
//	                open
//	                lock
//
// Now B thinks it's got a lock, but its lock file has been removed.  C
// has opened the same lock file name, thus creating a new file, and
// locked it.  So now B and C both think they've got the lock.  Game
// over.
//
// You might attempt re-arranging the close and unlink calls, but the
// problem remains.  In general, if B opens the same file as A, and B
// locks after A closes, then B can have a lock on a dangling file
// descriptor.
//
// The general problem is that the close and unlink steps are not
// atomic.
//
// Removable Lock Files - A Solution
//
// One solution is to guard the two halves of the removable lock file
// operations, open and lock, and close and unlink, with another lock
// file that is itself not removed.  This is the approach that this
// package takes with LockRm.  Using this approach, removable lock files
// may be implemented with in a race-free manner.
package lockfile

// Close calls' errors are not handled explicitly.  The error conditions
// all end up with the file descriptor being closed anyway, so there is
// nothing special to handle.

import (
	"os"

	"golang.org/x/sys/unix"
)

// Obtain a LockContext by calling Lock or LockNb.  It represents a
// locked file.
type LockContext struct {
	f *os.File
}

// Obtain a LockRmContext by calling LockRm.  It represents a locked
// file that can be removed on Unlock.
type LockRmContext struct {
	globalname string

	local *LockContext
}

// lock is the internal implementation for Lock and LockNb.  You merely
// specify whether or not you want the flock call to block by passing
// the block boolean.
func lock(filename string, block bool) (*LockContext, error) {
	f, err := os.OpenFile(filename, os.O_CREATE, 0666)
	if err != nil {
		return nil, err
	}

	how := unix.LOCK_EX
	if !block {
		how = how | unix.LOCK_NB
	}
	if err := unix.Flock(int(f.Fd()), how); err != nil {
		f.Close()
		return nil, err
	}

	return &LockContext{f}, nil
}

// Lock locks on the filename given and returns a new LockContext, on
// which you can later call Unlock.  This implementation blocks, and
// does not clean up the lock file on Unlock.
func Lock(filename string) (*LockContext, error) {
	return lock(filename, true)
}

// LockNb locks on the filename given and returns a new LockContext, on
// which you can later call Unlock.  This implementation does not block,
// and does not clean up the lock file on Unlock.
func LockNb(filename string) (*LockContext, error) {
	return lock(filename, false)
}

// Unlock unlocks the lock file represented by the LockContext.
func (lc *LockContext) Unlock() {
	// Close implicitly releases any kernel advisory locks.
	lc.f.Close()
}

// globalCtx wraps an inner function with a blocking Lock on a global
// lock file.  This is race-free since the global lock file is not
// removed.
func globalCtx(globalname string, inner func() error) error {
	glc, err := Lock(globalname)
	if err != nil {
		return err
	}
	defer glc.Unlock()
	return inner()
}

// LockRm implements a removable lock file, specified by localname.
// This implementation does not block, and removes the lock file on
// Unlock.
//
// On BSD systems, doing this in a race-free manner is trivial, via
// O_EXLOCK in an open(2) call, but this is generally unavailable on
// Unix-like systems due to Linux's lack of support for this option.
//
// With the normal facilities provided, removing a lock file on unlock
// creates race conditions.  However, if the "local" lock file
// operations are secured by use of a "global" lock file, which is
// itself not removed, this can be implemented in a race-free manner.
func LockRm(globalname, localname string) (*LockRmContext, error) {
	var lrc *LockRmContext
	err := globalCtx(globalname, func() error {
		llc, err := LockNb(localname)
		if err != nil {
			return err
		}
		lrc = &LockRmContext{
			globalname: globalname,
			local:      llc,
		}
		return nil
	})
	return lrc, err
}

// Unlock unlocks and removes the lock file represented by the
// LockRmContext.
func (lrc *LockRmContext) Unlock() error {
	return globalCtx(lrc.globalname, func() error {
		lrc.local.Unlock()
		return os.Remove(lrc.local.f.Name())
	})
}
<|endoftext|>


<commit_before>// Package memstore is an in-memory implementation of the UpdateStore interface.
package memstore

import (
	"partisci/version"
	"time"
)

// MemoryStore is an in-memory implementation of the UpdateStore interface.
type MemoryStore struct {
	version   map[string]version.Version
	app       map[string]version.AppSummary
	host      map[string]version.HostSummary
	threshold time.Time
}

func initMemoryStore(m *MemoryStore) {
	m.version = make(map[string]version.Version)
	m.app = make(map[string]version.AppSummary)
	m.host = make(map[string]version.HostSummary)
	m.threshold = time.Now()
}

// NewMemoryStore returns a empty MemoryStore.
func NewMemoryStore() (m *MemoryStore) {
	m = new(MemoryStore)
	initMemoryStore(m)
	return
}

// Apps returns summary information about each application, based on the known Versions.
func (s *MemoryStore) Apps() []version.AppSummary {
	vs := make([]version.AppSummary, 0)
	for _, v := range s.app {
		vs = append(vs, v)
	}
	return vs
}

// Hosts returns summary information about each host, based on the known Versions.
func (s *MemoryStore) Hosts() []version.HostSummary {
	vs := make([]version.HostSummary, 0)
	for _, v := range s.host {
		vs = append(vs, v)
	}
	return vs
}

// Versions returns full Version structs where their values match app_id, host
// and ver. Zero length strings are considered a match for all Versions.
func (s *MemoryStore) Versions(app_id string,
	host string, ver string) []version.Version {
	vs := make([]version.Version, 0)
	for _, v := range s.version {
		if (len(app_id) == 0 || app_id == v.AppId) &&
			(len(host) == 0 || host == v.Host) &&
			(len(ver) == 0 || ver == v.Ver) {
			vs = append(vs, v)
		}
	}
	return vs
}

// Update stores a Version and updates app and host summaries.
func (s *MemoryStore) Update(v version.Version) (err error) {
	key := v.Key()
	_, vpresent := s.version[key]
	if v.ExactUpdate.After(s.threshold) {
		s.version[key] = v
	}

	// app map
	as, present := s.app[v.AppId]
	if present {
		as.LastUpdate = v.LastUpdate
		if !vpresent {
			as.HostCount++
		}
	} else {
		appv := version.AppSummary{
			App:        v.App,
			AppId:      v.AppId,
			LastUpdate: v.LastUpdate,
			HostCount:  1,
		}
		s.app[v.AppId] = appv
	}

	// host map
	hostv := version.HostSummary{
		Host:       v.Host,
		LastUpdate: v.LastUpdate,
	}
	s.host[v.Host] = hostv
	return
}

// Clear empties the MemoryStore.
func (s *MemoryStore) Clear() {
	initMemoryStore(s)
}
<commit_msg>added godoc comments<commit_after>// Package memstore is an in-memory implementation of the UpdateStore interface.
package memstore

import (
	"partisci/version"
	"time"
)

// MemoryStore is an in-memory implementation of the UpdateStore interface.
type MemoryStore struct {
	version   map[string]version.Version
	app       map[string]version.AppSummary
	host      map[string]version.HostSummary
	threshold time.Time
}

func initMemoryStore(m *MemoryStore) {
	m.version = make(map[string]version.Version)
	m.app = make(map[string]version.AppSummary)
	m.host = make(map[string]version.HostSummary)
	m.threshold = time.Now()
}

// NewMemoryStore returns a new, initialized MemoryStore.
func NewMemoryStore() (m *MemoryStore) {
	m = new(MemoryStore)
	initMemoryStore(m)
	return
}

// Apps returns summary information about each application, based on the known Versions.
func (s *MemoryStore) Apps() []version.AppSummary {
	vs := make([]version.AppSummary, 0)
	for _, v := range s.app {
		vs = append(vs, v)
	}
	return vs
}

// Hosts returns summary information about each host, based on the known Versions.
func (s *MemoryStore) Hosts() []version.HostSummary {
	vs := make([]version.HostSummary, 0)
	for _, v := range s.host {
		vs = append(vs, v)
	}
	return vs
}

// Versions returns full Version structs where their values match app_id, host
// and ver. Zero length strings are considered a match for all Versions.
func (s *MemoryStore) Versions(app_id string,
	host string, ver string) []version.Version {
	vs := make([]version.Version, 0)
	for _, v := range s.version {
		if (len(app_id) == 0 || app_id == v.AppId) &&
			(len(host) == 0 || host == v.Host) &&
			(len(ver) == 0 || ver == v.Ver) {
			vs = append(vs, v)
		}
	}
	return vs
}

// Update stores a Version and updates app and host summaries.
func (s *MemoryStore) Update(v version.Version) (err error) {
	key := v.Key()
	_, vpresent := s.version[key]
	if v.ExactUpdate.After(s.threshold) {
		s.version[key] = v
	}

	// app map
	as, present := s.app[v.AppId]
	if present {
		as.LastUpdate = v.LastUpdate
		if !vpresent {
			as.HostCount++
		}
	} else {
		appv := version.AppSummary{
			App:        v.App,
			AppId:      v.AppId,
			LastUpdate: v.LastUpdate,
			HostCount:  1,
		}
		s.app[v.AppId] = appv
	}

	// host map
	hostv := version.HostSummary{
		Host:       v.Host,
		LastUpdate: v.LastUpdate,
	}
	s.host[v.Host] = hostv
	return
}

// Clear empties the MemoryStore.
func (s *MemoryStore) Clear() {
	initMemoryStore(s)
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2016 Dennis Chen
//
// This file is part of Clashr.
//
// Clashr is free software: you can redistribute it and/or modify it under the
// terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// Clashr is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for
// more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Clashr.  If not, see <http://www.gnu.org/licenses/>.

// Package cgroup provides a large amount of functionality for properly
// implementing cgroups in the judging and tracking of programs in Clashr.
// Most of this work is inspired by the DOMJudge implementation runguard.c and
// attempts to mimic a majoritiy of it's behavior
//
package cgroup

// #cgo pkg-config: libcgroup
// #include <libcgroup.h>
import "C"

import (
	"errors"
	"fmt"
)

// A uniform interface for the cgroup actions.
type Cgroup struct {
	name string
	cpus string
	mems int64
}

// OutputStats returns the memory used (in bytes) by a process controlled by a
// cgroup.
func (g *Cgroup) OutputStats() (int64, error) {
	var param *C.char

	param = C.CString(g.name)
	cg := C.cgroup_new_cgroup(param)
	if cg == nil {
		return 0, errors.New("cgroup_new_cgroup")
	}
	defer C.cgroup_free(&cg)

	if ret := C.cgroup_get_cgroup(cg); ret != 0 {
		err := fmt.Errorf("Get cgroup information: %s(d)",
			C.cgroup_strerror(ret), ret)
		return 0, err
	}
	param = C.CString("memory")
	cgController := C.cgroup_get_controller(cg, param)

	var maxUsage C.int64_t
	param = C.CString("memory.memsw.max_usage_in_bytes")
	if ret := C.cgroup_get_value_int64(cgController, param, &maxUsage); ret != 0 {
		err := fmt.Errorf("Get cgroup value: %s(%d)",
			C.cgroup_strerror(ret), ret)
		return 0, err
	}

	return int64(maxUsage), nil
}

// Create makes a new instance of the cgroup interface. It sets the memory
// limit of the cgroup to memsize, and the set of CPUs to use to cpuset. If
// memory does not need to be limited, set memsize to syscall.RLIMIT_INFINITY.
// Similarly, set cpuset to the empty string if CPUs do not need to be set.
func Create(cgroupname, cpuset string, memsize int64) (Cgroup, error) {
	var param *C.char

	param = C.CString(cgroupname)
	cg := C.cgroup_new_cgroup(param)
	if cg == nil {
		return Cgroup{}, errors.New("cgroup_new_cgroup")
	}
	defer C.cgroup_free(&cg)

	// Set memory restrictions. We limit both ram and ram+swap to the same
	// amount to prevent swapping.
	param = C.CString("memory")
	cgController := C.cgroup_add_controller(cg, param)

	mem := C.int64_t(memsize)
	param = C.CString("memory.limit_in_bytes")
	C.cgroup_add_value_int64(cgController, param, mem)
	param = C.CString("memory.memsw.limit_in_bytes")
	C.cgroup_add_value_int64(cgController, param, mem)

	if len(cpuset) > 0 {
		param = C.CString("cpuset")
		cgController = C.cgroup_add_controller(cg, param)

		var arg *C.char
		param = C.CString("cpuset.mems")
		arg = C.CString("0")
		C.cgroup_add_value_string(cgController, param, arg)
		param = C.CString("cpuset.cpus")
		arg = C.CString(cpuset)
		C.cgroup_add_value_string(cgController, param, arg)
	}
	return Cgroup{cgroupname, cpuset, memsize}, nil
}
<commit_msg>cgroup: actually create a new cgroup instead of break<commit_after>//
// Copyright (c) 2016 Dennis Chen
//
// This file is part of Clashr.
//
// Clashr is free software: you can redistribute it and/or modify it under the
// terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// Clashr is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for
// more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Clashr.  If not, see <http://www.gnu.org/licenses/>.

// Package cgroup provides a large amount of functionality for properly
// implementing cgroups in the judging and tracking of programs in Clashr.
// Most of this work is inspired by the DOMJudge implementation runguard.c and
// attempts to mimic a majoritiy of it's behavior
//
package cgroup

// #cgo pkg-config: libcgroup
// #include <libcgroup.h>
import "C"

import (
	"errors"
	"fmt"
)

// A uniform interface for the cgroup actions.
type Cgroup struct {
	name string
	cpus string
	mems int64
}

// OutputStats returns the memory used (in bytes) by a process controlled by a
// cgroup.
func (g *Cgroup) OutputStats() (int64, error) {
	var param *C.char

	param = C.CString(g.name)
	cg := C.cgroup_new_cgroup(param)
	if cg == nil {
		return 0, errors.New("cgroup_new_cgroup")
	}
	defer C.cgroup_free(&cg)

	if ret := C.cgroup_get_cgroup(cg); ret != 0 {
		err := fmt.Errorf("Get cgroup information: %s(d)",
			C.cgroup_strerror(ret), ret)
		return 0, err
	}
	param = C.CString("memory")
	cgController := C.cgroup_get_controller(cg, param)

	var maxUsage C.int64_t
	param = C.CString("memory.memsw.max_usage_in_bytes")
	if ret := C.cgroup_get_value_int64(cgController, param, &maxUsage); ret != 0 {
		err := fmt.Errorf("Get cgroup value: %s(%d)",
			C.cgroup_strerror(ret), ret)
		return 0, err
	}

	return int64(maxUsage), nil
}

// Create makes a new instance of the cgroup interface. It sets the memory
// limit of the cgroup to memsize, and the set of CPUs to use to cpuset. If
// memory does not need to be limited, set memsize to syscall.RLIMIT_INFINITY.
// Similarly, set cpuset to the empty string if CPUs do not need to be set.
func Create(cgroupname, cpuset string, memsize int64) (Cgroup, error) {
	var param *C.char

	param = C.CString(cgroupname)
	cg := C.cgroup_new_cgroup(param)
	if cg == nil {
		return Cgroup{}, errors.New("cgroup_new_cgroup")
	}
	defer C.cgroup_free(&cg)

	// Set memory restrictions. We limit both ram and ram+swap to the same
	// amount to prevent swapping.
	param = C.CString("memory")
	cgController := C.cgroup_add_controller(cg, param)

	mem := C.int64_t(memsize)
	param = C.CString("memory.limit_in_bytes")
	C.cgroup_add_value_int64(cgController, param, mem)
	param = C.CString("memory.memsw.limit_in_bytes")
	C.cgroup_add_value_int64(cgController, param, mem)

	// Setup CPU restrictions. The task is pinned to a specific set of CPUs
	// if a non-empty string is passed.
	if len(cpuset) > 0 {
		param = C.CString("cpuset")
		cgController = C.cgroup_add_controller(cg, param)

		var arg *C.char
		param = C.CString("cpuset.mems")
		arg = C.CString("0")
		C.cgroup_add_value_string(cgController, param, arg)
		param = C.CString("cpuset.cpus")
		arg = C.CString(cpuset)
		C.cgroup_add_value_string(cgController, param, arg)
	}

	// Perform the creation of the cgroup.
	if ret := C.cgroup_create_cgroup(cg, 1); ret != 0 {
		err := fmt.Errorf("Creating cgroup: %s(%d)",
			C.cgroup_stderror(ret), ret)
		return Cgroup{}, err
	}
	return Cgroup{cgroupname, cpuset, memsize}, nil
}
<|endoftext|>


<commit_before>// Copyright 2011, 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package charm

import (
	"fmt"
	"io"
	"io/ioutil"
	"reflect"

	"github.com/xeipuuv/gojsonschema"
	"launchpad.net/goyaml"
)

// Actions defines the available actions for the charm.
type Actions struct {
	ActionSpecs map[string]ActionSpec
}

// ActionSpec is a definition of the parameters and traits of an Action.
type ActionSpec struct {
	Description string
	Params      map[string]interface{}
}

// NewActions returns a new Actions object without any defined content.
func NewActions() *Actions {
	return &Actions{map[string]ActionSpec{}}
}

// ReadActions builds an Actions spec from a charm's actions.yaml.
func ReadActionsYaml(r io.Reader) (*Actions, error) {
	data, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}
	var actionsSpec *Actions
	if err := goyaml.Unmarshal(data, &actionsSpec); err != nil {
		return nil, err
	}
	if actionsSpec == nil {
		return nil, fmt.Errorf("Empty actions definition")
	}
	if reflect.DeepEqual(actionsSpec, &Actions{}) {
		return nil, fmt.Errorf("actions.yaml failed to unmarshal -- key mismatch")
	}
	for _, actionSpec := range actionsSpec.ActionSpecs {
		_, err := gojsonschema.NewJsonSchemaDocument(actionSpec.Params)
		if err != nil {
			return nil, fmt.Errorf("error loading Charm actions.yaml -- nonconformant params: %v", err)
		}
	}
	return actionsSpec, nil
}
<commit_msg>Applied requested changes to charm/actions.go.<commit_after>// Copyright 2011, 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package charm

import (
	"fmt"
	"io"
	"io/ioutil"
	"reflect"
	"regexp"
	"github.com/xeipuuv/gojsonschema"
	"launchpad.net/goyaml"
)

// Actions defines the available actions for the charm.
type Actions struct {
	ActionSpecs map[string]ActionSpec
}

// ActionSpec is a definition of the parameters and traits of an Action.
type ActionSpec struct {
	Description string
	Params      map[string]interface{}
}

// NewActions returns a new Actions object without any defined content.
func NewActions() *Actions {
	return &Actions{map[string]ActionSpec{}}
}

// ReadActions builds an Actions spec from a charm's actions.yaml.
func ReadActionsYaml(r io.Reader) (*Actions, error) {
	data, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}
	var actionsSpec *Actions
	if err := goyaml.Unmarshal(data, &actionsSpec); err != nil {
		return nil, err
	}
	if actionsSpec == nil {
		return nil, fmt.Errorf("empty actions definition")
	}
	if data != []byte{} && reflect.DeepEqual(actionsSpec, &Actions{}) {
		return nil, fmt.Errorf("actions.yaml failed to unmarshal -- key mismatch")
	}

	nameRule := regexp.MustCompile("^[^-][a-z-]+[^-]$")

	for name, actionSpec := range actionsSpec.ActionSpecs {
		badName := !nameRule.MatchString(name)
		if badName {
			return nil, fmt.Errorf("bad action name %s", name)
		}
		_, err := gojsonschema.NewJsonSchemaDocument(actionSpec.Params)
		if err != nil {
			return nil, fmt.Errorf("invalid params schema for action %q: %v", err)
		}
	}
	return actionsSpec, nil
}
<|endoftext|>


<commit_before>package untrusted

import (
	"fmt"

	"bazil.org/bazil/cas"
	"bazil.org/bazil/kv"
	"bazil.org/bazil/tokens"
	"code.google.com/p/go.crypto/nacl/secretbox"
	"github.com/dchest/blake2b"
)

type Convergent struct {
	// not a CAS because key derives from the plaintext version, but
	// used like a Fixed Content Storage (FCS)
	untrusted kv.KV
	secret    *[32]byte
}

var _ = kv.KV(&Convergent{})

var personalizeKey = []byte(tokens.Blake2bPersonalizationConvergentKey)

func (s *Convergent) computeBoxedKey(key []byte) []byte {
	conf := blake2b.Config{
		Size:   cas.KeySize,
		Key:    s.secret[:],
		Person: personalizeKey,
	}
	h, err := blake2b.New(&conf)
	if err != nil {
		panic(fmt.Errorf("blake2 config failure: %v", err))
	}
	// hash.Hash docs say it never fails
	_, _ = h.Write(key)
	return h.Sum(nil)
}

const nonceSize = 24

var personalizeNonce = []byte(tokens.Blake2bPersonalizationConvergentNonce)

// Nonce summarizes key, type and level so mismatch of e.g. type can
// be detected.
func (s *Convergent) makeNonce(key []byte) *[nonceSize]byte {
	conf := blake2b.Config{
		Size:   nonceSize,
		Person: personalizeNonce,
	}
	h, err := blake2b.New(&conf)
	if err != nil {
		panic(fmt.Errorf("blake2 config failure: %v", err))
	}
	// hash.Hash docs say it never fails
	_, _ = h.Write(key)

	var ret [nonceSize]byte
	h.Sum(ret[:0])
	return &ret
}

func (s *Convergent) Get(key []byte) ([]byte, error) {
	boxedkey := s.computeBoxedKey(key)
	box, err := s.untrusted.Get(boxedkey)
	if err != nil {
		return nil, err
	}

	nonce := s.makeNonce(key)
	plain, ok := secretbox.Open(nil, box, nonce, s.secret)
	if !ok {
		return nil, Corrupt{Key: key}
	}
	return plain, nil
}

func (s *Convergent) Put(key []byte, value []byte) error {
	nonce := s.makeNonce(key)
	box := secretbox.Seal(nil, value, nonce, s.secret)

	boxedkey := s.computeBoxedKey(key)
	err := s.untrusted.Put(boxedkey, box)
	return err
}

func New(store kv.KV, secret *[32]byte) *Convergent {
	return &Convergent{
		untrusted: store,
		secret:    secret,
	}
}

type Corrupt struct {
	Key []byte
}

func (c Corrupt) Error() string {
	return fmt.Sprintf("corrupt encrypted chunk: %x", c.Key)
}

var _ = error(Corrupt{})
<commit_msg>kv/untrusted: Use cgo blake2b for a 5.5x speedup in raw hashing<commit_after>package untrusted

import (
	"fmt"

	"bazil.org/bazil/cas"
	"bazil.org/bazil/kv"
	"bazil.org/bazil/tokens"
	"code.google.com/p/go.crypto/nacl/secretbox"
	"github.com/codahale/blake2"
)

type Convergent struct {
	// not a CAS because key derives from the plaintext version, but
	// used like a Fixed Content Storage (FCS)
	untrusted kv.KV
	secret    *[32]byte
}

var _ = kv.KV(&Convergent{})

var personalizeKey = []byte(tokens.Blake2bPersonalizationConvergentKey)

func (s *Convergent) computeBoxedKey(key []byte) []byte {
	conf := blake2.Config{
		Size:     cas.KeySize,
		Key:      s.secret[:],
		Personal: personalizeKey,
	}
	h := blake2.New(&conf)
	// hash.Hash docs say it never fails
	_, _ = h.Write(key)
	return h.Sum(nil)
}

const nonceSize = 24

var personalizeNonce = []byte(tokens.Blake2bPersonalizationConvergentNonce)

// Nonce summarizes key, type and level so mismatch of e.g. type can
// be detected.
func (s *Convergent) makeNonce(key []byte) *[nonceSize]byte {
	conf := blake2.Config{
		Size:     nonceSize,
		Personal: personalizeNonce,
	}
	h := blake2.New(&conf)
	// hash.Hash docs say it never fails
	_, _ = h.Write(key)

	var ret [nonceSize]byte
	h.Sum(ret[:0])
	return &ret
}

func (s *Convergent) Get(key []byte) ([]byte, error) {
	boxedkey := s.computeBoxedKey(key)
	box, err := s.untrusted.Get(boxedkey)
	if err != nil {
		return nil, err
	}

	nonce := s.makeNonce(key)
	plain, ok := secretbox.Open(nil, box, nonce, s.secret)
	if !ok {
		return nil, Corrupt{Key: key}
	}
	return plain, nil
}

func (s *Convergent) Put(key []byte, value []byte) error {
	nonce := s.makeNonce(key)
	box := secretbox.Seal(nil, value, nonce, s.secret)

	boxedkey := s.computeBoxedKey(key)
	err := s.untrusted.Put(boxedkey, box)
	return err
}

func New(store kv.KV, secret *[32]byte) *Convergent {
	return &Convergent{
		untrusted: store,
		secret:    secret,
	}
}

type Corrupt struct {
	Key []byte
}

func (c Corrupt) Error() string {
	return fmt.Sprintf("corrupt encrypted chunk: %x", c.Key)
}

var _ = error(Corrupt{})
<|endoftext|>


<commit_before>package urlvalues

import (
	"reflect"
	"strings"

	"github.com/go-pg/pg/internal/structfilter"
)

// Decode decodes url values into the struct.
func Decode(strct interface{}, values Values) error {
	v := reflect.Indirect(reflect.ValueOf(strct))
	meta := structfilter.GetStruct(v.Type())

	for name, values := range values {
		if strings.HasPrefix(name, ":") {
			name = name[1:]
		}
		if strings.HasSuffix(name, "[]") {
			name = name[:len(name)-2]
		}

		field := meta.Field(name)
		if field != nil && !field.NoDecode() {
			err := field.Scan(field.Value(v), values)
			if err != nil {
				return err
			}
		}
	}

	return nil
}
<commit_msg>urlvalues: use TrimPrefix and TrimSuffix<commit_after>package urlvalues

import (
	"reflect"
	"strings"

	"github.com/go-pg/pg/internal/structfilter"
)

// Decode decodes url values into the struct.
func Decode(strct interface{}, values Values) error {
	v := reflect.Indirect(reflect.ValueOf(strct))
	meta := structfilter.GetStruct(v.Type())

	for name, values := range values {
		name = strings.TrimPrefix(name, ":")
		name = strings.TrimSuffix(name, "[]")

		field := meta.Field(name)
		if field != nil && !field.NoDecode() {
			err := field.Scan(field.Value(v), values)
			if err != nil {
				return err
			}
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package command

import (
	"encoding/hex"
	"fmt"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/armon/go-metrics"
	"github.com/hashicorp/logutils"
	"github.com/hashicorp/vault/audit"
	"github.com/hashicorp/vault/command/server"
	"github.com/hashicorp/vault/helper/flag-slice"
	"github.com/hashicorp/vault/helper/gated-writer"
	"github.com/hashicorp/vault/helper/mlock"
	vaulthttp "github.com/hashicorp/vault/http"
	"github.com/hashicorp/vault/logical"
	"github.com/hashicorp/vault/physical"
	"github.com/hashicorp/vault/vault"
)

// ServerCommand is a Command that starts the Vault server.
type ServerCommand struct {
	AuditBackends      map[string]audit.Factory
	CredentialBackends map[string]logical.Factory
	LogicalBackends    map[string]logical.Factory

	Meta
}

func (c *ServerCommand) Run(args []string) int {
	var dev bool
	var configPath []string
	var logLevel string
	flags := c.Meta.FlagSet("server", FlagSetDefault)
	flags.BoolVar(&dev, "dev", false, "")
	flags.StringVar(&logLevel, "log-level", "info", "")
	flags.Usage = func() { c.Ui.Error(c.Help()) }
	flags.Var((*sliceflag.StringFlag)(&configPath), "config", "config")
	if err := flags.Parse(args); err != nil {
		return 1
	}

	// Validation
	if !dev && len(configPath) == 0 {
		c.Ui.Error("At least one config path must be specified with -config")
		flags.Usage()
		return 1
	}

	// Load the configuration
	var config *server.Config
	if dev {
		config = server.DevConfig()
	}
	for _, path := range configPath {
		current, err := server.LoadConfig(path)
		if err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Error loading configuration from %s: %s", path, err))
			return 1
		}

		if config == nil {
			config = current
		} else {
			config = config.Merge(current)
		}
	}

	// If mlock isn't supported, show a warning. We disable this in
	// dev because it is quite scary to see when first using Vault.
	if !dev && !mlock.Supported() {
		c.Ui.Output("==> WARNING: mlock not supported on this system!\n")
		c.Ui.Output("  The `mlock` syscall to prevent memory from being swapped to")
		c.Ui.Output("  disk is not supported on this system. Enabling mlock or")
		c.Ui.Output("  running Vault on a system with mlock is much more secure.\n")
	}

	// Create a logger. We wrap it in a gated writer so that it doesn't
	// start logging too early.
	logGate := &gatedwriter.Writer{Writer: os.Stderr}
	logger := log.New(&logutils.LevelFilter{
		Levels: []logutils.LogLevel{
			"TRACE", "DEBUG", "INFO", "WARN", "ERR"},
		MinLevel: logutils.LogLevel(strings.ToUpper(logLevel)),
		Writer:   logGate,
	}, "", log.LstdFlags)

	// Initialize the backend
	backend, err := physical.NewBackend(
		config.Backend.Type, config.Backend.Config)
	if err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Error initializing backend of type %s: %s",
			config.Backend.Type, err))
		return 1
	}

	// Attempt to detect the advertise address possible
	if detect, ok := backend.(physical.AdvertiseDetect); ok && config.Backend.AdvertiseAddr == "" {
		advertise, err := c.detectAdvertise(detect, config)
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Error detecting advertise address: %s", err))
		} else if advertise == "" {
			c.Ui.Error("Failed to detect advertise address.")
		} else {
			config.Backend.AdvertiseAddr = advertise
		}
	}

	// Initialize the core
	core, err := vault.NewCore(&vault.CoreConfig{
		AdvertiseAddr:      config.Backend.AdvertiseAddr,
		Physical:           backend,
		AuditBackends:      c.AuditBackends,
		CredentialBackends: c.CredentialBackends,
		LogicalBackends:    c.LogicalBackends,
		Logger:             logger,
		DisableMlock:       config.DisableMlock,
	})
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error initializing core: %s", err))
		return 1
	}

	// If we're in dev mode, then initialize the core
	if dev {
		init, err := c.enableDev(core)
		if err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Error initializing dev mode: %s", err))
			return 1
		}

		c.Ui.Output(fmt.Sprintf(
			"==> WARNING: Dev mode is enabled!\n\n"+
				"In this mode, Vault is completely in-memory and unsealed.\n"+
				"Vault is configured to only have a single unseal key. The root\n"+
				"token has already been authenticated with the CLI, so you can\n"+
				"immediately begin using the Vault CLI.\n\n"+
				"The only step you need to take is to set the following\n"+
				"environment variables:\n\n"+
				"    export VAULT_ADDR='http://127.0.0.1:8200'\n"+
				"    export VAULT_TOKEN='%s'\n\n"+
				"The unseal key and root token are reproduced below in case you\n"+
				"want to seal/unseal the Vault or play with authentication.\n\n"+
				"Unseal Key: %s\nRoot Token: %s\n",
			init.RootToken,
			hex.EncodeToString(init.SecretShares[0]),
			init.RootToken,
		))
	}

	// Compile server information for output later
	infoKeys := make([]string, 0, 10)
	info := make(map[string]string)
	info["backend"] = config.Backend.Type
	info["log level"] = logLevel
	info["mlock"] = fmt.Sprintf(
		"supported: %v, enabled: %v",
		mlock.Supported(), !config.DisableMlock)
	infoKeys = append(infoKeys, "log level", "mlock", "backend")

	// If the backend supports HA, then note it
	if _, ok := backend.(physical.HABackend); ok {
		info["backend"] += " (HA available)"
		info["advertise address"] = config.Backend.AdvertiseAddr
		infoKeys = append(infoKeys, "advertise address")
	}

	// Initialize the telemetry
	if err := c.setupTelementry(config); err != nil {
		c.Ui.Error(fmt.Sprintf("Error initializing telemetry: %s", err))
		return 1
	}

	// Initialize the listeners
	lns := make([]net.Listener, 0, len(config.Listeners))
	for i, lnConfig := range config.Listeners {
		ln, props, err := server.NewListener(lnConfig.Type, lnConfig.Config)
		if err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Error initializing listener of type %s: %s",
				lnConfig.Type, err))
			return 1
		}

		// Store the listener props for output later
		key := fmt.Sprintf("listener %d", i+1)
		propsList := make([]string, 0, len(props))
		for k, v := range props {
			propsList = append(propsList, fmt.Sprintf(
				"%s: %q", k, v))
		}
		sort.Strings(propsList)
		infoKeys = append(infoKeys, key)
		info[key] = fmt.Sprintf(
			"%s (%s)", lnConfig.Type, strings.Join(propsList, ", "))

		lns = append(lns, ln)
	}

	// Initialize the HTTP server
	server := &http.Server{}
	server.Handler = vaulthttp.Handler(core)
	for _, ln := range lns {
		go server.Serve(ln)
	}

	// Server configuration output
	padding := 18
	c.Ui.Output("==> Vault server configuration:\n")
	for _, k := range infoKeys {
		c.Ui.Output(fmt.Sprintf(
			"%s%s: %s",
			strings.Repeat(" ", padding-len(k)),
			strings.Title(k),
			info[k]))
	}
	c.Ui.Output("")

	// Output the header that the server has started
	c.Ui.Output("==> Vault server started! Log data will stream in below:\n")

	// Release the log gate.
	logGate.Flush()

	<-make(chan struct{})
	return 0
}

func (c *ServerCommand) enableDev(core *vault.Core) (*vault.InitResult, error) {
	// Initialize it with a basic single key
	init, err := core.Initialize(&vault.SealConfig{
		SecretShares:    1,
		SecretThreshold: 1,
	})
	if err != nil {
		return nil, err
	}

	// Copy the key so that it can be zeroed
	key := make([]byte, len(init.SecretShares[0]))
	copy(key, init.SecretShares[0])

	// Unseal the core
	unsealed, err := core.Unseal(key)
	if err != nil {
		return nil, err
	}
	if !unsealed {
		return nil, fmt.Errorf("failed to unseal Vault for dev mode")
	}

	// Set the token
	tokenHelper, err := c.TokenHelper()
	if err != nil {
		return nil, err
	}
	if err := tokenHelper.Store(init.RootToken); err != nil {
		return nil, err
	}

	return init, nil
}

// detectAdvertise is used to attempt advertise address detection
func (c *ServerCommand) detectAdvertise(detect physical.AdvertiseDetect,
	config *server.Config) (string, error) {
	// Get the hostname
	host, err := detect.DetectHostAddr()
	if err != nil {
		return "", err
	}

	// Default the port and scheme
	scheme := "https"
	port := 8200

	// Attempt to detect overrides
	for _, list := range config.Listeners {
		// Only attempt TCP
		if list.Type != "tcp" {
			continue
		}

		// Check if TLS is disabled
		if val, ok := list.Config["tls_disable"]; ok && val == "1" {
			scheme = "http"
		}

		// Check for address override
		addr, ok := list.Config["address"]
		if !ok {
			addr = "127.0.0.1:8200"
		}

		// Check for localhost
		hostStr, portStr, err := net.SplitHostPort(addr)
		if err != nil {
			continue
		}
		if hostStr == "127.0.0.1" {
			host = hostStr
		}

		// Check for custom port
		listPort, err := strconv.Atoi(portStr)
		if err != nil {
			continue
		}
		port = listPort
	}

	// Build a URL
	url := &url.URL{
		Scheme: scheme,
		Host:   fmt.Sprintf("%s:%d", host, port),
	}

	// Return the URL string
	return url.String(), nil
}

// setupTelementry is used ot setup the telemetry sub-systems
func (c *ServerCommand) setupTelementry(config *server.Config) error {
	/* Setup telemetry
	Aggregate on 10 second intervals for 1 minute. Expose the
	metrics over stderr when there is a SIGUSR1 received.
	*/
	inm := metrics.NewInmemSink(10*time.Second, time.Minute)
	metrics.DefaultInmemSignal(inm)
	metricsConf := metrics.DefaultConfig("vault")

	// Configure the statsite sink
	var fanout metrics.FanoutSink
	if config.StatsiteAddr != "" {
		sink, err := metrics.NewStatsiteSink(config.StatsiteAddr)
		if err != nil {
			return err
		}
		fanout = append(fanout, sink)
	}

	// Configure the statsd sink
	if config.StatsdAddr != "" {
		sink, err := metrics.NewStatsdSink(config.StatsdAddr)
		if err != nil {
			return err
		}
		fanout = append(fanout, sink)
	}

	// Initialize the global sink
	if len(fanout) > 0 {
		fanout = append(fanout, inm)
		metrics.NewGlobal(metricsConf, fanout)
	} else {
		metricsConf.EnableHostname = false
		metrics.NewGlobal(metricsConf, inm)
	}
	return nil
}

func (c *ServerCommand) Synopsis() string {
	return "Start a Vault server"
}

func (c *ServerCommand) Help() string {
	helpText := `
Usage: vault server [options]

  Start a Vault server.

  This command starts a Vault server that responds to API requests.
  Vault will start in a "sealed" state. The Vault must be unsealed
  with "vault unseal" or the API before this server can respond to requests.
  This must be done for every server.

  If the server is being started against a storage backend that has
  brand new (no existing Vault data in it), it must be initialized with
  "vault init" or the API first.

General Options:

  -config=<path>      Path to the configuration file or directory. This can be
                      specified multiple times. If it is a directory, all
                      files with a ".hcl" or ".json" suffix will be loaded.

  -log-level=info     Log verbosity. Defaults to "info", will be outputted
                      to stderr.

`
	return strings.TrimSpace(helpText)
}
<commit_msg>Use strconv.ParseBool<commit_after>package command

import (
	"encoding/hex"
	"fmt"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/armon/go-metrics"
	"github.com/hashicorp/logutils"
	"github.com/hashicorp/vault/audit"
	"github.com/hashicorp/vault/command/server"
	"github.com/hashicorp/vault/helper/flag-slice"
	"github.com/hashicorp/vault/helper/gated-writer"
	"github.com/hashicorp/vault/helper/mlock"
	vaulthttp "github.com/hashicorp/vault/http"
	"github.com/hashicorp/vault/logical"
	"github.com/hashicorp/vault/physical"
	"github.com/hashicorp/vault/vault"
)

// ServerCommand is a Command that starts the Vault server.
type ServerCommand struct {
	AuditBackends      map[string]audit.Factory
	CredentialBackends map[string]logical.Factory
	LogicalBackends    map[string]logical.Factory

	Meta
}

func (c *ServerCommand) Run(args []string) int {
	var dev bool
	var configPath []string
	var logLevel string
	flags := c.Meta.FlagSet("server", FlagSetDefault)
	flags.BoolVar(&dev, "dev", false, "")
	flags.StringVar(&logLevel, "log-level", "info", "")
	flags.Usage = func() { c.Ui.Error(c.Help()) }
	flags.Var((*sliceflag.StringFlag)(&configPath), "config", "config")
	if err := flags.Parse(args); err != nil {
		return 1
	}

	// Validation
	if !dev && len(configPath) == 0 {
		c.Ui.Error("At least one config path must be specified with -config")
		flags.Usage()
		return 1
	}

	// Load the configuration
	var config *server.Config
	if dev {
		config = server.DevConfig()
	}
	for _, path := range configPath {
		current, err := server.LoadConfig(path)
		if err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Error loading configuration from %s: %s", path, err))
			return 1
		}

		if config == nil {
			config = current
		} else {
			config = config.Merge(current)
		}
	}

	// If mlock isn't supported, show a warning. We disable this in
	// dev because it is quite scary to see when first using Vault.
	if !dev && !mlock.Supported() {
		c.Ui.Output("==> WARNING: mlock not supported on this system!\n")
		c.Ui.Output("  The `mlock` syscall to prevent memory from being swapped to")
		c.Ui.Output("  disk is not supported on this system. Enabling mlock or")
		c.Ui.Output("  running Vault on a system with mlock is much more secure.\n")
	}

	// Create a logger. We wrap it in a gated writer so that it doesn't
	// start logging too early.
	logGate := &gatedwriter.Writer{Writer: os.Stderr}
	logger := log.New(&logutils.LevelFilter{
		Levels: []logutils.LogLevel{
			"TRACE", "DEBUG", "INFO", "WARN", "ERR"},
		MinLevel: logutils.LogLevel(strings.ToUpper(logLevel)),
		Writer:   logGate,
	}, "", log.LstdFlags)

	// Initialize the backend
	backend, err := physical.NewBackend(
		config.Backend.Type, config.Backend.Config)
	if err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Error initializing backend of type %s: %s",
			config.Backend.Type, err))
		return 1
	}

	// Attempt to detect the advertise address possible
	if detect, ok := backend.(physical.AdvertiseDetect); ok && config.Backend.AdvertiseAddr == "" {
		advertise, err := c.detectAdvertise(detect, config)
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Error detecting advertise address: %s", err))
		} else if advertise == "" {
			c.Ui.Error("Failed to detect advertise address.")
		} else {
			config.Backend.AdvertiseAddr = advertise
		}
	}

	// Initialize the core
	core, err := vault.NewCore(&vault.CoreConfig{
		AdvertiseAddr:      config.Backend.AdvertiseAddr,
		Physical:           backend,
		AuditBackends:      c.AuditBackends,
		CredentialBackends: c.CredentialBackends,
		LogicalBackends:    c.LogicalBackends,
		Logger:             logger,
		DisableMlock:       config.DisableMlock,
	})
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error initializing core: %s", err))
		return 1
	}

	// If we're in dev mode, then initialize the core
	if dev {
		init, err := c.enableDev(core)
		if err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Error initializing dev mode: %s", err))
			return 1
		}

		c.Ui.Output(fmt.Sprintf(
			"==> WARNING: Dev mode is enabled!\n\n"+
				"In this mode, Vault is completely in-memory and unsealed.\n"+
				"Vault is configured to only have a single unseal key. The root\n"+
				"token has already been authenticated with the CLI, so you can\n"+
				"immediately begin using the Vault CLI.\n\n"+
				"The only step you need to take is to set the following\n"+
				"environment variables:\n\n"+
				"    export VAULT_ADDR='http://127.0.0.1:8200'\n"+
				"    export VAULT_TOKEN='%s'\n\n"+
				"The unseal key and root token are reproduced below in case you\n"+
				"want to seal/unseal the Vault or play with authentication.\n\n"+
				"Unseal Key: %s\nRoot Token: %s\n",
			init.RootToken,
			hex.EncodeToString(init.SecretShares[0]),
			init.RootToken,
		))
	}

	// Compile server information for output later
	infoKeys := make([]string, 0, 10)
	info := make(map[string]string)
	info["backend"] = config.Backend.Type
	info["log level"] = logLevel
	info["mlock"] = fmt.Sprintf(
		"supported: %v, enabled: %v",
		mlock.Supported(), !config.DisableMlock)
	infoKeys = append(infoKeys, "log level", "mlock", "backend")

	// If the backend supports HA, then note it
	if _, ok := backend.(physical.HABackend); ok {
		info["backend"] += " (HA available)"
		info["advertise address"] = config.Backend.AdvertiseAddr
		infoKeys = append(infoKeys, "advertise address")
	}

	// Initialize the telemetry
	if err := c.setupTelementry(config); err != nil {
		c.Ui.Error(fmt.Sprintf("Error initializing telemetry: %s", err))
		return 1
	}

	// Initialize the listeners
	lns := make([]net.Listener, 0, len(config.Listeners))
	for i, lnConfig := range config.Listeners {
		ln, props, err := server.NewListener(lnConfig.Type, lnConfig.Config)
		if err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Error initializing listener of type %s: %s",
				lnConfig.Type, err))
			return 1
		}

		// Store the listener props for output later
		key := fmt.Sprintf("listener %d", i+1)
		propsList := make([]string, 0, len(props))
		for k, v := range props {
			propsList = append(propsList, fmt.Sprintf(
				"%s: %q", k, v))
		}
		sort.Strings(propsList)
		infoKeys = append(infoKeys, key)
		info[key] = fmt.Sprintf(
			"%s (%s)", lnConfig.Type, strings.Join(propsList, ", "))

		lns = append(lns, ln)
	}

	// Initialize the HTTP server
	server := &http.Server{}
	server.Handler = vaulthttp.Handler(core)
	for _, ln := range lns {
		go server.Serve(ln)
	}

	// Server configuration output
	padding := 18
	c.Ui.Output("==> Vault server configuration:\n")
	for _, k := range infoKeys {
		c.Ui.Output(fmt.Sprintf(
			"%s%s: %s",
			strings.Repeat(" ", padding-len(k)),
			strings.Title(k),
			info[k]))
	}
	c.Ui.Output("")

	// Output the header that the server has started
	c.Ui.Output("==> Vault server started! Log data will stream in below:\n")

	// Release the log gate.
	logGate.Flush()

	<-make(chan struct{})
	return 0
}

func (c *ServerCommand) enableDev(core *vault.Core) (*vault.InitResult, error) {
	// Initialize it with a basic single key
	init, err := core.Initialize(&vault.SealConfig{
		SecretShares:    1,
		SecretThreshold: 1,
	})
	if err != nil {
		return nil, err
	}

	// Copy the key so that it can be zeroed
	key := make([]byte, len(init.SecretShares[0]))
	copy(key, init.SecretShares[0])

	// Unseal the core
	unsealed, err := core.Unseal(key)
	if err != nil {
		return nil, err
	}
	if !unsealed {
		return nil, fmt.Errorf("failed to unseal Vault for dev mode")
	}

	// Set the token
	tokenHelper, err := c.TokenHelper()
	if err != nil {
		return nil, err
	}
	if err := tokenHelper.Store(init.RootToken); err != nil {
		return nil, err
	}

	return init, nil
}

// detectAdvertise is used to attempt advertise address detection
func (c *ServerCommand) detectAdvertise(detect physical.AdvertiseDetect,
	config *server.Config) (string, error) {
	// Get the hostname
	host, err := detect.DetectHostAddr()
	if err != nil {
		return "", err
	}

	// Default the port and scheme
	scheme := "https"
	port := 8200

	// Attempt to detect overrides
	for _, list := range config.Listeners {
		// Only attempt TCP
		if list.Type != "tcp" {
			continue
		}

		// Check if TLS is disabled
		if val, ok := list.Config["tls_disable"]; ok {
			disable, err := strconv.ParseBool(val)
			if err != nil {
				return "", fmt.Errorf("tls_disable: %s", err)
			}

			if disable {
				scheme = "http"
			}
		}

		// Check for address override
		addr, ok := list.Config["address"]
		if !ok {
			addr = "127.0.0.1:8200"
		}

		// Check for localhost
		hostStr, portStr, err := net.SplitHostPort(addr)
		if err != nil {
			continue
		}
		if hostStr == "127.0.0.1" {
			host = hostStr
		}

		// Check for custom port
		listPort, err := strconv.Atoi(portStr)
		if err != nil {
			continue
		}
		port = listPort
	}

	// Build a URL
	url := &url.URL{
		Scheme: scheme,
		Host:   fmt.Sprintf("%s:%d", host, port),
	}

	// Return the URL string
	return url.String(), nil
}

// setupTelementry is used ot setup the telemetry sub-systems
func (c *ServerCommand) setupTelementry(config *server.Config) error {
	/* Setup telemetry
	Aggregate on 10 second intervals for 1 minute. Expose the
	metrics over stderr when there is a SIGUSR1 received.
	*/
	inm := metrics.NewInmemSink(10*time.Second, time.Minute)
	metrics.DefaultInmemSignal(inm)
	metricsConf := metrics.DefaultConfig("vault")

	// Configure the statsite sink
	var fanout metrics.FanoutSink
	if config.StatsiteAddr != "" {
		sink, err := metrics.NewStatsiteSink(config.StatsiteAddr)
		if err != nil {
			return err
		}
		fanout = append(fanout, sink)
	}

	// Configure the statsd sink
	if config.StatsdAddr != "" {
		sink, err := metrics.NewStatsdSink(config.StatsdAddr)
		if err != nil {
			return err
		}
		fanout = append(fanout, sink)
	}

	// Initialize the global sink
	if len(fanout) > 0 {
		fanout = append(fanout, inm)
		metrics.NewGlobal(metricsConf, fanout)
	} else {
		metricsConf.EnableHostname = false
		metrics.NewGlobal(metricsConf, inm)
	}
	return nil
}

func (c *ServerCommand) Synopsis() string {
	return "Start a Vault server"
}

func (c *ServerCommand) Help() string {
	helpText := `
Usage: vault server [options]

  Start a Vault server.

  This command starts a Vault server that responds to API requests.
  Vault will start in a "sealed" state. The Vault must be unsealed
  with "vault unseal" or the API before this server can respond to requests.
  This must be done for every server.

  If the server is being started against a storage backend that has
  brand new (no existing Vault data in it), it must be initialized with
  "vault init" or the API first.

General Options:

  -config=<path>      Path to the configuration file or directory. This can be
                      specified multiple times. If it is a directory, all
                      files with a ".hcl" or ".json" suffix will be loaded.

  -log-level=info     Log verbosity. Defaults to "info", will be outputted
                      to stderr.

`
	return strings.TrimSpace(helpText)
}
<|endoftext|>


<commit_before>package statemachine

import (
	"log"
	"os"
)

type Handler func() string

type Machine struct {
	Handlers map[string]Handler
	Logger   *log.Logger
}

type StateMachineError struct {
	State string
}

func (sme StateMachineError) Error() string {
	return "statemachine: No handler function registered for state: " + sme.State
}

func NewMachine() Machine {
	return Machine{
		Handlers: map[string]Handler{},
		Logger:   log.New(os.Stdout, "statemachine: ", 0),
	}
}

func (machine Machine) AddState(stateName string, handlerFn Handler) {
	machine.Handlers[stateName] = handlerFn
}

func (machine Machine) Run() (success bool, error error) {
	state := "INIT"
	machine.Logger.Println("Starting in state: INIT")
	for {
		if handler, present := machine.Handlers[state]; present {
			oldstate := state
			state = handler()
			machine.Logger.Printf("State transition: %s -> %s\n", oldstate, state)
			if state == "END" {
				machine.Logger.Println("Terminating")
				return true, nil
			}
		} else {
			return false, StateMachineError{state}
		}
	}
}
<commit_msg>Add levels to log output<commit_after>package statemachine

import (
	"log"
	"os"
)

type Handler func() string

type Machine struct {
	Handlers map[string]Handler
	Logger   *log.Logger
}

type StateMachineError struct {
	State string
}

func (sme StateMachineError) Error() string {
	return "ERROR: No handler function registered for state: " + sme.State
}

func NewMachine() Machine {
	return Machine{
		Handlers: map[string]Handler{},
		Logger:   log.New(os.Stdout, "statemachine: ", 0),
	}
}

func (machine Machine) AddState(stateName string, handlerFn Handler) {
	machine.Handlers[stateName] = handlerFn
}

func (machine Machine) Run() (success bool, error error) {
	state := "INIT"
	machine.Logger.Println("INFO: Starting in state: INIT")
	for {
		if handler, present := machine.Handlers[state]; present {
			oldstate := state
			state = handler()
			machine.Logger.Printf("INFO: State transition: %s -> %s\n", oldstate, state)
			if state == "END" {
				machine.Logger.Println("INFO: Terminating")
				return true, nil
			}
		} else {
			err := StateMachineError{state}
			machine.Logger.Print(err)
			return false, err
		}
	}
}
<|endoftext|>


<commit_before>/*

	golden is a package designed to make it possible to compare a game to a
	golden run for testing purposes. It takes a record saved in
	storage/filesystem format and compares it.

*/
package golden

import (
	"errors"
	"github.com/jkomoros/boardgame"
	"github.com/jkomoros/boardgame/storage/filesystem/record"
	"github.com/jkomoros/boardgame/storage/memory"
	"github.com/yudai/gojsondiff"
	"github.com/yudai/gojsondiff/formatter"
	"io/ioutil"
	"path/filepath"
	"reflect"
	"strconv"
)

//Compare is the primary method in the package. It takes a game delegate and a
//filename denoting a record to compare against. delegate shiould be a fresh
//delegate not yet affiliated with a manager.
func Compare(delegate boardgame.GameDelegate, recFilename string) error {

	manager, err := boardgame.NewGameManager(delegate, memory.NewStorageManager())

	if err != nil {
		return errors.New("Couldn't create new manager: " + err.Error())
	}

	rec, err := record.New(recFilename)

	if err != nil {
		return errors.New("Couldn't create record: " + err.Error())
	}

	return compare(manager, rec)

}

//CompareFolder is like Compare, except it will iterate through any file in
//recFolder that ends in .json. Errors if any of those files cannot be parsed
//into recs, or if no files match.
func CompareFolder(delegate boardgame.GameDelegate, recFolder string) error {
	manager, err := boardgame.NewGameManager(delegate, memory.NewStorageManager())

	if err != nil {
		return errors.New("Couldn't create new manager: " + err.Error())
	}

	infos, err := ioutil.ReadDir(recFolder)

	if err != nil {
		return errors.New("Couldn't read folder: " + err.Error())
	}

	processedRecs := 0

	for _, info := range infos {
		if info.IsDir() {
			continue
		}

		if filepath.Ext(info.Name()) != ".json" {
			continue
		}

		rec, err := record.New(filepath.Join(recFolder, info.Name()))

		if err != nil {
			return errors.New("File with name " + info.Name() + " couldn't be loaded into rec: " + err.Error())
		}

		if err := compare(manager, rec); err != nil {
			return errors.New("File named " + info.Name() + " had compare error: " + err.Error())
		}

		processedRecs++
	}

	if processedRecs < 1 {
		return errors.New("Processed 0 recs in folder")
	}

	return nil
}

func compare(manager *boardgame.GameManager, rec *record.Record) error {
	game, err := manager.RecreateGame(rec.Game())

	if err != nil {
		return errors.New("Couldn't create game: " + err.Error())
	}

	lastVerifiedVersion := 0

	for !game.Finished() {
		//Verify all new moves that have happened since the last time we
		//checked (often, fix-up moves).
		for lastVerifiedVersion < game.Version() {
			stateToCompare, err := rec.State(lastVerifiedVersion)

			if err != nil {
				return errors.New("Couldn't get " + strconv.Itoa(lastVerifiedVersion) + " state: " + err.Error())
			}

			if err := compareJsonBlobs(game.State(lastVerifiedVersion).StorageRecord(), stateToCompare); err != nil {
				return errors.New("State " + strconv.Itoa(lastVerifiedVersion) + " compared differently: " + err.Error())
			}

			if lastVerifiedVersion > 0 {

				//Version 0 has no associated move

				recMove, err := rec.Move(lastVerifiedVersion)

				if err != nil {
					return errors.New("Couldn't get move " + strconv.Itoa(lastVerifiedVersion) + " from record")
				}

				moves := game.MoveRecords(lastVerifiedVersion)

				if len(moves) < 1 {
					return errors.New("Didn't fetch historical move records for " + strconv.Itoa(lastVerifiedVersion))
				}

				//Warning: records are modified by this method
				if err := compareMoveStorageRecords(moves[len(moves)-1], recMove); err != nil {
					return errors.New("Move " + strconv.Itoa(lastVerifiedVersion) + " compared differently: " + err.Error())
				}
			}

			lastVerifiedVersion++
		}

		nextMoveRec, err := rec.Move(lastVerifiedVersion + 1)

		if err != nil {
			//We'll assume that menas that's all of the moves there are to make.
			break
		}

		if nextMoveRec.Proposer < 0 {
			return errors.New("At version " + strconv.Itoa(lastVerifiedVersion) + " the next player move to apply was not applied by a player")
		}

		nextMove, err := nextMoveRec.Inflate(game)

		if err != nil {
			return errors.New("Couldn't inflate move: " + err.Error())
		}

		if err := <-game.ProposeMove(nextMove, nextMoveRec.Proposer); err != nil {
			return errors.New("Couldn't propose next move in chain: " + err.Error())
		}

	}

	if game.Finished() != rec.Game().Finished {
		return errors.New("Game finished did not match rec")
	}

	if !reflect.DeepEqual(game.Winners(), rec.Game().Winners) {
		return errors.New("Game winners did not match")
	}

	return nil
}

var differ = gojsondiff.New()

var diffformatter = formatter.NewDeltaFormatter()

func compareJsonBlobs(one, two []byte) error {

	diff, err := differ.Compare(one, two)

	if err != nil {
		return errors.New("Couldn't diff: " + err.Error())
	}

	if diff.Modified() {

		str, err := diffformatter.Format(diff)

		if err != nil {
			return errors.New("Couldn't format diff: " + err.Error())
		}

		return errors.New("Diff: " + str)
	}

	return nil

}

//warning: modifies the records
func compareMoveStorageRecords(one, two *boardgame.MoveStorageRecord) error {

	if one == nil {
		return errors.New("One was nil")
	}

	if two == nil {
		return errors.New("Two was nil")
	}

	oneBlob := one.Blob
	twoBlob := two.Blob

	//Set the fields we know might differ to known values
	one.Blob = nil
	two.Blob = nil

	two.Timestamp = one.Timestamp

	if !reflect.DeepEqual(one, two) {
		return errors.New("Move storage records differed in base fields")
	}

	return compareJsonBlobs(oneBlob, twoBlob)

}
<commit_msg>Better documentation of what golden.Compare does. Part of #648.<commit_after>/*

	golden is a package designed to make it possible to compare a game to a
	golden run for testing purposes. It takes a record saved in
	storage/filesystem format and compares it.

*/
package golden

import (
	"errors"
	"github.com/jkomoros/boardgame"
	"github.com/jkomoros/boardgame/storage/filesystem/record"
	"github.com/jkomoros/boardgame/storage/memory"
	"github.com/yudai/gojsondiff"
	"github.com/yudai/gojsondiff/formatter"
	"io/ioutil"
	"path/filepath"
	"reflect"
	"strconv"
)

//Compare is the primary method in the package. It takes a game delegate and a
//filename denoting a record to compare against. delegate shiould be a fresh
//delegate not yet affiliated with a manager. It compares every version and
//move in the history (ignoring things that shouldn't be the same, like
//timestamps) and reports the first place they divrge. Any time it finds a
//move not proposed by AdminPlayerIndex it will propose that move. As long as
//your game uses state.Rand() for all randomness and is otherwise
//deterministic then everything should work.
func Compare(delegate boardgame.GameDelegate, recFilename string) error {

	manager, err := boardgame.NewGameManager(delegate, memory.NewStorageManager())

	if err != nil {
		return errors.New("Couldn't create new manager: " + err.Error())
	}

	rec, err := record.New(recFilename)

	if err != nil {
		return errors.New("Couldn't create record: " + err.Error())
	}

	return compare(manager, rec)

}

//CompareFolder is like Compare, except it will iterate through any file in
//recFolder that ends in .json. Errors if any of those files cannot be parsed
//into recs, or if no files match.
func CompareFolder(delegate boardgame.GameDelegate, recFolder string) error {
	manager, err := boardgame.NewGameManager(delegate, memory.NewStorageManager())

	if err != nil {
		return errors.New("Couldn't create new manager: " + err.Error())
	}

	infos, err := ioutil.ReadDir(recFolder)

	if err != nil {
		return errors.New("Couldn't read folder: " + err.Error())
	}

	processedRecs := 0

	for _, info := range infos {
		if info.IsDir() {
			continue
		}

		if filepath.Ext(info.Name()) != ".json" {
			continue
		}

		rec, err := record.New(filepath.Join(recFolder, info.Name()))

		if err != nil {
			return errors.New("File with name " + info.Name() + " couldn't be loaded into rec: " + err.Error())
		}

		if err := compare(manager, rec); err != nil {
			return errors.New("File named " + info.Name() + " had compare error: " + err.Error())
		}

		processedRecs++
	}

	if processedRecs < 1 {
		return errors.New("Processed 0 recs in folder")
	}

	return nil
}

func compare(manager *boardgame.GameManager, rec *record.Record) error {
	game, err := manager.RecreateGame(rec.Game())

	if err != nil {
		return errors.New("Couldn't create game: " + err.Error())
	}

	lastVerifiedVersion := 0

	for !game.Finished() {
		//Verify all new moves that have happened since the last time we
		//checked (often, fix-up moves).
		for lastVerifiedVersion < game.Version() {
			stateToCompare, err := rec.State(lastVerifiedVersion)

			if err != nil {
				return errors.New("Couldn't get " + strconv.Itoa(lastVerifiedVersion) + " state: " + err.Error())
			}

			if err := compareJsonBlobs(game.State(lastVerifiedVersion).StorageRecord(), stateToCompare); err != nil {
				return errors.New("State " + strconv.Itoa(lastVerifiedVersion) + " compared differently: " + err.Error())
			}

			if lastVerifiedVersion > 0 {

				//Version 0 has no associated move

				recMove, err := rec.Move(lastVerifiedVersion)

				if err != nil {
					return errors.New("Couldn't get move " + strconv.Itoa(lastVerifiedVersion) + " from record")
				}

				moves := game.MoveRecords(lastVerifiedVersion)

				if len(moves) < 1 {
					return errors.New("Didn't fetch historical move records for " + strconv.Itoa(lastVerifiedVersion))
				}

				//Warning: records are modified by this method
				if err := compareMoveStorageRecords(moves[len(moves)-1], recMove); err != nil {
					return errors.New("Move " + strconv.Itoa(lastVerifiedVersion) + " compared differently: " + err.Error())
				}
			}

			lastVerifiedVersion++
		}

		nextMoveRec, err := rec.Move(lastVerifiedVersion + 1)

		if err != nil {
			//We'll assume that menas that's all of the moves there are to make.
			break
		}

		if nextMoveRec.Proposer < 0 {
			return errors.New("At version " + strconv.Itoa(lastVerifiedVersion) + " the next player move to apply was not applied by a player")
		}

		nextMove, err := nextMoveRec.Inflate(game)

		if err != nil {
			return errors.New("Couldn't inflate move: " + err.Error())
		}

		if err := <-game.ProposeMove(nextMove, nextMoveRec.Proposer); err != nil {
			return errors.New("Couldn't propose next move in chain: " + err.Error())
		}

	}

	if game.Finished() != rec.Game().Finished {
		return errors.New("Game finished did not match rec")
	}

	if !reflect.DeepEqual(game.Winners(), rec.Game().Winners) {
		return errors.New("Game winners did not match")
	}

	return nil
}

var differ = gojsondiff.New()

var diffformatter = formatter.NewDeltaFormatter()

func compareJsonBlobs(one, two []byte) error {

	diff, err := differ.Compare(one, two)

	if err != nil {
		return errors.New("Couldn't diff: " + err.Error())
	}

	if diff.Modified() {

		str, err := diffformatter.Format(diff)

		if err != nil {
			return errors.New("Couldn't format diff: " + err.Error())
		}

		return errors.New("Diff: " + str)
	}

	return nil

}

//warning: modifies the records
func compareMoveStorageRecords(one, two *boardgame.MoveStorageRecord) error {

	if one == nil {
		return errors.New("One was nil")
	}

	if two == nil {
		return errors.New("Two was nil")
	}

	oneBlob := one.Blob
	twoBlob := two.Blob

	//Set the fields we know might differ to known values
	one.Blob = nil
	two.Blob = nil

	two.Timestamp = one.Timestamp

	if !reflect.DeepEqual(one, two) {
		return errors.New("Move storage records differed in base fields")
	}

	return compareJsonBlobs(oneBlob, twoBlob)

}
<|endoftext|>


<commit_before>package commands

import (
	"bytes"
	"fmt"
	"io"
	"time"

	cmds "github.com/jbenet/go-ipfs/commands"
	core "github.com/jbenet/go-ipfs/core"
	peer "github.com/jbenet/go-ipfs/p2p/peer"
	u "github.com/jbenet/go-ipfs/util"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
)

const kPingTimeout = 10 * time.Second

type PingResult struct {
	Success bool
	Time    time.Duration
	Text    string
}

var PingCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "send echo request packets to IPFS hosts",
		Synopsis: `
Send pings to a peer using the routing system to discover its address
		`,
		ShortDescription: `
		ipfs ping is a tool to find a node (in the routing system),
		send pings, wait for pongs, and print out round-trip latency information.
		`,
	},
	Arguments: []cmds.Argument{
		cmds.StringArg("peer ID", true, true, "ID of peer to be pinged"),
	},
	Options: []cmds.Option{
		cmds.IntOption("count", "n", "number of ping messages to send"),
	},
	Marshalers: cmds.MarshalerMap{
		cmds.Text: func(res cmds.Response) (io.Reader, error) {
			outChan, ok := res.Output().(chan interface{})
			if !ok {
				return nil, u.ErrCast()
			}

			marshal := func(v interface{}) (io.Reader, error) {
				obj, ok := v.(*PingResult)
				if !ok {
					return nil, u.ErrCast()
				}

				buf := new(bytes.Buffer)
				if len(obj.Text) > 0 {
					buf = bytes.NewBufferString(obj.Text + "\n")
				} else if obj.Success {
					fmt.Fprintf(buf, "Pong took %.2fms\n", obj.Time.Seconds()*1000)
				} else {
					fmt.Fprintf(buf, "Pong failed\n")
				}
				return buf, nil
			}

			return &cmds.ChannelMarshaler{
				Channel:   outChan,
				Marshaler: marshal,
			}, nil
		},
	},
	Run: func(req cmds.Request) (interface{}, error) {
		n, err := req.Context().GetNode()
		if err != nil {
			return nil, err
		}

		// Must be online!
		if !n.OnlineMode() {
			return nil, errNotOnline
		}

		peerID, err := peer.IDB58Decode(req.Arguments()[0])
		if err != nil {
			return nil, err
		}

		// Set up number of pings
		numPings := 10
		val, found, err := req.Option("count").Int()
		if err != nil {
			return nil, err
		}
		if found {
			numPings = val
		}

		outChan := make(chan interface{})

		go pingPeer(n, peerID, numPings, outChan)

		return outChan, nil
	},
	Type: PingResult{},
}

func pingPeer(n *core.IpfsNode, pid peer.ID, numPings int, outChan chan interface{}) {
	defer close(outChan)

	// Make sure we can find the node in question
	outChan <- &PingResult{
		Text: fmt.Sprintf("Looking up peer %s", pid.Pretty()),
	}

	// TODO: get master context passed in
	ctx, _ := context.WithTimeout(context.TODO(), kPingTimeout)
	p, err := n.Routing.FindPeer(ctx, pid)
	if err != nil {
		outChan <- &PingResult{Text: fmt.Sprintf("Peer lookup error: %s", err)}
		return
	}
	n.Peerstore.AddPeerInfo(p)

	outChan <- &PingResult{Text: fmt.Sprintf("Peer found, starting pings.")}

	var total time.Duration
	for i := 0; i < numPings; i++ {
		ctx, _ = context.WithTimeout(context.TODO(), kPingTimeout)
		took, err := n.Routing.Ping(ctx, p.ID)
		if err != nil {
			log.Errorf("Ping error: %s", err)
			outChan <- &PingResult{Text: fmt.Sprintf("Ping error: %s", err)}
			break
		}
		outChan <- &PingResult{
			Success: true,
			Time:    took,
		}
		total += took
		time.Sleep(time.Second)
	}
	averagems := total.Seconds() * 1000 / float64(numPings)
	outChan <- &PingResult{
		Text: fmt.Sprintf("Average latency: %.2fms", averagems),
	}
}
<commit_msg>improve UI of ping<commit_after>package commands

import (
	"bytes"
	"fmt"
	"io"
	"time"

	cmds "github.com/jbenet/go-ipfs/commands"
	config "github.com/jbenet/go-ipfs/config"
	core "github.com/jbenet/go-ipfs/core"
	peer "github.com/jbenet/go-ipfs/p2p/peer"
	u "github.com/jbenet/go-ipfs/util"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
)

const kPingTimeout = 10 * time.Second

type PingResult struct {
	Success bool
	Time    time.Duration
	Text    string
}

var PingCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "send echo request packets to IPFS hosts",
		Synopsis: `
Send pings to a peer using the routing system to discover its address
		`,
		ShortDescription: `
		ipfs ping is a tool to find a node (in the routing system),
		send pings, wait for pongs, and print out round-trip latency information.
		`,
	},
	Arguments: []cmds.Argument{
		cmds.StringArg("peer ID", true, true, "ID of peer to be pinged"),
	},
	Options: []cmds.Option{
		cmds.IntOption("count", "n", "number of ping messages to send"),
	},
	Marshalers: cmds.MarshalerMap{
		cmds.Text: func(res cmds.Response) (io.Reader, error) {
			outChan, ok := res.Output().(chan interface{})
			if !ok {
				return nil, u.ErrCast()
			}

			marshal := func(v interface{}) (io.Reader, error) {
				obj, ok := v.(*PingResult)
				if !ok {
					return nil, u.ErrCast()
				}

				buf := new(bytes.Buffer)
				if len(obj.Text) > 0 {
					buf = bytes.NewBufferString(obj.Text + "\n")
				} else if obj.Success {
					fmt.Fprintf(buf, "Pong received: time=%.2f ms\n", obj.Time.Seconds()*1000)
				} else {
					fmt.Fprintf(buf, "Pong failed\n")
				}
				return buf, nil
			}

			return &cmds.ChannelMarshaler{
				Channel:   outChan,
				Marshaler: marshal,
			}, nil
		},
	},
	Run: func(req cmds.Request) (interface{}, error) {
		n, err := req.Context().GetNode()
		if err != nil {
			return nil, err
		}

		// Must be online!
		if !n.OnlineMode() {
			return nil, errNotOnline
		}

		bsp, err := config.ParseBootstrapPeer(req.Arguments()[0])
		if err != nil {
			return nil, err
		}

		peerID, err := peer.IDB58Decode(bsp.PeerID)
		if err != nil {
			return nil, err
		}

		if len(bsp.Address) > 0 {
			addr, err := ma.NewMultiaddr(bsp.Address)
			if err != nil {
				return nil, err
			}
			n.Peerstore.AddAddress(peerID, addr)
		}

		// Set up number of pings
		numPings := 10
		val, found, err := req.Option("count").Int()
		if err != nil {
			return nil, err
		}
		if found {
			numPings = val
		}

		outChan := make(chan interface{})

		go pingPeer(n, peerID, numPings, outChan)

		return outChan, nil
	},
	Type: PingResult{},
}

func pingPeer(n *core.IpfsNode, pid peer.ID, numPings int, outChan chan interface{}) {
	defer close(outChan)

	if len(n.Peerstore.Addresses(pid)) == 0 {
		// Make sure we can find the node in question
		outChan <- &PingResult{
			Text: fmt.Sprintf("Looking up peer %s", pid.Pretty()),
		}

		// TODO: get master context passed in
		ctx, _ := context.WithTimeout(context.TODO(), kPingTimeout)
		p, err := n.Routing.FindPeer(ctx, pid)
		if err != nil {
			outChan <- &PingResult{Text: fmt.Sprintf("Peer lookup error: %s", err)}
			return
		}
		n.Peerstore.AddPeerInfo(p)
	}

	outChan <- &PingResult{Text: fmt.Sprintf("PING %s.", pid.Pretty())}

	var total time.Duration
	for i := 0; i < numPings; i++ {
		ctx, _ := context.WithTimeout(context.TODO(), kPingTimeout)
		took, err := n.Routing.Ping(ctx, pid)
		if err != nil {
			log.Errorf("Ping error: %s", err)
			outChan <- &PingResult{Text: fmt.Sprintf("Ping error: %s", err)}
			break
		}
		outChan <- &PingResult{
			Success: true,
			Time:    took,
		}
		total += took
		time.Sleep(time.Second)
	}
	averagems := total.Seconds() * 1000 / float64(numPings)
	outChan <- &PingResult{
		Text: fmt.Sprintf("Average latency: %.2fms", averagems),
	}
}
<|endoftext|>